Spaces:
Sleeping
Sleeping
File size: 6,611 Bytes
66c9c8a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | import argparse
import os
import shutil
import pathlib
import platform
from typing import NamedTuple
import setuptools
from wheel.bdist_wheel import bdist_wheel
# Parse --build-option arguments meant for the bdist_wheel command. We have to parse these
# ourselves because when bdist_wheel runs it's too late to select a subset of libraries for package_data.
parser = argparse.ArgumentParser()
parser.add_argument("command")
parser.add_argument(
"--platform", "-P", type=str, default="", help="Wheel platform: windows|linux|macos-x86_64|aarch64|universal"
)
args = parser.parse_known_args()[0]
# return a canonical machine architecture string
# - "x86_64" for x86-64, aka. AMD64, aka. x64
# - "aarch64" for AArch64, aka. ARM64
def machine_architecture() -> str:
machine = platform.machine()
if machine == "x86_64" or machine == "AMD64":
return "x86_64"
if machine == "aarch64" or machine == "arm64":
return "aarch64"
raise RuntimeError(f"Unrecognized machine architecture {machine}")
class Platform(NamedTuple):
os: str
arch: str
fancy_name: str
extension: str
tag: str
def name(self) -> str:
return self.os + "-" + self.arch
platforms = [
Platform("windows", "x86_64", "Windows x86-64", ".dll", "win_amd64"),
Platform("linux", "x86_64", "Linux x86-64", ".so", "manylinux2014_x86_64"),
Platform("linux", "aarch64", "Linux AArch64", ".so", "manylinux2014_aarch64"),
Platform("macos", "universal", "macOS universal", ".dylib", "macosx_10_13_universal2"),
]
class Library(NamedTuple):
file: str
directory: str
platform: Platform
# Enumerate warp/bin libraries
def detect_warp_libraries():
detected_libraries = set()
warp_bin = pathlib.Path("warp/bin")
for file in warp_bin.rglob("*.*"):
for p in platforms:
if os.path.splitext(file.name)[1] == p.extension:
# If this is a local build, assume we want a wheel for this machine's architecture
if file.parent.name == "bin" and (p.arch == machine_architecture() or p.arch == "universal"):
detected_libraries.add(Library(file.name, "bin/", p))
else:
# Excpect libraries to be in a subdirectory named after the wheel platform
platform_name = p.name()
if file.parent.name == platform_name:
detected_libraries.add(Library(file.name, "bin/" + platform_name + "/", p))
if len(detected_libraries) == 0:
raise Exception("No libraries found in warp/bin. Please run build_lib.py first.")
return detected_libraries
detected_libraries = detect_warp_libraries()
detected_platforms = set([lib.platform for lib in detected_libraries])
wheel_platform = None # The one platform for which we're building a wheel
if args.command == "bdist_wheel":
if args.platform != "":
for p in platforms:
if args.platform == p.name():
wheel_platform = p
print(f"Platform argument specified for building {p.fancy_name} wheel")
break
if wheel_platform is None:
print(f"Platform argument '{args.platform}' not recognized")
elif wheel_platform not in detected_platforms:
print(f"No libraries found for {wheel_platform.fancy_name}")
print("Falling back to auto-detection")
wheel_platform = None
if wheel_platform is None:
if len(detected_platforms) > 1:
print("Libraries for multiple platforms were detected. Picking the first one.")
print(
"Run `python -m build --wheel -C--build-option=-P[windows|linux|macos]-[x86_64|aarch64|universal]` to select a specific one."
)
wheel_platform = next(iter(detected_platforms))
print("Creating Warp wheel for " + wheel_platform.fancy_name)
# Binary wheel distribution builds assume that the platform you're building on will be the platform
# of the package. This class overrides the platform tag.
# https://packaging.python.org/en/latest/specifications/platform-compatibility-tags
class WarpBDistWheel(bdist_wheel):
# Even though we parse the platform argument ourselves, we need to declare it here as well so
# setuptools.Command can validate the command line options.
user_options = bdist_wheel.user_options + [
("platform=", "P", "Wheel platform: windows|linux|macos-x86_64|aarch64|universal"),
]
def initialize_options(self):
super().initialize_options()
self.platform = ""
def get_tag(self):
if wheel_platform is not None:
# The wheel's complete tag format is {python tag}-{abi tag}-{platform tag}.
return "py3", "none", wheel_platform.tag
else:
# The target platform was not overridden. Fall back to base class behavior.
return bdist_wheel.get_tag(self)
def run(self):
super().run()
# Clean up so we can re-invoke `py -m build --wheel -C--build-option=--platform=...`
# See https://github.com/pypa/setuptools/issues/1871 for details.
shutil.rmtree("./build", ignore_errors=True)
shutil.rmtree("./warp_lang.egg-info", ignore_errors=True)
# Distributions are identified as non-pure (i.e. containing non-Python code, or binaries) if the
# setuptools.setup() `ext_modules` parameter is not empty, but this assumes building extension
# modules from source through the Python build. This class provides an override for prebuilt binaries:
class BinaryDistribution(setuptools.Distribution):
def has_ext_modules(self):
return True
def get_warp_libraries(platform):
libraries = []
for library in detected_libraries:
if library.platform == platform:
src = "warp/" + library.directory + library.file
dst = "warp/bin/" + library.file
if src != dst:
shutil.copyfile(src, dst)
libraries.append("bin/" + library.file)
return libraries
if wheel_platform is not None:
warp_binary_libraries = get_warp_libraries(wheel_platform)
else:
warp_binary_libraries = [] # Not needed during egg_info command
setuptools.setup(
package_data={
"": [
"native/*.cpp",
"native/*.cu",
"native/*.h",
"native/clang/*.cpp",
"native/nanovdb/*.h",
"tests/assets/*",
]
+ warp_binary_libraries,
},
distclass=BinaryDistribution,
cmdclass={
"bdist_wheel": WarpBDistWheel,
},
)
|