|
| 1 | +# Copyright (c) 2016 The Pybind Development Team, All rights reserved. |
| 2 | +# |
| 3 | +# Redistribution and use in source and binary forms, with or without |
| 4 | +# modification, are permitted provided that the following conditions are met: |
| 5 | +# |
| 6 | +# 1. Redistributions of source code must retain the above copyright notice, this |
| 7 | +# list of conditions and the following disclaimer. |
| 8 | +# |
| 9 | +# 2. Redistributions in binary form must reproduce the above copyright notice, |
| 10 | +# this list of conditions and the following disclaimer in the documentation |
| 11 | +# and/or other materials provided with the distribution. |
| 12 | +# |
| 13 | +# 3. Neither the name of the copyright holder nor the names of its contributors |
| 14 | +# may be used to endorse or promote products derived from this software |
| 15 | +# without specific prior written permission. |
| 16 | +# |
| 17 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 18 | +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 19 | +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 20 | +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| 21 | +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 23 | +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| 24 | +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 25 | +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 | +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | +# |
| 28 | +# You are under no obligation whatsoever to provide any bug fixes, patches, or |
| 29 | +# upgrades to the features, functionality or performance of the source code |
| 30 | +# ("Enhancements") to anyone; however, if you choose to make your Enhancements |
| 31 | +# available either publicly, or directly to the author of this software, without |
| 32 | +# imposing a separate written license agreement for such Enhancements, then you |
| 33 | +# hereby grant the following license: a non-exclusive, royalty-free perpetual |
| 34 | +# license to install, use, modify, prepare derivative works, incorporate into |
| 35 | +# other computer software, distribute, and sublicense such enhancements or |
| 36 | +# derivative works thereof, in binary and source code form. |
| 37 | + |
| 38 | +import os |
| 39 | +import re |
| 40 | +import subprocess |
| 41 | +import sys |
| 42 | + |
| 43 | +from setuptools import Extension, setup |
| 44 | +from setuptools.command.build_ext import build_ext |
| 45 | + |
| 46 | +# Convert distutils Windows platform specifiers to CMake -A arguments |
| 47 | +PLAT_TO_CMAKE = { |
| 48 | + "win32": "Win32", |
| 49 | + "win-amd64": "x64", |
| 50 | + "win-arm32": "ARM", |
| 51 | + "win-arm64": "ARM64", |
| 52 | +} |
| 53 | + |
| 54 | + |
| 55 | +# A CMakeExtension needs a sourcedir instead of a file list. |
| 56 | +# The name must be the _single_ output extension from the CMake build. |
| 57 | +# If you need multiple extensions, see scikit-build. |
| 58 | +class CMakeExtension(Extension): |
| 59 | + def __init__(self, name, sourcedir=""): |
| 60 | + Extension.__init__(self, name, sources=[]) |
| 61 | + self.sourcedir = os.path.abspath(sourcedir) |
| 62 | + |
| 63 | + |
| 64 | +class CMakeBuild(build_ext): |
| 65 | + def build_extension(self, ext): |
| 66 | + extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) |
| 67 | + |
| 68 | + # required for auto-detection & inclusion of auxiliary "native" libs |
| 69 | + if not extdir.endswith(os.path.sep): |
| 70 | + extdir += os.path.sep |
| 71 | + |
| 72 | + debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug |
| 73 | + cfg = "Debug" if debug else "Release" |
| 74 | + |
| 75 | + # CMake lets you override the generator - we need to check this. |
| 76 | + # Can be set with Conda-Build, for example. |
| 77 | + cmake_generator = os.environ.get("CMAKE_GENERATOR", "") |
| 78 | + |
| 79 | + # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON |
| 80 | + # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code |
| 81 | + # from Python. |
| 82 | + cmake_args = [ |
| 83 | + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}", |
| 84 | + f"-DPYTHON_EXECUTABLE={sys.executable}", |
| 85 | + f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm |
| 86 | + ] |
| 87 | + build_args = [] |
| 88 | + # Adding CMake arguments set as environment variable |
| 89 | + # (needed e.g. to build for ARM OSx on conda-forge) |
| 90 | + if "CMAKE_ARGS" in os.environ: |
| 91 | + cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item] |
| 92 | + |
| 93 | + # In this example, we pass in the version to C++. You might not need to. |
| 94 | + cmake_args += [f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}"] |
| 95 | + |
| 96 | + if self.compiler.compiler_type != "msvc": |
| 97 | + # Using Ninja-build since it a) is available as a wheel and b) |
| 98 | + # multithreads automatically. MSVC would require all variables be |
| 99 | + # exported for Ninja to pick it up, which is a little tricky to do. |
| 100 | + # Users can override the generator with CMAKE_GENERATOR in CMake |
| 101 | + # 3.15+. |
| 102 | + if not cmake_generator or cmake_generator == "Ninja": |
| 103 | + try: |
| 104 | + import ninja # noqa: F401 |
| 105 | + |
| 106 | + ninja_executable_path = os.path.join(ninja.BIN_DIR, "ninja") |
| 107 | + cmake_args += [ |
| 108 | + "-GNinja", |
| 109 | + f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}", |
| 110 | + ] |
| 111 | + except ImportError: |
| 112 | + pass |
| 113 | + |
| 114 | + else: |
| 115 | + |
| 116 | + # Single config generators are handled "normally" |
| 117 | + single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) |
| 118 | + |
| 119 | + # CMake allows an arch-in-generator style for backward compatibility |
| 120 | + contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) |
| 121 | + |
| 122 | + # Specify the arch if using MSVC generator, but only if it doesn't |
| 123 | + # contain a backward-compatibility arch spec already in the |
| 124 | + # generator name. |
| 125 | + if not single_config and not contains_arch: |
| 126 | + cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] |
| 127 | + |
| 128 | + # Multi-config generators have a different way to specify configs |
| 129 | + if not single_config: |
| 130 | + cmake_args += [ |
| 131 | + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}" |
| 132 | + ] |
| 133 | + build_args += ["--config", cfg] |
| 134 | + |
| 135 | + if sys.platform.startswith("darwin"): |
| 136 | + # Cross-compile support for macOS - respect ARCHFLAGS if set |
| 137 | + archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) |
| 138 | + if archs: |
| 139 | + cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] |
| 140 | + |
| 141 | + # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level |
| 142 | + # across all generators. |
| 143 | + if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: |
| 144 | + # self.parallel is a Python 3 only way to set parallel jobs by hand |
| 145 | + # using -j in the build_ext call, not supported by pip or PyPA-build. |
| 146 | + if hasattr(self, "parallel") and self.parallel: |
| 147 | + # CMake 3.12+ only. |
| 148 | + build_args += [f"-j{self.parallel}"] |
| 149 | + |
| 150 | + build_temp = os.path.join(self.build_temp, ext.name) |
| 151 | + if not os.path.exists(build_temp): |
| 152 | + os.makedirs(build_temp) |
| 153 | + |
| 154 | + subprocess.check_call(["cmake", ext.sourcedir] + cmake_args, cwd=build_temp) |
| 155 | + subprocess.check_call(["cmake", "--build", "."] + build_args, cwd=build_temp) |
| 156 | + |
| 157 | + |
| 158 | +# The information here can also be placed in setup.cfg - better separation of |
| 159 | +# logic and declaration, and simpler if you include description/version in a file. |
| 160 | +setup( |
| 161 | + name="pytraversal", |
| 162 | + version="1.1", |
| 163 | + author="Christoph Rist", |
| 164 | + |
| 165 | + description="python bindings for voxel traversal", |
| 166 | + long_description="", |
| 167 | + ext_modules=[CMakeExtension("pytraversal")], |
| 168 | + cmdclass={"build_ext": CMakeBuild}, |
| 169 | + zip_safe=False, |
| 170 | + extras_require={"test": ["pytest>=6.0"]}, |
| 171 | + python_requires=">=3.6", |
| 172 | +) |
0 commit comments