#------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. #-------------------------------------------------------------------------- from setuptools import setup, find_packages, Extension from distutils import log as logger from distutils.command.build_ext import build_ext as _build_ext from glob import glob from os import path, getcwd, environ, remove, walk, makedirs, listdir from shutil import copyfile, copytree, rmtree import platform import subprocess import sys import datetime nightly_build = False featurizers_build = False package_name = 'onnxruntime' wheel_name_suffix = None # Any combination of the following arguments can be applied if '--use_featurizers' in sys.argv: featurizers_build = True sys.argv.remove('--use_featurizers') if '--nightly_build' in sys.argv: package_name = 'ort-nightly' nightly_build = True sys.argv.remove('--nightly_build') for arg in sys.argv[1:]: if arg.startswith("--wheel_name_suffix="): wheel_name_suffix = arg[len("--wheel_name_suffix="):] sys.argv.remove(arg) break # The following arguments are mutually exclusive if '--use_tensorrt' in sys.argv: package_name = 'onnxruntime-gpu-tensorrt' if not nightly_build else 'ort-trt-nightly' sys.argv.remove('--use_tensorrt') elif '--use_cuda' in sys.argv: package_name = 'onnxruntime-gpu' if not nightly_build else 'ort-gpu-nightly' sys.argv.remove('--use_cuda') elif '--use_ngraph' in sys.argv: package_name = 'onnxruntime-ngraph' sys.argv.remove('--use_ngraph') elif '--use_openvino' in sys.argv: package_name = 'onnxruntime-openvino' sys.argv.remove('--use_openvino') elif '--use_dnnl' in sys.argv: package_name = 'onnxruntime-dnnl' sys.argv.remove('--use_dnnl') elif '--use_nuphar' in sys.argv: package_name = 'onnxruntime-nuphar' sys.argv.remove('--use_nuphar') elif '--use_vitisai' in sys.argv: package_name = 'onnxruntime-vitisai' sys.argv.remove('--use_vitisai') elif '--use_acl' in sys.argv: package_name = 'onnxruntime-acl' sys.argv.remove('--use_acl') elif '--use_armnn' in sys.argv: package_name = 'onnxruntime-armnn' sys.argv.remove('--use_armnn') # PEP 513 defined manylinux1_x86_64 and manylinux1_i686 # PEP 571 defined manylinux2010_x86_64 and manylinux2010_i686 # PEP 599 defines the following platform tags: # manylinux2014_x86_64 # manylinux2014_i686 # manylinux2014_aarch64 # manylinux2014_armv7l # manylinux2014_ppc64 # manylinux2014_ppc64le # manylinux2014_s390x manylinux_tags = [ 'manylinux1_x86_64', 'manylinux1_i686', 'manylinux2010_x86_64', 'manylinux2010_i686', 'manylinux2014_x86_64', 'manylinux2014_i686', 'manylinux2014_aarch64', 'manylinux2014_armv7l', 'manylinux2014_ppc64', 'manylinux2014_ppc64le', 'manylinux2014_s390x', ] is_manylinux = environ.get('AUDITWHEEL_PLAT', None) in manylinux_tags class build_ext(_build_ext): def build_extension(self, ext): dest_file = self.get_ext_fullpath(ext.name) logger.info('copying %s -> %s', ext.sources[0], dest_file) copyfile(ext.sources[0], dest_file) try: from wheel.bdist_wheel import bdist_wheel as _bdist_wheel class bdist_wheel(_bdist_wheel): def finalize_options(self): _bdist_wheel.finalize_options(self) if not is_manylinux: self.root_is_pure = False def _rewrite_ld_preload(self, to_preload): with open('onnxruntime/capi/_ld_preload.py', 'rt') as f: ld_preload = f.read().splitlines() with open('onnxruntime/capi/_ld_preload.py', 'wt') as f: for line in ld_preload: f.write(line) f.write('\n') if 'LD_PRELOAD_BEGIN_MARK' in line: break if len(to_preload) > 0: f.write('from ctypes import CDLL, RTLD_GLOBAL\n') for library in to_preload: f.write('_{} = CDLL("{}", mode=RTLD_GLOBAL)\n'.format(library.split('.')[0], library)) def run(self): if is_manylinux: source = 'onnxruntime/capi/onnxruntime_pybind11_state.so' dest = 'onnxruntime/capi/onnxruntime_pybind11_state_manylinux1.so' logger.info('copying %s -> %s', source, dest) copyfile(source, dest) result = subprocess.run(['patchelf', '--print-needed', dest], check=True, stdout=subprocess.PIPE, universal_newlines=True) cuda_dependencies = ['libcublas.so', 'libcudnn.so', 'libcudart.so', 'libcurand.so', 'libcufft.so', 'libnvToolsExt.so'] to_preload = [] args = ['patchelf', '--debug'] for line in result.stdout.split('\n'): for dependency in cuda_dependencies: if dependency in line: to_preload.append(line) args.extend(['--remove-needed', line]) args.append(dest) if len(to_preload) > 0: subprocess.run(args, check=True, stdout=subprocess.PIPE) self._rewrite_ld_preload(to_preload) _bdist_wheel.run(self) if is_manylinux: file = glob(path.join(self.dist_dir, '*linux*.whl'))[0] logger.info('repairing %s for manylinux1', file) try: subprocess.run(['auditwheel', 'repair', '-w', self.dist_dir, file], check=True, stdout=subprocess.PIPE) finally: logger.info('removing %s', file) remove(file) except ImportError as error: print("Error importing dependencies:") print(error) bdist_wheel = None # Additional binaries if platform.system() == 'Linux': libs = ['onnxruntime_pybind11_state.so', 'libdnnl.so.1', 'libmklml_intel.so', 'libmklml_gnu.so', 'libiomp5.so', 'mimalloc.so'] # DNNL & TensorRT EPs are built as shared libs libs.extend(['libonnxruntime_providers_shared.so']) libs.extend(['libonnxruntime_providers_dnnl.so']) libs.extend(['libonnxruntime_providers_tensorrt.so']) # nGraph Libs libs.extend(['libngraph.so', 'libcodegen.so', 'libcpu_backend.so', 'libmkldnn.so', 'libtbb_debug.so', 'libtbb_debug.so.2', 'libtbb.so', 'libtbb.so.2']) # OpenVINO Libs if package_name == 'onnxruntime-openvino': if platform.system() == 'Linux': libs.extend(['libovep_ngraph.so']) # Nuphar Libs libs.extend(['libtvm.so.0.5.1']) if nightly_build: libs.extend(['libonnxruntime_pywrapper.so']) elif platform.system() == "Darwin": libs = ['onnxruntime_pybind11_state.so', 'libdnnl.1.dylib', 'mimalloc.so'] # TODO add libmklml and libiomp5 later. # DNNL & TensorRT EPs are built as shared libs libs.extend(['libonnxruntime_providers_shared.dylib']) libs.extend(['libonnxruntime_providers_dnnl.dylib']) libs.extend(['libonnxruntime_providers_tensorrt.dylib']) if nightly_build: libs.extend(['libonnxruntime_pywrapper.dylib']) else: libs = ['onnxruntime_pybind11_state.pyd', 'dnnl.dll', 'mklml.dll', 'libiomp5md.dll'] # DNNL & TensorRT EPs are built as shared libs libs.extend(['onnxruntime_providers_shared.dll']) libs.extend(['onnxruntime_providers_dnnl.dll']) libs.extend(['onnxruntime_providers_tensorrt.dll']) # nGraph Libs libs.extend(['ngraph.dll', 'cpu_backend.dll', 'tbb.dll', 'mimalloc-override.dll', 'mimalloc-redirect.dll', 'mimalloc-redirect32.dll']) # Nuphar Libs libs.extend(['tvm.dll']) if nightly_build: libs.extend(['onnxruntime_pywrapper.dll']) if is_manylinux: data = ['capi/libonnxruntime_pywrapper.so'] if nightly_build else [] ext_modules = [ Extension( 'onnxruntime.capi.onnxruntime_pybind11_state', ['onnxruntime/capi/onnxruntime_pybind11_state_manylinux1.so'], ), ] else: data = [path.join('capi', x) for x in libs if path.isfile(path.join('onnxruntime', 'capi', x))] ext_modules = [] # Additional examples examples_names = ["mul_1.onnx", "logreg_iris.onnx", "sigmoid.onnx"] examples = [path.join('datasets', x) for x in examples_names] # Extra files such as EULA and ThirdPartyNotices extra = ["LICENSE", "ThirdPartyNotices.txt", "Privacy.md"] # Description README = path.join(getcwd(), "docs/python/README.rst") if not path.exists(README): this = path.dirname(__file__) README = path.join(this, "docs/python/README.rst") if not path.exists(README): raise FileNotFoundError("Unable to find 'README.rst'") with open(README) as f: long_description = f.read() packages = [ 'onnxruntime', 'onnxruntime.backend', 'onnxruntime.capi', 'onnxruntime.capi.training', 'onnxruntime.datasets', 'onnxruntime.tools', 'onnxruntime.quantization', ] package_data = {} data_files = [] if package_name == 'onnxruntime-nuphar': packages += ["onnxruntime.nuphar"] extra += [path.join('nuphar', 'NUPHAR_CACHE_VERSION')] if featurizers_build: # Copy the featurizer data from its current directory into the onnx runtime directory so that the # content can be included as module data. # Apparently, the root_dir is different based on how the script is invoked source_root_dir = None dest_root_dir = None for potential_source_prefix, potential_dest_prefix in [ (getcwd(), getcwd()), (path.dirname(__file__), path.dirname(__file__)), (path.join(getcwd(), ".."), getcwd()), ]: potential_dir = path.join(potential_source_prefix, "external", "FeaturizersLibrary", "Data") if path.isdir(potential_dir): source_root_dir = potential_source_prefix dest_root_dir = potential_dest_prefix break if source_root_dir is None: raise Exception("Unable to find the build root dir") assert dest_root_dir is not None featurizer_source_dir = path.join(source_root_dir, "external", "FeaturizersLibrary", "Data") assert path.isdir(featurizer_source_dir), featurizer_source_dir featurizer_dest_dir = path.join(dest_root_dir, "onnxruntime", "FeaturizersLibrary", "Data") if path.isdir(featurizer_dest_dir): rmtree(featurizer_dest_dir) for item in listdir(featurizer_source_dir): this_featurizer_source_fullpath = path.join(featurizer_source_dir) assert path.isdir(this_featurizer_source_fullpath), this_featurizer_source_fullpath copytree(this_featurizer_source_fullpath, featurizer_dest_dir) packages.append("onnxruntime.FeaturizersLibrary.Data.{}".format(item)) package_data[packages[-1]] = listdir(path.join(featurizer_dest_dir, item)) package_data["onnxruntime"] = data + examples + extra version_number = '' with open('VERSION_NUMBER') as f: version_number = f.readline().strip() if nightly_build: #https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables build_suffix = environ.get('BUILD_BUILDNUMBER') if build_suffix is None: #The following line is only for local testing build_suffix = str(datetime.datetime.now().date().strftime("%Y%m%d")) else: build_suffix = build_suffix.replace('.','') version_number = version_number + ".dev" + build_suffix if wheel_name_suffix: package_name = "{}_{}".format(package_name, wheel_name_suffix) cmd_classes = {} if bdist_wheel is not None : cmd_classes['bdist_wheel'] = bdist_wheel cmd_classes['build_ext'] = build_ext requirements_path = path.join(getcwd(), "requirements.txt") if not path.exists(requirements_path): this = path.dirname(__file__) requirements_path = path.join(this, "requirements.txt") if not path.exists(requirements_path): raise FileNotFoundError("Unable to find 'requirements.txt'") with open(requirements_path) as f: install_requires = f.read().splitlines() # Setup setup( name=package_name, version=version_number, description='ONNX Runtime Python bindings', long_description=long_description, author='Microsoft Corporation', author_email='onnx@microsoft.com', cmdclass=cmd_classes, license="MIT License", packages=packages, ext_modules=ext_modules, package_data=package_data, data_files=data_files, install_requires=install_requires, entry_points= { 'console_scripts': [ 'onnxruntime_test = onnxruntime.tools.onnxruntime_test:main', ] }, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: POSIX :: Linux', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS', 'Programming Language :: Python', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7'], )