diff --git a/.gitignore b/.gitignore index 1dbc687d..87caa5f8 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,10 @@ target/ #Ipython Notebook .ipynb_checkpoints + +#PyCharm +/.idea + +# Build temporary files +/contrib.enabled +/cv_version.py diff --git a/.gitmodules b/.gitmodules index 33e5752e..ce3da2e1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,8 @@ url = https://github.com/Itseez/opencv.git [submodule "multibuild"] path = multibuild - url = https://github.com/skvark/multibuild.git + url = https://github.com/matthew-brett/multibuild.git + branch = devel [submodule "opencv_contrib"] path = opencv_contrib url = https://github.com/opencv/opencv_contrib.git diff --git a/.travis.yml b/.travis.yml index 26493e18..9f7750e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,54 +1,50 @@ env: global: - - REPO_DIR=opencv - # Commit from opencv that you want to build - - BUILD_COMMIT=6d4f66472e14b29b8e1623859cfebfdc67f677c3 - # pip dependencies to _build_ your project - - BUILD_DEPENDS="numpy==1.11.1" - # pip dependencies to _test_ your project. Include any dependencies - # that you need, that are also specified in BUILD_DEPENDS, this will be - # a separate install. + - "PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'" + # pip dependencies to _test_ your project - TEST_DEPENDS="numpy==1.11.1" + - PLAT=x86_64 - UNICODE_WIDTH=32 - secure: "mU040XIYWtDjRms27deQy5fNg9HBFF9fiLfSteBaMjopZKXFUBsdMTKYGEVvX8DA879guMdjG8Prw1aCFhTTYlWgJ0Afm4YucRC0vAD4HLNhqLJ2lIpRceR3+2qPX+Oz5ATVVRi3ghBeJ20LLtNgOgf6esQVjdrYNC+YqmguClHKEYAxS7ngW42iQP8HX2anRcz9q9H7exZ9fX/D1PJfMNka/mNaB5KXZu5zdLuk/E0VbWU2tMWVIDUvx4uBlpE1d8HixEV5LHnuVE/QI36BcyucYxstTNKW6pGYgrhkYf+0PX4BphZXwY7EUBwzXsYLmyge6yH8W6NfvTW0ZasFF6xzQc9bsj+gAZN7H+hN2a42VQqIpkoJw9sU0hqzCOQf6ZvWUQgwFdAHJRHqe/zk4456WxnF0kAgbZdKaGOl0/n0WvgHNqD5bgO8Zzb1XyJTKoR+eAtYKXuz3KgpxKvZMMQVr8wMlI1cFEuGjIm+7ZrYB5jPvQrVzV/DgOq4gkPHOjjhu478UFlhGA9/XWwcyidC3b7zuBN2E7xVuTMlKdk7URB3AHXfG5bZgUG80vllQDGXQDpHVnv4Qi8bGCzI4iKTpp4fCibbqxFLxW1jhjmgePseGcie7Avpe+zXznkbmM2BqMCu3QRmtmFL3eCifwMf3rCNlAs0Sd3iLmEvyos=" - secure: "omn6B+H6s0g1p9rhLGhFtFN1bSB80HCsNUUD9ROEpUirk7Sj7Wxms4CDi1f7aACANsZPXD7YZ72oNpWDJ6hSfTBf2yN1/d1iPILs7F5jt0yeratkDEOXkys1QpfMNO7r3DZ17X3IwvUGy9Mm+Sv15k+DaBdQ/65qwQ4ORIbHZRv3/lwkQ7Z88utjx6DLa9Jwc8fnEjjzIry51lO3OGJoWrjOZlOi2HV9MZ69PuuBdEEuicwfeLnV64QWRle++B51TQZC/3HF5+BBvYXm0LdvV4nSQVa9nTXaOWYcBROPNZizktJI91G6vG6gghWmI1cDR53n9LgCbA3YkPTJm/5Gjn9D+gfU5F16WQ4PFOHfzPZD8nTVmlUDUiuQ30W9QZ+O2ct7wi/xF4/Ff7V+0RIqGSnjhX6SGWk7UziQyGgCjBvYiRIQzfUyGu+86vrqNVXCyBlKOz6rWStTyq/Z0KEIXZFqop+ddeYdsEem5ZxCQ51uTpRMynVgEdKj++1Hn5411Rhntw0Am7RWdDEbFJ65OUyIpNtvlcHVM7ur03oz0hGcZIIkxWHJrCdr80Nw9r/s6KXYvidCNsu4SPx0XYo8KiTA6E2lkIAa5Ct6dZR6m5gjG2vmvlKzRmoD/7byJZN66usNxBh2LuKlgNFuHfG6iR+I6f3XCNmSUOJfm7KZYVI=" -language: python -# The travis Python version is unrelated to the version we build and test -# with. This is set with the MB_PYTHON_VERSION variable. -python: 3.5 + +# Host Python is never used +language: generic +# Required to invoke docker ourselves as per https://docs.travis-ci.com/user/docker/ sudo: required -dist: trusty services: docker +# https://docs.travis-ci.com/user/reference/trusty/ +dist: trusty + +# Save some time, we and setup check them out on demand instead +# https://docs.travis-ci.com/user/customizing-the-build/#Git-Clone-Depth +git: + submodules: false + matrix: - exclude: - # Exclude the default Python 3.5 build - - python: 3.5 + fast_finish: true include: # default builds for MacOS - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=2.7 - ENABLE_CONTRIB=0 - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=3.4 - ENABLE_CONTRIB=0 - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=3.5 - ENABLE_CONTRIB=0 - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=3.6 @@ -56,25 +52,21 @@ matrix: # Contrib builds for MacOS - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=2.7 - ENABLE_CONTRIB=1 - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=3.4 - ENABLE_CONTRIB=1 - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=3.5 - ENABLE_CONTRIB=1 - os: osx - language: generic osx_image: xcode8.3 env: - MB_PYTHON_VERSION=3.6 @@ -123,14 +115,14 @@ matrix: env: - MB_PYTHON_VERSION=3.6 - ENABLE_CONTRIB=0 - - BUILD_DEPENDS=numpy==1.11.3 + - TEST_DEPENDS=numpy==1.11.3 - os: linux env: - MB_PYTHON_VERSION=3.6 - PLAT=i686 - ENABLE_CONTRIB=0 - - BUILD_DEPENDS=numpy==1.11.3 + - TEST_DEPENDS=numpy==1.11.3 # contrib builds for Linux @@ -184,7 +176,7 @@ matrix: env: - MB_PYTHON_VERSION=3.6 - - BUILD_DEPENDS=numpy==1.11.3 + - TEST_DEPENDS=numpy==1.11.3 - ENABLE_CONTRIB=1 @@ -193,29 +185,54 @@ matrix: - MB_PYTHON_VERSION=3.6 - PLAT=i686 - - BUILD_DEPENDS=numpy==1.11.3 + - TEST_DEPENDS=numpy==1.11.3 - ENABLE_CONTRIB=1 -before_install: - - echo $ENABLE_CONTRIB > contrib.enabled - - source multibuild/common_utils.sh - - source multibuild/travis_steps.sh - - python find_version.py - - cp LICENSE*.txt cv2/ - - cp opencv/data/haarcascades/*.xml cv2/data/ - - before_install - -install: - # Maybe get and clean and patch source - - clean_code $REPO_DIR $BUILD_COMMIT - - travis_wait 120 build_wheel $REPO_DIR $PLAT - -script: - - install_run $PLAT - -after_success: - # Upload wheels to pypi - - pip install twine - - if [ -n "$TRAVIS_TAG" ]; then twine upload -u ${USER} -p ${PASS} --skip-existing ${TRAVIS_BUILD_DIR}/wheelhouse/opencv*; else echo "Tag not set, deployment skipped."; fi - - source travis/deploy.sh +# The first line is printed in the folding header in Travis output +before_install: | + # Check out and prepare the source + set -e + #Multibuild doesn't have releases, so --depth would break eventually (see + #https://superuser.com/questions/1240216/server-does-not-allow-request-for-unadvertised) + git submodule update --init multibuild + source multibuild/common_utils.sh + # https://github.com/matthew-brett/multibuild/issues/116 + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export ARCH_FLAGS=" "; fi + source multibuild/travis_steps.sh + # This sets -x + source multibuild_customize.sh + echo $ENABLE_CONTRIB > contrib.enabled + before_install + # Not interested in travis internal scripts' output + set +x + +install: | + # Build and package + set -x + build_wheel $REPO_DIR $PLAT + set +x + +script: | + # Install and run tests + set -x + install_run $PLAT + set +x + +after_success: | + # Upload wheels to pypi if requested + if [ -n "$TRAVIS_TAG" ]; then + set -x + pip install twine + + if [[ $ENABLE_CONTRIB == 0 ]]; then + echo "This is default build. Deployment will be done to to PyPI entry opencv-python." + else + echo "This is contrib build. Deployment will be done to to PyPI entry opencv-contrib-python." + fi + + twine upload -u ${USER} -p ${PASS} --skip-existing ${TRAVIS_BUILD_DIR}/wheelhouse/opencv* + set +x + else + echo "Tag not set, deployment skipped." + fi diff --git a/appveyor.yml b/appveyor.yml index 090c7d8d..80bd5e97 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,145 +7,73 @@ environment: matrix: - PYTHON: "C:/Python27" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "2.7" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python27-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "2.7" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python34" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "3.4" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python34-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "3.4" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python35" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "3.5" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python35-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "3.5" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python36" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "3.6" - NP_VERSION: "1.11.3" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python36-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "3.6" - NP_VERSION: "1.11.3" ENABLE_CONTRIB: 0 - PYTHON: "C:/Python27" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "2.7" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python27-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "2.7" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python34" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "3.4" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python34-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "3.4" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python35" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "3.5" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python35-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "3.5" - NP_VERSION: "1.11.1" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python36" - BUILD_ENV: "Visual Studio 14" - BUILD_DIR: "build" - PYTHON_VERSION: "3.6" - NP_VERSION: "1.11.3" ENABLE_CONTRIB: 1 - PYTHON: "C:/Python36-x64" - BUILD_ENV: "Visual Studio 14 Win64" - BUILD_DIR: "build64" - PYTHON_VERSION: "3.6" - NP_VERSION: "1.11.3" ENABLE_CONTRIB: 1 -install: -- cmd: >- - - git submodule update --init --recursive - - C:\Python35\python.exe find_version.py - - "%PYTHON%/python.exe" -m pip install --upgrade pip - - "%PYTHON%/python.exe" -m pip install -r requirements.txt - - "%PYTHON%/python.exe" -m pip install "numpy==%NP_VERSION%" +matrix: + fast_finish: true + build_script: -- appveyor\build.cmd +- cmd: | -before_test: -- cmd: >- + "%PYTHON%/python.exe" setup.py bdist_wheel - cd .. +before_test: +- ps: | - if %ENABLE_CONTRIB% EQU 0 ("%PYTHON%/python.exe" -m pip install --no-index --find-links=%APPVEYOR_BUILD_FOLDER%\dist\ opencv-python) else ("%PYTHON%/python.exe" -m pip install --no-index --find-links=%APPVEYOR_BUILD_FOLDER%\dist\ opencv-contrib-python) + cd ${Env:APPVEYOR_BUILD_FOLDER}\tests + &"${Env:PYTHON}/python.exe" -m pip install --user (ls "../dist/opencv_*.whl") + if ($LastExitCode -ne 0) {throw $LastExitCode} test_script: -- cmd: >- +- cmd: | cd %APPVEYOR_BUILD_FOLDER%\tests - "%PYTHON%/python.exe" -m unittest test artifacts: @@ -153,8 +81,16 @@ artifacts: name: wheels deploy_script: -- cd %APPVEYOR_BUILD_FOLDER% - -- if %ENABLE_CONTRIB% EQU 0 (echo "This is default build. Deplyoment will be done to to PyPI entry opencv-python.") else (echo "This is contrib build. Deplyoment will be done to to PyPI entry opencv-contrib-python.") - -- if "%APPVEYOR_REPO_TAG%"=="true" ("%PYTHON%/python.exe" -m twine upload -u %USER% -p %PASS% --skip-existing dist/opencv*) else (echo "Tag not set, deployment skipped.") \ No newline at end of file +- ps: | + + if (${Env:APPVEYOR_REPO_TAG} -eq "true") { + cd ${Env:APPVEYOR_BUILD_FOLDER} + if (${Env:ENABLE_CONTRIB} -eq 0) ` + {echo "This is a default build. Deployment will be done to PyPI entry opencv-python."} ` + else ` + {echo "This is a contrib build. Deployment will be done to PyPI entry opencv-contrib-python."} + + &"${Env:PYTHON}/python.exe" -m pip install twine + &"${Env:PYTHON}/python.exe" -m twine upload -u ${Env:USER} -p ${Env:PASS} --skip-existing dist/opencv* } ` + else + {echo "Tag not set, deployment skipped."} diff --git a/appveyor/build.cmd b/appveyor/build.cmd deleted file mode 100644 index a5c802a9..00000000 --- a/appveyor/build.cmd +++ /dev/null @@ -1,33 +0,0 @@ -if not exist "%APPVEYOR_BUILD_FOLDER%\opencv\%BUILD_DIR%" mkdir "%APPVEYOR_BUILD_FOLDER%\opencv\%BUILD_DIR%" - -cd opencv - -if %ENABLE_CONTRIB% EQU 1 ( - - if %PYTHON_VERSION% GEQ 3 cmake -G "%BUILD_ENV%" -H"." -B"%BUILD_DIR%" -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DPYTHON3_EXECUTABLE="%PYTHON%/python.exe" -DPYTHON3_LIBRARY="%PYTHON%/libs/python3*.lib" -DPYTHON3_INCLUDE_DIR="%PYTHON%/include" -Wno-dev - if %PYTHON_VERSION% LSS 3 cmake -G "%BUILD_ENV%" -H"." -B"%BUILD_DIR%" -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -Wno-dev - -) else ( - - if %PYTHON_VERSION% GEQ 3 cmake -G "%BUILD_ENV%" -H"." -B"%BUILD_DIR%" -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DPYTHON3_EXECUTABLE="%PYTHON%/python.exe" -DPYTHON3_LIBRARY="%PYTHON%/libs/python3*.lib" -DPYTHON3_INCLUDE_DIR="%PYTHON%/include" -Wno-dev - if %PYTHON_VERSION% LSS 3 cmake -G "%BUILD_ENV%" -H"." -B"%BUILD_DIR%" -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -Wno-dev - -) - -cd %BUILD_DIR% - -cmake --build . --config Release - -cd ..\.. -cd - -if %PYTHON_VERSION% GEQ 3 xcopy "%APPVEYOR_BUILD_FOLDER%\opencv\%BUILD_DIR%\lib\python3\Release\*.pyd" .\cv2 /I -if %PYTHON_VERSION% LSS 3 xcopy "%APPVEYOR_BUILD_FOLDER%\opencv\%BUILD_DIR%\lib\RELEASE\*.pyd" .\cv2 /I - -xcopy "%APPVEYOR_BUILD_FOLDER%\opencv\%BUILD_DIR%\bin\Release\*.dll" .\cv2 /I -xcopy "%APPVEYOR_BUILD_FOLDER%\LICENSE*.txt" .\cv2 /I -xcopy "%APPVEYOR_BUILD_FOLDER%\opencv\data\haarcascades\*.xml" .\cv2\data /I - -dir - -"%PYTHON%/python.exe" setup.py bdist_wheel \ No newline at end of file diff --git a/config.sh b/config.sh index 3817bbb7..3eba50b3 100644 --- a/config.sh +++ b/config.sh @@ -1,50 +1,71 @@ #!/bin/bash -set +e +#Customize multibuild logic that is run after entering docker. +#Sourced by docker_build_wrap.sh and docker_test_wrap.sh . +#Runs in Docker, so only the vars passed to `docker run' exist. +#See multibuild/README.rst echo "=== Loading config.sh === " +# To see build progress +function build_wheel { + build_bdist_wheel $@ +} + if [ -n "$IS_OSX" ]; then echo " > OSX environment " - function build_wheel { - # Custom build_wheel function for OSX - # Run using '.' instead of '$REPO_DIR' to build from - # opencv-python instead of opencv - build_pip_wheel . $@ - } else echo " > Linux environment " fi function pre_build { echo "Starting pre-build" + set -e - set +e if [ -n "$IS_OSX" ]; then echo "Running for OSX" - source travis/build-wheels-osx.sh + + # For some reason, gt@4 and ffmpeg can be preinstalled in Travis Mac env + echo 'Installing QT4' + brew tap | grep -qxF cartr/qt4 || brew tap -v cartr/qt4 + brew tap --list-pinned | grep -qxF cartr/qt4 || brew tap-pin -v cartr/qt4 + brew list --versions qt@4 || brew install -v qt@4 + echo '-----------------' + echo 'Installing FFmpeg' + # brew install does produce output regularly on a regular MacOS, + # but Travis doesn't see it for some reason + brew list --versions ffmpeg || \ + travis_wait brew install -v ffmpeg --without-x264 --without-xvid --without-gpl + brew info ffmpeg + echo '-----------------' else echo "Running for linux" - source /io/travis/build-wheels.sh fi + qmake -query } function run_tests { # Runs tests on installed distribution from an empty directory - # python --version - # python -c 'import sys; import yourpackage; sys.exit(yourpackage.test())' - set +e echo "Run tests..." echo $PWD - ls -lh if [ -n "$IS_OSX" ]; then echo "Running for OS X" cd ../tests/ - source ../travis/test-wheels.sh else echo "Running for linux" - apt-get update - apt-get -y install --fix-missing libglib2.0-0 libsm6 cd /io/tests/ - source /io/travis/test-wheels.sh fi + + test_wheels +} + +function test_wheels { + PYTHON=python$PYTHON_VERSION + + echo "Starting tests..." + + #Test package + $PYTHON -m unittest test } + +export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' +set -x \ No newline at end of file diff --git a/cv2/__init__.py b/cv2/__init__.py index ca2cb308..3c176752 100644 --- a/cv2/__init__.py +++ b/cv2/__init__.py @@ -1,6 +1,6 @@ import importlib -import os +# make IDE's (PyCharm) autocompletion happy from .cv2 import * from .data import * diff --git a/multibuild b/multibuild index ad0ab85c..9330c3dc 160000 --- a/multibuild +++ b/multibuild @@ -1 +1 @@ -Subproject commit ad0ab85c3d3e3ec352c2c9bac973bd96da265c85 +Subproject commit 9330c3dcc318b7b2b734ab00485d2ab253761811 diff --git a/multibuild_customize.sh b/multibuild_customize.sh new file mode 100644 index 00000000..9b798c90 --- /dev/null +++ b/multibuild_customize.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# Customize multibuild logic that is run before entering Docker. Sourced from travis.yml . +export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' +set -x +REPO_DIR=$(dirname "${BASH_SOURCE[0]}") +DOCKER_IMAGE='quay.io/skvark/manylinux_$plat' diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 6c4932c1..00000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -wheel -twine diff --git a/setup.py b/setup.py index 2a89aa6f..039136d7 100644 --- a/setup.py +++ b/setup.py @@ -1,115 +1,349 @@ -from setuptools import setup, find_packages -from setuptools.dist import Distribution -import pip -import os -import sys -import io - -# cv_version.py should be generated by running find_version.py -from cv_version import opencv_version - -contrib_build = False -package_name = "opencv-python" -numpy_version = "" -long_description = "" -package_data = {} - -contrib = os.getenv('ENABLE_CONTRIB', None) - -if contrib is not None: - if int(contrib) == 1: - contrib_build = True -else: - try: - print("Trying to read contrib enable flag from file...") - with open("contrib.enabled") as f: - flag = int(f.read(1)) - if flag == 1: - contrib_build = True - except: - pass +# No 3rd-party modules here, see "3rd-party" note below +import io, os, os.path, sys, runpy, subprocess, re, sysconfig -# Use different README and package name for contrib build. -if contrib_build: - package_name = "opencv-contrib-python" - with io.open('README_CONTRIB.rst', encoding="utf-8") as f: - long_description = f.read() -else: - with io.open('README.rst', encoding="utf-8") as f: - long_description = f.read() -# Get required numpy version -for package in pip.get_installed_distributions(): - if package.key == "numpy": - numpy_version = package.version +def main(): + os.chdir(os.path.dirname(os.path.abspath(__file__))) -if os.name == 'posix': - package_data['cv2'] = ['*.so'] -else: - package_data['cv2'] = ['*.pyd', '*.dll'] + # These are neede for source fetching + cmake_source_dir = "opencv" + build_contrib = get_build_contrib() -package_data['cv2'] += ["LICENSE.txt", "LICENSE-3RD-PARTY.txt"] -package_data[''] = ['*.xml'] -""" + # Only import 3rd-party modules after having installed all the build dependencies: + # any of them, or their dependencies, can be updated during that process, + # leading to version conflicts + numpy_version = get_or_install("numpy", "1.11.3" if sys.version_info[:2] >= (3, 6) else "1.11.1") + get_or_install("scikit-build") + import skbuild + + if os.path.exists('.git'): + import pip.vcs.git + g = pip.vcs.git.Git() + use_depth = g.get_git_version() >= type(g.get_git_version())("1.8.4") + g.run_command(["submodule", "update", "--init", "--recursive"] + \ + (["--depth=1"] if use_depth else []) + \ + [cmake_source_dir]) + if build_contrib: + g.run_command(["submodule", "update", "--init", "--recursive"] + \ + (["--depth=1"] if use_depth else []) + \ + ["opencv_contrib"]) + del use_depth, g, pip -This is my old hack to force binary distribution. -However, it doesn't work properly because the binaries -are placed into purelib instead of platlib. + # https://stackoverflow.com/questions/1405913/python-32bit-or-64bit-mode + x64 = sys.maxsize>2**32 -class BinaryDistribution(Distribution): - def has_ext_modules(self): - return True - def is_pure(self): - return False -""" + package_name = "opencv-contrib-python" if build_contrib else "opencv-python" + long_description = io.open('README_CONTRIB.rst' if build_contrib else 'README.rst', encoding="utf-8").read() + package_version = get_opencv_version() -# This creates a list which is empty but returns a length of 1. -# Should make the wheel a binary distribution and platlib compliant. + packages = ['cv2', 'cv2.data'] + package_data = \ + {'cv2': + ['*%s' % sysconfig.get_config_var('SO')] + (['*.dll'] if os.name == 'nt' else []) + + ["LICENSE.txt", "LICENSE-3RD-PARTY.txt"], + 'cv2.data': + ["*.xml"] + } + + # Files from CMake output to copy to package. + # Path regexes with forward slashes relative to CMake install dir. + rearrange_cmake_output_data = \ + {'cv2': + ([r'bin/opencv_ffmpeg\d{3}%s\.dll' % + ('_64' if x64 else '')] if os.name == 'nt' else [] + ) + \ + # In Windows, in python/X.Y//; in Linux, in just python/X.Y/. + # Naming conventions vary so widely between versions and OSes + # had to give up on checking them. + ['python/([^/]+/){1,2}cv2[^/]*%(ext)s' % { + 'ext': re.escape(sysconfig.get_config_var('SO')) + } + ], + 'cv2.data': + [ # OPENCV_OTHER_INSTALL_PATH + ('etc' if os.name =='nt' else 'share/OpenCV') + + r'/haarcascades/.*\.xml'] + } + # Files in sourcetree outside package dir that should be copied to package. + # Raw paths relative to sourcetree root. + files_outside_package_dir = \ + {'cv2': + ['LICENSE.txt', 'LICENSE-3RD-PARTY.txt'] + } + + cmake_args = ([ + "-G", "Visual Studio 14" + (" Win64" if x64 else '') + ] if os.name == 'nt' else [ + "-G", "Unix Makefiles" #don't make CMake try (and fail) Ninja first + ]) + \ + [ + # skbuild inserts PYTHON_* vars. That doesn't satisfy opencv build scripts in case of Py3 + "-DPYTHON%d_EXECUTABLE=%s" % (sys.version_info[0], sys.executable), + "-DBUILD_opencv_python%d=ON" % sys.version_info[0], + # Otherwise, opencv scripts would want to install `.pyd' right into site-packages, + # and skbuild bails out on seeing that + "-DINSTALL_CREATE_DISTRIB=ON", + # See opencv/CMakeLists.txt for options and defaults + "-DBUILD_opencv_apps=OFF", + "-DBUILD_SHARED_LIBS=OFF", + "-DBUILD_TESTS=OFF", + "-DBUILD_PERF_TESTS=OFF", + "-DBUILD_DOCS=OFF" + ] + \ + ([ "-DOPENCV_EXTRA_MODULES_PATH=" + os.path.abspath("opencv_contrib/modules") ] + if build_contrib else []) + + # OS-specific components + if sys.platform == 'darwin' or sys.platform.startswith('linux'): + cmake_args.append( "-DWITH_QT=4" ) + if sys.platform.startswith('linux'): + cmake_args.append( "-DWITH_V4L=ON" ) + if all(v in os.environ for v in ('JPEG_INCLUDE_DIR', 'JPEG_LIBRARY')): + cmake_args += [ + "-DBUILD_JPEG=OFF", + "-DJPEG_INCLUDE_DIR=%s" % os.environ['JPEG_INCLUDE_DIR'], + "-DJPEG_LIBRARY=%s" % os.environ['JPEG_LIBRARY'] + ] + + # Turn off broken components + if sys.platform == 'darwin': + cmake_args.append("-DWITH_LAPACK=OFF") # Some OSX LAPACK fns are incompatible, see + # https://github.com/skvark/opencv-python/issues/21 + if sys.platform.startswith('linux'): + cmake_args.append( "-DWITH_IPP=OFF" ) # https://github.com/opencv/opencv/issues/10411 + + + + # ABI config variables are introduced in PEP 425 + if sys.version_info[:2] < (3, 2): + import warnings + warnings.filterwarnings('ignore', r"Config variable '[^']+' is unset, " + r"Python ABI tag may be incorrect", + category=RuntimeWarning) + del warnings + + + # works via side effect + RearrangeCMakeOutput(rearrange_cmake_output_data, + files_outside_package_dir, + package_data.keys()) + + skbuild.setup( + name=package_name, + version=package_version, + url='https://github.com/skvark/opencv-python', + license='MIT', + description='Wrapper package for OpenCV python bindings.', + long_description=long_description, + packages=packages, + package_data=package_data, + maintainer="Olli-Pekka Heinisuo", + include_package_data=True, + ext_modules=EmptyListWithLength(), + install_requires="numpy>=%s" % numpy_version, + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Intended Audience :: Education', + 'Intended Audience :: Information Technology', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: MIT License', + 'Operating System :: MacOS', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: C++', + 'Programming Language :: Python :: Implementation :: CPython', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Image Recognition', + 'Topic :: Software Development', + ], + cmake_args=cmake_args, + cmake_source_dir=cmake_source_dir, + ) + + +class RearrangeCMakeOutput(object): + """Patch SKBuild logic to only take files related to the Python package + and construct a file hierarchy that SKBuild expects (see below)""" + _setuptools_wrap = None + + # Have to wrap a function reference, or it's converted + # into an instance method on attr assignment + import argparse + wraps = argparse.Namespace( + _classify_files=None) + del argparse + + package_paths_re = None + packages = None + files_outside_package = None + + def __init__(self, package_paths_re, files_outside_package, packages): + cls = self.__class__ + assert not cls.wraps._classify_files, "Singleton object" + import skbuild.setuptools_wrap + + cls._setuptools_wrap = skbuild.setuptools_wrap + cls.wraps._classify_files = cls._setuptools_wrap._classify_files + cls._setuptools_wrap._classify_files = self._classify_files_override + + cls.package_paths_re = package_paths_re + cls.files_outside_package = files_outside_package + cls.packages = packages + def __del__(self): + cls = self.__class__ + cls._setuptools_wrap._classify_files = cls.wraps._classify_files + cls.wraps._classify_files = None + cls._setuptools_wrap = None + + def _classify_files_override(self, install_paths, + package_data, package_prefixes, + py_modules, new_py_modules, + scripts, new_scripts, + data_files, + cmake_source_dir, cmake_install_reldir): + """From all CMake output, we're only interested in a few files + and must place them into CMake install dir according + to Python conventions for SKBuild to find them: + package\ + file + subpackage\ + etc. + """ + cls = self.__class__ + # 'relpath'/'reldir' = relative to CMAKE_INSTALL_DIR/cmake_install_dir + # 'path'/'dir' = relative to sourcetree root + cmake_install_dir = os.path.join(cls._setuptools_wrap.CMAKE_INSTALL_DIR, + cmake_install_reldir) + install_relpaths = [os.path.relpath(p, cmake_install_dir) for p in install_paths] + fslash_install_relpaths = [p.replace(os.path.sep, '/') for p in install_relpaths] + relpaths_zip = list(zip(fslash_install_relpaths, install_relpaths)) + del install_relpaths, fslash_install_relpaths + + final_install_relpaths = [] + print("Copying files from CMake output") + for package_name, relpaths_re in cls.package_paths_re.items(): + package_dest_reldir = package_name.replace('.', os.path.sep) + for relpath_re in relpaths_re: + found = False + r = re.compile(relpath_re+'$') + for fslash_relpath, relpath in relpaths_zip: + m = r.match(fslash_relpath) + if not m: continue + found = True + new_install_relpath = os.path.join( + package_dest_reldir, + os.path.basename(relpath)) + cls._setuptools_wrap._copy_file( + os.path.join(cmake_install_dir, relpath), + os.path.join(cmake_install_dir, new_install_relpath), + hide_listing=False) + final_install_relpaths.append(new_install_relpath) + del m, fslash_relpath, new_install_relpath + else: + if not found: raise Exception("Not found: '%s'" % relpath_re) + del r, found + del relpaths_zip + + print("Copying files from non-default sourcetree locations") + for package_name, paths in cls.files_outside_package.items(): + package_dest_reldir = package_name.replace('.', os.path.sep) + for path in paths: + new_install_relpath = os.path.join( + package_dest_reldir, + # Don't yet have a need to copy + # to subdirectories of package dir + os.path.basename(path)) + cls._setuptools_wrap._copy_file( + path, os.path.join(cmake_install_dir, new_install_relpath), + hide_listing = False + ) + final_install_relpaths.append(new_install_relpath) + + + final_install_paths = [os.path.join(cmake_install_dir, p) for p in final_install_relpaths] + + return (cls.wraps._classify_files)( + final_install_paths, + package_data, package_prefixes, + py_modules, new_py_modules, + scripts, new_scripts, + data_files, + # To get around a demented check + # that prepends source dir to paths and breaks package detection code. + # Can't imagine what the authors were thinking that should be doing. + cmake_source_dir = '', + cmake_install_dir = cmake_install_reldir + ) + + +def install_packages(*requirements): + # No more convenient way until PEP 518 is implemented; setuptools only handles eggs + subprocess.check_call([sys.executable, + "-m", "pip", "install"] + + list(requirements)) + + +def get_opencv_version(): + # cv_version.py should be generated by running find_version.py + runpy.run_path("find_version.py") + from cv_version import opencv_version + return opencv_version + + +def get_build_contrib(): + build_contrib = False + try: + build_contrib = bool(int(os.getenv('ENABLE_CONTRIB', None))) + except Exception: + pass + + if not build_contrib: + try: + build_contrib = bool(int(open("contrib.enabled").read(1))) + except Exception: + pass + return build_contrib + + +def get_or_install(name, version = None): + """If a package is already installed, build against it. If not, install""" + # Do not import 3rd-party modules into the current process + import json + js_packages = json.loads( + subprocess.check_output( + [sys.executable, "-m", "pip", "list", "--format=json"]) + .decode('ascii')) #valid names & versions are ASCII as per PEP 440 + try: + [package] = (package for package in js_packages + if package['name'] == name) + except ValueError: + install_packages("%s==%s"%(name, version) if version else name) + return version + else: + return package['version'] + + +# This creates a list which is empty but returns a length of 1. +# Should make the wheel a binary distribution and platlib compliant. class EmptyListWithLength(list): def __len__(self): return 1 -setup(name=package_name, - version=opencv_version, - url='https://github.com/skvark/opencv-python', - license='MIT', - description='Wrapper package for OpenCV python bindings.', - long_description=long_description, - packages=find_packages(), - package_data=package_data, - maintainer="Olli-Pekka Heinisuo", - include_package_data=True, - ext_modules=EmptyListWithLength(), - install_requires="numpy>=%s" % numpy_version, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'Intended Audience :: Information Technology', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: MIT License', - 'Operating System :: MacOS', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX', - 'Operating System :: Unix', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: C++', - 'Programming Language :: Python :: Implementation :: CPython', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Image Recognition', - 'Topic :: Software Development', - ] - ) +if __name__ == '__main__': + main() diff --git a/travis/build-wheels-osx.sh b/travis/build-wheels-osx.sh deleted file mode 100644 index 9ecc9ea5..00000000 --- a/travis/build-wheels-osx.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -set +e -echo 'Begin build-wheel OSX ...' - -export PYTHON_VERSION=${MB_PYTHON_VERSION/./} -echo 'MB_PYTHON_VERSION: ' "$MB_PYTHON_VERSION" -echo 'PYTHON_VERSION: ' "$PYTHON_VERSION" - -echo 'PIP and brew installs' - -pip install "$BUILD_DEPENDS" - -echo 'Installing QT4' -brew tap cartr/qt4 -brew tap-pin cartr/qt4 -brew install qt@4 -echo '-----------------' -echo 'Installing FFmpeg' -brew install ffmpeg --without-x264 --without-xvid --without-gpl -brew info ffmpeg -echo '-----------------' - -qmake -query - -cd opencv - -echo "Apply patch" - -git apply --ignore-space-change --ignore-whitespace ../travis/disable_i386.patch - -echo "Detect Python paths for OpenCV" - -PYTHON_VERSION_STRING=$(python -c "from platform import python_version; print(python_version())") -PYTHON_INCLUDE_PATH=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") -PYTHON_PACKAGES_PATH=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") -PYTHON_NUMPY_INCLUDE_DIRS=$(python -c "import os; os.environ['DISTUTILS_USE_SDK']='1'; import numpy.distutils; print(os.pathsep.join(numpy.distutils.misc_util.get_numpy_include_dirs()))") -PYTHON_NUMPY_VERSION=$(python -c "import numpy; print(numpy.version.version)") - -echo "PYthon version string: $PYTHON_VERSION_STRING" -echo "Python include path: $PYTHON_INCLUDE_PATH" -echo "Python packages path: $PYTHON_PACKAGES_PATH" -echo "Python numpy incude dirs: $PYTHON_NUMPY_INCLUDE_DIRS" -echo "Python numpy version: $PYTHON_NUMPY_VERSION" - -echo 'Config make' - -mkdir build -cd build - -if [[ $PYTHON_VERSION == 2* ]] && [[ $ENABLE_CONTRIB == 0 ]]; then - echo 'Config for Py2' - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D CMAKE_TOOLCHAIN_FILE=../../travis/toolchain_macos.cmake \ - -D BUILD_opencv_python3=OFF -D BUILD_opencv_java=OFF -D BUILD_SHARED_LIBS=OFF -D WITH_LAPACK=OFF -D WITH_QT=4 \ - -D INSTALL_C_EXAMPLES=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF \ - -D BUILD_EXAMPLES=OFF \ - -D PYTHON2INTERP_FOUND=ON -DPYTHON2LIBS_FOUND=ON \ - -D PYTHON2_EXECUTABLE=python \ - -D PYTHON2_VERSION_STRING="$PYTHON_VERSION_STRING" \ - -D PYTHON2_INCLUDE_PATH="$PYTHON_INCLUDE_PATH" \ - -D PYTHON2_PACKAGES_PATH="$PYTHON_PACKAGES_PATH" \ - -D PYTHON2_NUMPY_INCLUDE_DIRS="$PYTHON_NUMPY_INCLUDE_DIRS" \ - -D PYTHON2_NUMPY_VERSION="$PYTHON_NUMPY_VERSION" \ - .. - -fi - -if [[ $PYTHON_VERSION == 3* ]] && [[ $ENABLE_CONTRIB == 0 ]]; then - echo 'Config for Py3' - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D CMAKE_TOOLCHAIN_FILE=../../travis/toolchain_macos.cmake \ - -D BUILD_opencv_python2=OFF -D BUILD_opencv_java=OFF -D BUILD_SHARED_LIBS=OFF -D WITH_LAPACK=OFF -D WITH_QT=4 \ - -D INSTALL_C_EXAMPLES=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF \ - -D BUILD_EXAMPLES=OFF \ - -D PYTHON3INTERP_FOUND=ON -DPYTHON3LIBS_FOUND=ON \ - -D PYTHON3_EXECUTABLE=python \ - -D PYTHON3_VERSION_STRING="$PYTHON_VERSION_STRING" \ - -D PYTHON3_INCLUDE_PATH="$PYTHON_INCLUDE_PATH" \ - -D PYTHON3_PACKAGES_PATH="$PYTHON_PACKAGES_PATH" \ - -D PYTHON3_NUMPY_INCLUDE_DIRS="$PYTHON_NUMPY_INCLUDE_DIRS" \ - -D PYTHON3_NUMPY_VERSION="$PYTHON_NUMPY_VERSION" \ - .. - -fi - -if [[ $PYTHON_VERSION == 2* ]] && [[ $ENABLE_CONTRIB == 1 ]]; then - echo 'Config for Py2' - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D CMAKE_TOOLCHAIN_FILE=../../travis/toolchain_macos.cmake -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \ - -D BUILD_opencv_python3=OFF -D BUILD_opencv_java=OFF -D BUILD_SHARED_LIBS=OFF -D WITH_LAPACK=OFF -D WITH_QT=4 \ - -D INSTALL_C_EXAMPLES=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF \ - -D BUILD_EXAMPLES=OFF \ - -D PYTHON2INTERP_FOUND=ON -DPYTHON2LIBS_FOUND=ON \ - -D PYTHON2_EXECUTABLE=python \ - -D PYTHON2_VERSION_STRING="$PYTHON_VERSION_STRING" \ - -D PYTHON2_INCLUDE_PATH="$PYTHON_INCLUDE_PATH" \ - -D PYTHON2_PACKAGES_PATH="$PYTHON_PACKAGES_PATH" \ - -D PYTHON2_NUMPY_INCLUDE_DIRS="$PYTHON_NUMPY_INCLUDE_DIRS" \ - -D PYTHON2_NUMPY_VERSION="$PYTHON_NUMPY_VERSION" \ - .. - -fi - -if [[ $PYTHON_VERSION == 3* ]] && [[ $ENABLE_CONTRIB == 1 ]]; then - echo 'Config for Py3' - cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D CMAKE_TOOLCHAIN_FILE=../../travis/toolchain_macos.cmake -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \ - -D BUILD_opencv_python2=OFF -D BUILD_opencv_java=OFF -D BUILD_SHARED_LIBS=OFF -D WITH_LAPACK=OFF -D WITH_QT=4 \ - -D INSTALL_C_EXAMPLES=OFF -D INSTALL_PYTHON_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF \ - -D BUILD_EXAMPLES=OFF \ - -D PYTHON3INTERP_FOUND=ON -DPYTHON3LIBS_FOUND=ON \ - -D PYTHON3_EXECUTABLE=python \ - -D PYTHON3_VERSION_STRING="$PYTHON_VERSION_STRING" \ - -D PYTHON3_INCLUDE_PATH="$PYTHON_INCLUDE_PATH" \ - -D PYTHON3_PACKAGES_PATH="$PYTHON_PACKAGES_PATH" \ - -D PYTHON3_NUMPY_INCLUDE_DIRS="$PYTHON_NUMPY_INCLUDE_DIRS" \ - -D PYTHON3_NUMPY_VERSION="$PYTHON_NUMPY_VERSION" \ - .. - -fi - -echo 'Begin build' - -if [[ $PYTHON_VERSION == 2* ]]; then - echo 'Build for Py2' - make -j2 opencv_python2 - -fi - -if [[ $PYTHON_VERSION == 3* ]]; then - echo 'Build for Py3' - make -j2 opencv_python3 - -fi - -# Moving back to opencv-python -cd ../.. - -if [[ $PYTHON_VERSION == 2* ]]; then - echo 'Copying *.so for Py2' - cp opencv/build/lib/cv2.so cv2/ - -fi - -if [[ $PYTHON_VERSION == 3* ]]; then - echo 'Copying *.so for Py3' - cp opencv/build/lib/python3/*.so cv2/ - -fi - -echo 'Build wheel' - diff --git a/travis/build-wheels.sh b/travis/build-wheels.sh deleted file mode 100755 index c6598d20..00000000 --- a/travis/build-wheels.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -set +e -echo 'Begin build-wheel...' - -export PYTHON_VERSION=${PYTHON_VERSION/./} -echo 'PYTHON_VERSION: ' "$PYTHON_VERSION" - -ENABLE_CONTRIB=$(