2 from pathlib import Path
5 from itertools import chain
6 from distutils.command.build_py import build_py as _build_py
7 from distutils.command.clean import clean as _clean
10 from setuptools import setup, Extension, find_packages
11 from setuptools.command.build_ext import build_ext as _build_ext
12 from setuptools.command.install import install as _install
14 IS_WINDOWS = (platform.system() == 'Windows')
15 IS_DARWIN = (platform.system() == 'Darwin')
16 IS_LINUX = (platform.system() == 'Linux')
18 REQUIREMENTS_FILE = 'requirements.txt'
19 PACKAGE_NAME = 'inference_engine'
21 PACKAGE = Path(PACKAGE_NAME)
22 C_LIB_NAME = '{}._C'.format(PACKAGE_NAME)
24 _build_cmd = ['cmake', '--build', '.']
26 INFERENCE_ENGINE_DIR = None
27 BUNDLE_INFERENCE_ENGINE = False
30 def parse_command_line_options(cls):
31 """Propagates command line options to sub-commands.
32 Allows to run install command with build_ext options"""
34 base_user_options = getattr(cls, 'user_options', [])
35 base_boolean_options = getattr(cls, 'boolean_options', [])
37 base_init_options = cls.initialize_options
39 cls.user_options = base_user_options + [
40 ('copy-ie-libs', None, 'Copy Inference Engine Libraries to package directory'),
41 ('inference-engine-dir=', None, 'Path to Inference Engine directory')
44 cls.boolean_options = base_boolean_options + [
48 def initialize_options(self):
49 self.copy_ie_libs = False
50 self.inference_engine_dir = None
51 base_init_options(self)
54 global INFERENCE_ENGINE_DIR
55 global BUNDLE_INFERENCE_ENGINE
58 BUNDLE_INFERENCE_ENGINE = True
60 if self.inference_engine_dir:
61 INFERENCE_ENGINE_DIR = self.inference_engine_dir
65 cls.initialize_options = initialize_options
70 @parse_command_line_options
71 class install(_install):
75 @parse_command_line_options
76 class build_py(_build_py):
80 @parse_command_line_options
81 class build_ext(_build_ext):
83 if not self.extensions:
86 for i, ext in enumerate(self.extensions):
87 if ext.name == C_LIB_NAME:
89 self.extensions.pop(i)
94 def _build_cmake(self):
95 print("Building C++ extension")
96 if Path.cwd().joinpath("Makefile").is_file():
97 # in build directory, run make only
98 subprocess.call(_build_cmd)
100 # compile extension library and
101 self.build_cmake_lib()
102 print("Built C++ extension")
104 def build_cmake_lib(self):
105 def save_call(*args, error_msg=None, **kwargs):
106 if subprocess.call(*args, **kwargs) != 0:
109 shutil.rmtree(tmp_build_dir.as_posix(), ignore_errors=True)
112 tmp_build_dir = Path("tmp_build")
113 destination = Path(self.build_lib) / PACKAGE_NAME if not self.inplace else Path(PACKAGE_NAME)
114 tmp_build_dir.mkdir(exist_ok=False)
116 _python_executable_opt = ['-DPYTHON_EXECUTABLE={}'.format(sys.executable)]
117 _build_type_opt = ['-DCMAKE_BUILD_TYPE=Release']
118 _generator_opt = ['-G', 'NMake Makefiles' if IS_WINDOWS else "Unix Makefiles"]
121 if BUNDLE_INFERENCE_ENGINE:
122 _optional.append('-DCOPY_IE_LIBS=ON')
124 if INFERENCE_ENGINE_DIR:
125 _optional.append('-DInferenceEngine_DIR={}'.format(INFERENCE_ENGINE_DIR))
127 _cmake_cmd = list(chain(['cmake'], _generator_opt, _build_type_opt, _python_executable_opt, _optional, ['..']))
129 save_call(_cmake_cmd, cwd=tmp_build_dir.as_posix(), error_msg="Cmake generator failed")
130 save_call(_build_cmd, cwd=tmp_build_dir.as_posix(), error_msg="Build command failed")
132 build_ext.copy_compiled_libs(tmp_build_dir / PACKAGE_NAME, destination)
133 shutil.rmtree(tmp_build_dir.as_posix(), ignore_errors=False)
136 def copy_compiled_libs(source_dir, destination):
137 extensions = ['so', 'dll', 'pyd']
138 for path in chain.from_iterable(source_dir.glob("*.%s" % ext) for ext in extensions):
139 shutil.copy(path.as_posix(), destination.as_posix())
144 shutil.rmtree("tmp_build", ignore_errors=True)
145 extensions = ['so', 'dll', 'pyd']
146 for path in chain.from_iterable(PACKAGE.glob("*.%s" % ext) for ext in extensions):
151 def paths_to_str(paths):
152 return [p.as_posix() for p in paths]
155 with open(REQUIREMENTS_FILE) as reqs:
156 requirements = set(reqs.read().splitlines())
158 # do not spoil pre-installed opencv (in case it was built from source)
159 _opencv_package = "opencv-python"
163 if _opencv_package in requirements:
164 requirements.remove(_opencv_package)
166 requirements.add(_opencv_package)
170 PACKAGE / 'ie_api_impl.cpp',
171 PACKAGE / 'ie_api_impl.hpp',
173 PACKAGE / 'ie_api_impl_defs.pxd',
174 PACKAGE / 'ie_api.pyx',
175 PACKAGE / 'ie_api.pxd',
179 Extension(C_LIB_NAME, paths_to_str(c_sources))
183 'build_ext': build_ext,
184 'build_py': build_py,
192 description='Python inference for Inference Engine',
193 packages=find_packages(exclude=['tests']),
194 package_data={PACKAGE_NAME: ['*.so', '*.dll', '*dylib*', '*.pyd']},
195 include_package_data=True,
196 ext_modules=extensions,
198 install_requires=list(requirements),