Repository navigation
Expand file tree
/
Copy pathsetup.py
More file actions
172 lines (143 loc) · 5.7 KB
/
Copy pathsetup.py
File metadata and controls
172 lines (143 loc) · 5.7 KB
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
"""
Build driver for the lightusd PyPI wheel.
Flow:
1. Invoke CMake on the standalone `src/next` project (next-core), building
the `lightusd_next`, `tydra_next` and `lightusd_c` static libraries.
The legacy lightusd core is NOT built or linked into the Python wheel
(v1.0.0 next + tydra-next only, npm preview tag). Native
(`cmake -S .`) and WASM (`web/CMakeLists.txt` / `web/binding.cc` with
LIGHTUSD_WASM_PRODUCT=legacy/next/combined) still build the legacy path.
2. Compile the `src/python/py-*.c` sources into the `lightusd._core`
extension, linking those static archives.
Two build flavors from the same sources:
- Regular CPython: stable-ABI (abi3) extension with
Py_LIMITED_API=0x030A0000; the wheel is tagged cp310-abi3 and covers
CPython >= 3.10.
- Free-threaded CPython (Py_GIL_DISABLED, e.g. 3.14t): the limited API is
unavailable there, so a regular version-specific extension is built
(wheel tag cp314t-...). The module declares Py_mod_gil=Py_MOD_GIL_NOT_USED.
"""
from __future__ import annotations
import os
import pathlib
import platform
import shutil
import subprocess
import sysconfig
from setuptools import Extension, setup
from setuptools.command.build_ext import build_ext
ROOT = pathlib.Path(__file__).parent.resolve()
CMAKE_BUILD_DIR = ROOT / "build_py_ext_next"
PY_LIMITED_API = 0x030A0000 # CPython 3.10 floor for the abi3 wheel
# The stable ABI cannot be used on free-threaded CPython builds.
FREE_THREADED = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
USE_LIMITED = (not FREE_THREADED and
os.environ.get("LIGHTUSD_PY_LIMITED_API", "1") != "0")
def _cmake_configure_and_build() -> None:
CMAKE_BUILD_DIR.mkdir(parents=True, exist_ok=True)
cmake_args = [
"cmake",
"-S", str(ROOT / "src" / "next"),
"-B", str(CMAKE_BUILD_DIR),
"-DCMAKE_BUILD_TYPE=MinSizeRel",
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
"-DLIGHTUSD_NEXT_ENABLE_THREAD=ON",
"-DLIGHTUSD_NEXT_BUILD_TESTS=OFF",
"-DLIGHTUSD_NEXT_BUILD_PYTHON=OFF",
]
is_windows = platform.system() == "Windows"
# On Windows, prefer the native Visual Studio generator so CMake
# auto-locates MSVC without needing cl.exe on PATH. Elsewhere Ninja is
# strictly faster if available.
if not is_windows and shutil.which("ninja") is not None:
cmake_args.extend(["-G", "Ninja"])
if is_windows:
cmake_args.append("-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL")
extra = os.environ.get("LIGHTUSD_CMAKE_ARGS", "")
if extra:
cmake_args.extend(extra.split())
env = os.environ.copy()
subprocess.check_call(cmake_args, env=env)
build_args = [
"cmake", "--build", str(CMAKE_BUILD_DIR),
"--config", "MinSizeRel",
"--target", "lightusd_next",
"--target", "tydra_next",
"--target", "lightusd_c",
"--parallel", str(os.cpu_count() or 2),
]
subprocess.check_call(build_args, env=env)
def _find_static_lib(stem: str) -> pathlib.Path:
"""Locate a static library built by CMake with variable naming across
platforms and generator types (multi-config vs single-config)."""
candidates = [
CMAKE_BUILD_DIR / f"lib{stem}.a",
CMAKE_BUILD_DIR / f"{stem}.lib",
CMAKE_BUILD_DIR / "MinSizeRel" / f"{stem}.lib",
]
candidates += list(CMAKE_BUILD_DIR.rglob(f"lib{stem}.a"))
candidates += list(CMAKE_BUILD_DIR.rglob(f"{stem}.lib"))
for c in candidates:
if c.is_file():
return c
raise FileNotFoundError(
f"Could not locate static library for target '{stem}' under "
f"{CMAKE_BUILD_DIR}. Candidates tried: {candidates}")
class CMakeBuildExt(build_ext):
"""Drive CMake to produce static libs, then compile the C extension."""
def run(self) -> None:
_cmake_configure_and_build()
# Link order matters for static archives on POSIX: dependents first.
c_api = _find_static_lib("lightusd_c")
tydra = _find_static_lib("tydra_next")
core = _find_static_lib("lightusd_next")
for ext in self.extensions:
ext.extra_objects = [str(c_api), str(tydra), str(core)] + list(
ext.extra_objects)
super().run()
extra_compile_args = []
extra_link_args = []
if platform.system() == "Linux":
extra_compile_args += ["-O2", "-ffunction-sections", "-fdata-sections"]
extra_link_args += ["-lstdc++", "-lm", "-lpthread",
"-Wl,--gc-sections", "-Wl,-s"]
elif platform.system() == "Darwin":
extra_compile_args += ["-O2"]
extra_link_args += ["-lc++", "-Wl,-dead_strip", "-Wl,-x"]
elif platform.system() == "Windows":
# Explicit C standard: the .c sources use C99 compound literals and
# designated initializers. Linux/Darwin get an implicit C99-superset
# default from GCC/Clang, but MSVC needs this spelled out. This repo's
# CI/build already targets VS2022, which has supported /std:c17 since
# 16.8.
extra_compile_args += ["/O2", "/std:c17"]
define_macros = []
if USE_LIMITED:
define_macros.append(("Py_LIMITED_API", hex(PY_LIMITED_API)))
ext = Extension(
name="lightusd._core",
sources=[
"src/python/py-module.c",
"src/python/py-array.c",
"src/python/py-prim.c",
"src/python/py-render.c",
"src/python/py-stage.c",
],
include_dirs=[
"src/c-api",
"src/python",
],
define_macros=define_macros,
py_limited_api=USE_LIMITED,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
language="c",
)
options = {}
if USE_LIMITED:
options["bdist_wheel"] = {"py_limited_api": "cp310"}
setup(
ext_modules=[ext],
cmdclass={"build_ext": CMakeBuildExt},
options=options,
)