summaryrefslogtreecommitdiffstats
path: root/ml/dlib/setup.py
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/setup.py')
-rw-r--r--ml/dlib/setup.py251
1 files changed, 251 insertions, 0 deletions
diff --git a/ml/dlib/setup.py b/ml/dlib/setup.py
new file mode 100644
index 000000000..9bc20b334
--- /dev/null
+++ b/ml/dlib/setup.py
@@ -0,0 +1,251 @@
+"""setup for the dlib project
+ Copyright (C) 2015 Ehsan Azar (dashesy@linux.com)
+ License: Boost Software License See LICENSE.txt for the full license.
+
+This file basically just uses CMake to compile the dlib python bindings project
+located in the tools/python folder and then puts the outputs into standard
+python packages.
+
+To build the dlib:
+ python setup.py build
+To build and install:
+ python setup.py install
+To package the wheel (after pip installing twine and wheel):
+ python setup.py bdist_wheel
+To upload the binary wheel to PyPi
+ twine upload dist/*.whl
+To upload the source distribution to PyPi
+ python setup.py sdist upload
+To exclude/include certain options in the cmake config use --yes and --no:
+ for example:
+ --yes USE_AVX_INSTRUCTIONS: will set -DUSE_AVX_INSTRUCTIONS=yes
+ --no USE_AVX_INSTRUCTIONS: will set -DUSE_AVX_INSTRUCTIONS=no
+Additional options:
+ --compiler-flags: pass flags onto the compiler, e.g. --compiler-flags "-Os -Wall" passes -Os -Wall onto GCC.
+ -G: Set the CMake generator. E.g. -G "Visual Studio 14 2015"
+ --clean: delete any previous build folders and rebuild. You should do this if you change any build options
+ by setting --compiler-flags or --yes or --no since last time you ran a build to make sure the changes
+ take effect.
+ --set: set arbitrary options e.g. --set CUDA_HOST_COMPILER=/usr/bin/gcc-6.4.0
+"""
+import os
+import re
+import sys
+import shutil
+import platform
+import subprocess
+import multiprocessing
+from distutils import log
+from math import ceil,floor
+
+from setuptools import setup, Extension
+from setuptools.command.build_ext import build_ext
+from distutils.version import LooseVersion
+
+
+def get_extra_cmake_options():
+ """read --clean, --yes, --no, --set, --compiler-flags, and -G options from the command line and add them as cmake switches.
+ """
+ _cmake_extra_options = []
+ _clean_build_folder = False
+
+ opt_key = None
+
+ argv = [arg for arg in sys.argv] # take a copy
+ # parse command line options and consume those we care about
+ for arg in argv:
+ if opt_key == 'compiler-flags':
+ _cmake_extra_options.append('-DCMAKE_CXX_FLAGS={arg}'.format(arg=arg.strip()))
+ elif opt_key == 'G':
+ _cmake_extra_options += ['-G', arg.strip()]
+ elif opt_key == 'yes':
+ _cmake_extra_options.append('-D{arg}=yes'.format(arg=arg.strip()))
+ elif opt_key == 'no':
+ _cmake_extra_options.append('-D{arg}=no'.format(arg=arg.strip()))
+ elif opt_key == 'set':
+ _cmake_extra_options.append('-D{arg}'.format(arg=arg.strip()))
+
+ if opt_key:
+ sys.argv.remove(arg)
+ opt_key = None
+ continue
+
+ if arg == '--clean':
+ _clean_build_folder = True
+ sys.argv.remove(arg)
+ continue
+
+ if arg in ['--yes', '--no', '--set', '--compiler-flags']:
+ opt_key = arg[2:].lower()
+ sys.argv.remove(arg)
+ continue
+ if arg in ['-G']:
+ opt_key = arg[1:]
+ sys.argv.remove(arg)
+ continue
+
+ return _cmake_extra_options, _clean_build_folder
+
+cmake_extra_options,clean_build_folder = get_extra_cmake_options()
+
+
+class CMakeExtension(Extension):
+ def __init__(self, name, sourcedir=''):
+ Extension.__init__(self, name, sources=[])
+ self.sourcedir = os.path.abspath(sourcedir)
+
+def rmtree(name):
+ """remove a directory and its subdirectories.
+ """
+ def remove_read_only(func, path, exc):
+ excvalue = exc[1]
+ if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
+ os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
+ func(path)
+ else:
+ raise
+
+ if os.path.exists(name):
+ log.info('Removing old directory {}'.format(name))
+ shutil.rmtree(name, ignore_errors=False, onerror=remove_read_only)
+
+
+class CMakeBuild(build_ext):
+
+ def get_cmake_version(self):
+ try:
+ out = subprocess.check_output(['cmake', '--version'])
+ except OSError:
+ raise RuntimeError("CMake must be installed to build the following extensions: " +
+ ", ".join(e.name for e in self.extensions))
+ return re.search(r'version\s*([\d.]+)', out.decode()).group(1)
+
+ def run(self):
+ if platform.system() == "Windows":
+ if LooseVersion(self.get_cmake_version()) < '3.1.0':
+ raise RuntimeError("CMake >= 3.1.0 is required on Windows")
+
+ for ext in self.extensions:
+ self.build_extension(ext)
+
+ def build_extension(self, ext):
+ extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
+
+ cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir,
+ '-DPYTHON_EXECUTABLE=' + sys.executable]
+
+ cmake_args += cmake_extra_options
+
+ cfg = 'Debug' if self.debug else 'Release'
+ build_args = ['--config', cfg]
+
+ if platform.system() == "Windows":
+ cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)]
+ if sys.maxsize > 2**32:
+ cmake_args += ['-A', 'x64']
+ build_args += ['--', '/m']
+ else:
+ cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
+ # Do a parallel build
+ build_args += ['--', '-j'+str(num_available_cpu_cores(2))]
+
+ build_folder = os.path.abspath(self.build_temp)
+
+ if clean_build_folder:
+ rmtree(build_folder)
+ if not os.path.exists(build_folder):
+ os.makedirs(build_folder)
+
+ cmake_setup = ['cmake', ext.sourcedir] + cmake_args
+ cmake_build = ['cmake', '--build', '.'] + build_args
+
+ print("Invoking CMake setup: '{}'".format(' '.join(cmake_setup)))
+ subprocess.check_call(cmake_setup, cwd=build_folder)
+ print("Invoking CMake build: '{}'".format(' '.join(cmake_build)))
+ subprocess.check_call(cmake_build, cwd=build_folder)
+
+def num_available_cpu_cores(ram_per_build_process_in_gb):
+ if 'TRAVIS' in os.environ and os.environ['TRAVIS']=='true':
+ # When building on travis-ci, just use 2 cores since travis-ci limits
+ # you to that regardless of what the hardware might suggest.
+ return 2
+ try:
+ mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
+ mem_gib = mem_bytes/(1024.**3)
+ num_cores = multiprocessing.cpu_count()
+ # make sure we have enough ram for each build process.
+ mem_cores = int(floor(mem_gib/float(ram_per_build_process_in_gb)+0.5));
+ # We are limited either by RAM or CPU cores. So pick the limiting amount
+ # and return that.
+ return max(min(num_cores, mem_cores), 1)
+ except ValueError:
+ return 2 # just assume 2 if we can't get the os to tell us the right answer.
+
+
+from setuptools.command.test import test as TestCommand
+class PyTest(TestCommand):
+ user_options = [('pytest-args=', 'a', "Arguments to pass to pytest")]
+
+ def initialize_options(self):
+ TestCommand.initialize_options(self)
+ self.pytest_args = '--ignore docs --ignore dlib'
+
+ def run_tests(self):
+ import shlex
+ #import here, cause outside the eggs aren't loaded
+ import pytest
+ errno = pytest.main(shlex.split(self.pytest_args))
+ sys.exit(errno)
+
+def read_version_from_cmakelists(cmake_file):
+ """Read version information
+ """
+ major = re.findall("set\(CPACK_PACKAGE_VERSION_MAJOR.*\"(.*)\"", open(cmake_file).read())[0]
+ minor = re.findall("set\(CPACK_PACKAGE_VERSION_MINOR.*\"(.*)\"", open(cmake_file).read())[0]
+ patch = re.findall("set\(CPACK_PACKAGE_VERSION_PATCH.*\"(.*)\"", open(cmake_file).read())[0]
+ return major + '.' + minor + '.' + patch
+
+def read_entire_file(fname):
+ """Read text out of a file relative to setup.py.
+ """
+ return open(os.path.join(fname)).read()
+
+setup(
+ name='dlib',
+ version=read_version_from_cmakelists('dlib/CMakeLists.txt'),
+ description='A toolkit for making real world machine learning and data analysis applications',
+ long_description=read_entire_file('README.md'),
+ author='Davis King',
+ author_email='davis@dlib.net',
+ url='https://github.com/davisking/dlib',
+ license='Boost Software License',
+ ext_modules=[CMakeExtension('dlib','tools/python')],
+ cmdclass=dict(build_ext=CMakeBuild, test=PyTest),
+ zip_safe=False,
+ tests_require=['pytest'],
+ packages=['dlib'],
+ keywords=['dlib', 'Computer Vision', 'Machine Learning'],
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Science/Research',
+ 'Intended Audience :: Developers',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: POSIX',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: Microsoft',
+ 'Operating System :: Microsoft :: Windows',
+ 'Programming Language :: C++',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Topic :: Scientific/Engineering',
+ 'Topic :: Scientific/Engineering :: Artificial Intelligence',
+ 'Topic :: Scientific/Engineering :: Image Recognition',
+ 'Topic :: Software Development',
+ ],
+)