onnx
/
setup.py
319 строк · 11.6 Кб
1# Copyright (c) ONNX Project Contributors
2#
3# SPDX-License-Identifier: Apache-2.0
4
5# NOTE: Put all metadata in pyproject.toml.
6# Set the environment variable `ONNX_PREVIEW_BUILD=1` to build the dev preview release.
7from __future__ import annotations8
9import contextlib10import datetime11import glob12import logging13import multiprocessing14import os15import platform16import shlex17import shutil18import subprocess19import sys20import sysconfig21import textwrap22from typing import ClassVar23
24import setuptools25import setuptools.command.build_ext26import setuptools.command.build_py27import setuptools.command.develop28
29TOP_DIR = os.path.realpath(os.path.dirname(__file__))30CMAKE_BUILD_DIR = os.path.join(TOP_DIR, ".setuptools-cmake-build")31
32WINDOWS = os.name == "nt"33
34CMAKE = shutil.which("cmake3") or shutil.which("cmake")35
36################################################################################
37# Global variables for controlling the build variant
38################################################################################
39
40# Default value is set to TRUE\1 to keep the settings same as the current ones.
41# However going forward the recommended way to is to set this to False\0
42ONNX_ML = os.getenv("ONNX_ML") != "0"43ONNX_VERIFY_PROTO3 = os.getenv("ONNX_VERIFY_PROTO3") == "1"44ONNX_NAMESPACE = os.getenv("ONNX_NAMESPACE", "onnx")45ONNX_BUILD_TESTS = os.getenv("ONNX_BUILD_TESTS") == "1"46ONNX_DISABLE_EXCEPTIONS = os.getenv("ONNX_DISABLE_EXCEPTIONS") == "1"47ONNX_DISABLE_STATIC_REGISTRATION = os.getenv("ONNX_DISABLE_STATIC_REGISTRATION") == "1"48ONNX_PREVIEW_BUILD = os.getenv("ONNX_PREVIEW_BUILD") == "1"49
50USE_MSVC_STATIC_RUNTIME = os.getenv("USE_MSVC_STATIC_RUNTIME", "0") == "1"51DEBUG = os.getenv("DEBUG", "0") == "1"52COVERAGE = os.getenv("COVERAGE", "0") == "1"53
54# Customize the wheel plat-name; sometimes useful for MacOS builds.
55# See https://github.com/onnx/onnx/pull/6117
56ONNX_WHEEL_PLATFORM_NAME = os.getenv("ONNX_WHEEL_PLATFORM_NAME")57
58################################################################################
59# Pre Check
60################################################################################
61
62assert CMAKE, "Could not find cmake in PATH"63
64################################################################################
65# Version
66################################################################################
67
68try:69_git_version = (70subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=TOP_DIR)71.decode("ascii")72.strip()73)74except (OSError, subprocess.CalledProcessError):75_git_version = ""76
77with open(os.path.join(TOP_DIR, "VERSION_NUMBER"), encoding="utf-8") as version_file:78_version = version_file.read().strip()79if ONNX_PREVIEW_BUILD:80# Create the dev build for weekly releases81todays_date = datetime.date.today().strftime("%Y%m%d")82_version += ".dev" + todays_date83VERSION_INFO = {"version": _version, "git_version": _git_version}84
85################################################################################
86# Utilities
87################################################################################
88
89
90@contextlib.contextmanager91def cd(path):92if not os.path.isabs(path):93raise RuntimeError(f"Can only cd to absolute path, got: {path}")94orig_path = os.getcwd()95os.chdir(path)96try:97yield98finally:99os.chdir(orig_path)100
101
102def get_ext_suffix():103return sysconfig.get_config_var("EXT_SUFFIX")104
105
106################################################################################
107# Customized commands
108################################################################################
109
110
111def create_version(directory: str):112"""Create version.py based on VERSION_INFO."""113version_file_path = os.path.join(directory, "onnx", "version.py")114os.makedirs(os.path.dirname(version_file_path), exist_ok=True)115
116with open(version_file_path, "w", encoding="utf-8") as f:117f.write(118textwrap.dedent(119f"""\120# This file is generated by setup.py. DO NOT EDIT!
121
122
123version = "{VERSION_INFO['version']}"124git_version = "{VERSION_INFO['git_version']}"125"""
126)127)128
129
130class CmakeBuild(setuptools.Command):131"""Compiles everything when `python setup.py build` is run using cmake.132
133Custom args can be passed to cmake by specifying the `CMAKE_ARGS`
134environment variable.
135
136The number of CPUs used by `make` can be specified by passing `-j<ncpus>`
137to `setup.py build`. By default all CPUs are used.
138"""
139
140user_options: ClassVar[list] = [141("jobs=", "j", "Specifies the number of jobs to use with make")142]143
144def initialize_options(self):145self.jobs = None146
147def finalize_options(self):148self.set_undefined_options("build", ("parallel", "jobs"))149if self.jobs is None and os.getenv("MAX_JOBS") is not None:150self.jobs = os.getenv("MAX_JOBS")151self.jobs = multiprocessing.cpu_count() if self.jobs is None else int(self.jobs)152
153def run(self):154os.makedirs(CMAKE_BUILD_DIR, exist_ok=True)155
156with cd(CMAKE_BUILD_DIR):157build_type = "Release"158# configure159cmake_args = [160CMAKE,161f"-DPYTHON_INCLUDE_DIR={sysconfig.get_path('include')}",162f"-DPYTHON_EXECUTABLE={sys.executable}",163"-DBUILD_ONNX_PYTHON=ON",164"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",165f"-DONNX_NAMESPACE={ONNX_NAMESPACE}",166f"-DPY_EXT_SUFFIX={get_ext_suffix() or ''}",167]168if COVERAGE:169cmake_args.append("-DONNX_COVERAGE=ON")170if COVERAGE or DEBUG:171# in order to get accurate coverage information, the172# build needs to turn off optimizations173build_type = "Debug"174cmake_args.append(f"-DCMAKE_BUILD_TYPE={build_type}")175if WINDOWS:176cmake_args.extend(177[178# we need to link with libpython on windows, so179# passing python version to window in order to180# find python in cmake181f"-DPY_VERSION={'{}.{}'.format(*sys.version_info[:2])}",182]183)184if USE_MSVC_STATIC_RUNTIME:185cmake_args.append("-DONNX_USE_MSVC_STATIC_RUNTIME=ON")186if platform.architecture()[0] == "64bit":187if "arm" in platform.machine().lower():188cmake_args.extend(["-A", "ARM64"])189else:190cmake_args.extend(["-A", "x64", "-T", "host=x64"])191else: # noqa: PLR5501192if "arm" in platform.machine().lower():193cmake_args.extend(["-A", "ARM"])194else:195cmake_args.extend(["-A", "Win32", "-T", "host=x86"])196if ONNX_ML:197cmake_args.append("-DONNX_ML=1")198if ONNX_VERIFY_PROTO3:199cmake_args.append("-DONNX_VERIFY_PROTO3=1")200if ONNX_BUILD_TESTS:201cmake_args.append("-DONNX_BUILD_TESTS=ON")202if ONNX_DISABLE_EXCEPTIONS:203cmake_args.append("-DONNX_DISABLE_EXCEPTIONS=ON")204if ONNX_DISABLE_STATIC_REGISTRATION:205cmake_args.append("-DONNX_DISABLE_STATIC_REGISTRATION=ON")206if "CMAKE_ARGS" in os.environ:207extra_cmake_args = shlex.split(os.environ["CMAKE_ARGS"])208# prevent crossfire with downstream scripts209del os.environ["CMAKE_ARGS"]210logging.info("Extra cmake args: %s", extra_cmake_args)211cmake_args.extend(extra_cmake_args)212cmake_args.append(TOP_DIR)213logging.info("Using cmake args: %s", cmake_args)214if "-DONNX_DISABLE_EXCEPTIONS=ON" in cmake_args:215raise RuntimeError(216"-DONNX_DISABLE_EXCEPTIONS=ON option is only available for c++ builds. Python binding require exceptions to be enabled."217)218subprocess.check_call(cmake_args)219
220build_args = [CMAKE, "--build", os.curdir]221if WINDOWS:222build_args.extend(["--config", build_type])223build_args.extend(["--", f"/maxcpucount:{self.jobs}"])224else:225build_args.extend(["--", "-j", str(self.jobs)])226subprocess.check_call(build_args)227
228
229class BuildPy(setuptools.command.build_py.build_py):230def run(self):231if self.editable_mode:232dst_dir = TOP_DIR233else:234dst_dir = self.build_lib235create_version(dst_dir)236return super().run()237
238
239class Develop(setuptools.command.develop.develop):240def run(self):241create_version(TOP_DIR)242return super().run()243
244
245class BuildExt(setuptools.command.build_ext.build_ext):246def run(self):247self.run_command("cmake_build")248return super().run()249
250def build_extensions(self):251# We override this method entirely because the actual building is done252# by cmake_build. Here we just copy the built extensions to the final253# destination.254build_lib = self.build_lib255extension_dst_dir = os.path.join(build_lib, "onnx")256os.makedirs(extension_dst_dir, exist_ok=True)257
258for ext in self.extensions:259fullname = self.get_ext_fullname(ext.name)260filename = os.path.basename(self.get_ext_filename(fullname))261
262if not WINDOWS:263lib_dir = CMAKE_BUILD_DIR264else:265# Windows compiled extensions are stored in Release/Debug subfolders266debug_lib_dir = os.path.join(CMAKE_BUILD_DIR, "Debug")267release_lib_dir = os.path.join(CMAKE_BUILD_DIR, "Release")268if os.path.exists(debug_lib_dir):269lib_dir = debug_lib_dir270elif os.path.exists(release_lib_dir):271lib_dir = release_lib_dir272src = os.path.join(lib_dir, filename)273dst = os.path.join(extension_dst_dir, filename)274self.copy_file(src, dst)275
276# Copy over the generated python files to build/source dir depending on editable mode277if self.editable_mode:278dst_dir = TOP_DIR279else:280dst_dir = build_lib281
282generated_py_files = glob.glob(os.path.join(CMAKE_BUILD_DIR, "onnx", "*.py"))283generated_pyi_files = glob.glob(os.path.join(CMAKE_BUILD_DIR, "onnx", "*.pyi"))284assert generated_py_files, "Bug: No generated python files found"285assert generated_pyi_files, "Bug: No generated python stubs found"286for src in (*generated_py_files, *generated_pyi_files):287dst = os.path.join(dst_dir, os.path.relpath(src, CMAKE_BUILD_DIR))288os.makedirs(os.path.dirname(dst), exist_ok=True)289self.copy_file(src, dst)290
291
292CMD_CLASS = {293"cmake_build": CmakeBuild,294"build_py": BuildPy,295"build_ext": BuildExt,296"develop": Develop,297}
298
299################################################################################
300# Extensions
301################################################################################
302
303EXT_MODULES = [setuptools.Extension(name="onnx.onnx_cpp2py_export", sources=[])]304
305
306################################################################################
307# Final
308################################################################################
309
310setuptools.setup(311ext_modules=EXT_MODULES,312cmdclass=CMD_CLASS,313version=VERSION_INFO["version"],314options=(315{"bdist_wheel": {"plat_name": ONNX_WHEEL_PLATFORM_NAME}}316if ONNX_WHEEL_PLATFORM_NAME is not None317else {}318),319)
320