Skip to content

Commit 32caaba

Browse files
laramielcopybara-github
authored andcommitted
local_python_runtime needs to pass defines like Py_GIL_DISABLED
PiperOrigin-RevId: 831607733 Change-Id: Ic205d1b91ff932210d1feb2cb9f7e1f0e5de6c09
1 parent 448e84f commit 32caaba

File tree

4 files changed

+148
-118
lines changed

4 files changed

+148
-118
lines changed

bazel/repo_rules/get_local_runtime_info.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,15 @@ def _get_python_library_info(base_executable) -> dict[str, Any]:
154154
else:
155155
version = f"{sys.version_info.major}.{sys.version_info.minor}"
156156

157+
defines = []
158+
if config_vars.get("Py_GIL_DISABLED", "0") == "1":
159+
defines.append("Py_GIL_DISABLED")
160+
161+
# Avoid automatically linking the libraries on windows via pydefine.h
162+
# pragma comment(lib ...)
163+
if _IS_WINDOWS:
164+
defines.append("Py_NO_LINK_LIB")
165+
157166
# sys.abiflags may not exist, but it still may be set in the config.
158167
abi_flags = _get_abi_flags(config_vars.get)
159168

@@ -243,6 +252,7 @@ def _unique_basenames(inputs: dict[str, None]) -> list[str]:
243252
"abi_flags": abi_flags,
244253
"shlib_suffix": ".dylib" if _IS_DARWIN else "",
245254
"additional_dlls": dlls,
255+
"defines": defines,
246256
}
247257

248258

bazel/repo_rules/local_python_runtime.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ define_local_runtime_toolchain_impl(
6666
interpreter_path = "{interpreter_path}",
6767
interface_library = {interface_library},
6868
libraries = {libraries},
69+
defines = {defines},
6970
abi3_interface_library = {abi3_interface_library},
7071
abi3_libraries = {abi3_libraries},
7172
additional_dlls = {additional_dlls},
@@ -83,6 +84,7 @@ def _expand_incompatible_template():
8384
interpreter_path = "/incompatible",
8485
interface_library = "None",
8586
libraries = "[]",
87+
defines = "[]",
8688
abi3_interface_library = "None",
8789
abi3_libraries = "[]",
8890
additional_dlls = "[]",
@@ -232,6 +234,7 @@ def _local_python_repo_impl(rctx):
232234
interpreter_path = repo_utils.norm_path(interpreter_path),
233235
interface_library = repr(interface_library),
234236
libraries = repr(libraries),
237+
defines = repr(info["defines"]),
235238
abi3_interface_library = repr(abi3_interface_library),
236239
abi3_libraries = repr(abi3_libraries),
237240
additional_dlls = repr(additional_dlls),

bazel/repo_rules/local_runtime_repo_setup.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def define_local_runtime_toolchain_impl(
3838
interpreter_path,
3939
interface_library,
4040
libraries,
41+
defines,
4142
abi3_interface_library,
4243
abi3_libraries,
4344
additional_dlls):
@@ -67,6 +68,7 @@ def define_local_runtime_toolchain_impl(
6768
e.g. "lib/python312.lib"
6869
libraries: `list[str]` Path[s] to the python libraries.
6970
e.g. ["lib/python312.dll"] or ["lib/python312.so"]
71+
defines: `list[str]` List of additional defines.
7072
abi3_interface_library: `str` Path to the interface library.
7173
e.g. "lib/python3.lib"
7274
abi3_libraries: `list[str]` Path[s] to the python libraries.
@@ -109,6 +111,7 @@ def define_local_runtime_toolchain_impl(
109111
name = "python_headers_abi3",
110112
hdrs = [":includes"],
111113
includes = ["include"],
114+
defines = defines, # NOTE: Users should define Py_LIMITED_API=3
112115
deps = select({
113116
"@bazel_tools//src/conditions:windows": [":abi3_interface"],
114117
"//conditions:default": [],
@@ -119,6 +122,7 @@ def define_local_runtime_toolchain_impl(
119122
name = "python_headers",
120123
hdrs = [":includes"],
121124
includes = ["include"],
125+
defines = defines,
122126
deps = select({
123127
"@bazel_tools//src/conditions:windows": [":interface"],
124128
"//conditions:default": [],
@@ -129,12 +133,14 @@ def define_local_runtime_toolchain_impl(
129133
cc_library(
130134
name = "libpython_abi3",
131135
hdrs = [":includes"],
136+
defines = defines, # NOTE: Users should define Py_LIMITED_API=3
132137
srcs = abi3_libraries + additional_dlls,
133138
)
134139

135140
cc_library(
136141
name = "libpython",
137142
hdrs = [":includes"],
143+
defines = defines,
138144
srcs = libraries + additional_dlls,
139145
)
140146

setup.py

Lines changed: 129 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -250,137 +250,148 @@ class BuildExtCommand(setuptools.command.build_ext.build_ext):
250250
"""Overrides default build_ext command to invoke bazel."""
251251

252252
def run(self):
253-
if not self.dry_run:
254-
ext = self.extensions[0]
255-
ext_full_path = self.get_ext_fullpath(ext.name)
253+
ext = self.extensions[0]
254+
ext_full_path = self.get_ext_fullpath(ext.name)
256255

257-
prebuilt_path = os.getenv('TENSORSTORE_PREBUILT_DIR')
258-
if not prebuilt_path:
256+
prebuilt_path = os.getenv('TENSORSTORE_PREBUILT_DIR')
257+
if not prebuilt_path:
259258

260-
env = os.environ.copy()
259+
env = os.environ.copy()
261260

262-
# Bazel cache includes PATH; attempt to remove the pip build-env
263-
# from the PATH as bazel is already hermetic to improve cache use.
264-
if 'PATH' in env:
265-
env['PATH'] = _normalize_path(env['PATH'])
261+
# Bazel cache includes PATH; attempt to remove the pip build-env
262+
# from the PATH as bazel is already hermetic to improve cache use.
263+
if 'PATH' in env:
264+
env['PATH'] = _normalize_path(env['PATH'])
266265

267-
# Ensure python_configure.bzl finds the correct Python version.
268-
env['PYTHON_BIN_PATH'] = sys.executable
266+
# Ensure python_configure.bzl finds the correct Python version.
267+
env['PYTHON_BIN_PATH'] = sys.executable
269268

270-
bazelisk = os.getenv('TENSORSTORE_BAZELISK', 'bazelisk.py')
271-
# Controlled via `setup.py build_ext --debug` flag.
272-
default_compilation_mode = 'dbg' if self.debug else 'opt'
273-
startup_options = shlex.split(
274-
os.getenv('TENSORSTORE_BAZEL_STARTUP_OPTIONS', '')
275-
)
276-
build_options = shlex.split(
277-
os.getenv('TENSORSTORE_BAZEL_BUILD_OPTIONS', '')
278-
)
269+
bazelisk = os.getenv('TENSORSTORE_BAZELISK', 'bazelisk.py')
270+
# Controlled via `setup.py build_ext --debug` flag.
271+
default_compilation_mode = 'dbg' if self.debug else 'opt'
272+
startup_options = shlex.split(
273+
os.getenv('TENSORSTORE_BAZEL_STARTUP_OPTIONS', '')
274+
)
275+
build_options = shlex.split(
276+
os.getenv('TENSORSTORE_BAZEL_BUILD_OPTIONS', '')
277+
)
279278

280-
# Build with a specific compilation mode.
281-
# When in opt mode also set -O3 optimizations to override bazel -O2.
282-
compilation_mode = os.getenv(
283-
'TENSORSTORE_BAZEL_COMPILATION_MODE', default_compilation_mode
284-
)
285-
build_flags = ['build', '-c', compilation_mode]
286-
if compilation_mode == 'opt':
287-
if 'win32' in sys.platform:
288-
# Assumes MSVC compiler.
289-
build_flags.append('--copt=/Ox')
290-
else:
291-
build_flags.append('--copt=-O3')
292-
293-
version_stamp = self.distribution.get_version()
294-
if version_stamp:
295-
build_flags.append(
296-
'--//tensorstore/internal/version=%s' % version_stamp
297-
)
298-
299-
build_command = (
300-
[sys.executable, '-u', bazelisk]
301-
+ startup_options
302-
+ build_flags
303-
+ [
304-
'//python/tensorstore:_tensorstore__shared_objects',
305-
'--verbose_failures',
306-
# Bazel does not seem to download these files by default when
307-
# using remote caching.
308-
r'--remote_download_regex=.*/(_tensorstore\.(so|pyd))',
309-
]
310-
+ build_options
311-
)
312-
if 'darwin' in sys.platform:
313-
# Note: Bazel does not use the MACOSX_DEPLOYMENT_TARGET environment
314-
# variable.
315-
build_command += ['--macos_minimum_os=%s' % _macos_deployment_target]
316-
# Support cross-compilation on macOS
317-
# https://github.com/pypa/cibuildwheel/discussions/997#discussioncomment-2045760
318-
darwin_cpus = [
319-
x for x in os.getenv('ARCHFLAGS', '').split() if x != '-arch'
320-
]
321-
# cibuildwheel sets `ARCHFLAGS` to one of:
322-
# '-arch x86_64'
323-
# '-arch arm64'
324-
# '-arch arm64 -arch x86_64'
325-
if darwin_cpus:
326-
if len(darwin_cpus) > 1:
327-
raise ValueError(
328-
'Fat/universal %r build not supported' % (darwin_cpus,)
329-
)
330-
darwin_cpu = darwin_cpus[0]
331-
build_command += [
332-
f'--cpu=darwin_{darwin_cpu}',
333-
f'--macos_cpus={darwin_cpu}',
334-
]
335-
if sys.platform == 'win32':
336-
# Disable the constexpr mutex constructor which is incompatible with
337-
# older versions of msvcp140.dll.
338-
#
339-
# https://developercommunity.visualstudio.com/t/Access-violation-with-std::mutex::lock-a/10664660#T-N10668856
340-
build_command += ['--copt=/D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR']
341-
342-
# Disable newer exception handling from Visual Studio 2019, since it
343-
# requires a newer C++ runtime than shipped with Python.
344-
#
345-
# https://cibuildwheel.readthedocs.io/en/stable/faq/#importerror-dll-load-failed-the-specific-module-could-not-be-found-error-on-windows
346-
build_command += ['--copt=/d2FH4-']
279+
# Build with a specific compilation mode.
280+
# When in opt mode also set -O3 optimizations to override bazel -O2.
281+
compilation_mode = os.getenv(
282+
'TENSORSTORE_BAZEL_COMPILATION_MODE', default_compilation_mode
283+
)
284+
build_flags = ['build', '-c', compilation_mode]
285+
if compilation_mode == 'opt':
286+
if 'win32' in sys.platform:
287+
# Assumes MSVC compiler.
288+
build_flags.append('--copt=/Ox')
347289
else:
348-
# Build with hidden visibility for more efficient code generation.
349-
# Note that this also hides most symbols, but ultimately has no effect
350-
# on symbol visibility because a separate linker option is already
351-
# used to hide all extraneous symbols anyway.
352-
build_command += ['--copt=-fvisibility=hidden']
290+
build_flags.append('--copt=-O3')
353291

354-
print(f'Executing {shlex.join(build_command)} with env {env}')
355-
subprocess.check_call(build_command, env=env)
356-
suffix = '.pyd' if os.name == 'nt' else '.so'
357-
built_ext_path = os.path.join(
358-
'bazel-bin/python/tensorstore/_tensorstore' + suffix
292+
version_stamp = self.distribution.get_version()
293+
if version_stamp:
294+
build_flags.append(
295+
'--//tensorstore/internal/version=%s' % version_stamp
359296
)
360-
else:
361-
# If `TENSORSTORE_PREBUILT_DIR` is set, the extension module is assumed
362-
# to have already been built a prior call to `build_ext -b
363-
# $TENSORSTORE_PREBUILT_DIR`.
297+
298+
if sysconfig.get_config_var('Py_GIL_DISABLED') == '1':
299+
build_flags.append(
300+
'--@rules_python//python/config_settings:py_freethreaded=yes'
301+
)
302+
303+
build_command = (
304+
[sys.executable, '-u', bazelisk]
305+
+ startup_options
306+
+ build_flags
307+
+ [
308+
'//python/tensorstore:_tensorstore__shared_objects',
309+
'--verbose_failures',
310+
# Bazel does not seem to download these files by default when
311+
# using remote caching.
312+
r'--remote_download_regex=.*/(_tensorstore\.(so|pyd))',
313+
]
314+
+ build_options
315+
)
316+
if 'darwin' in sys.platform:
317+
# Note: Bazel does not use the MACOSX_DEPLOYMENT_TARGET environment
318+
# variable.
319+
build_command += ['--macos_minimum_os=%s' % _macos_deployment_target]
320+
# Support cross-compilation on macOS
321+
# https://github.com/pypa/cibuildwheel/discussions/997#discussioncomment-2045760
322+
darwin_cpus = [
323+
x for x in os.getenv('ARCHFLAGS', '').split() if x != '-arch'
324+
]
325+
# cibuildwheel sets `ARCHFLAGS` to one of:
326+
# '-arch x86_64'
327+
# '-arch arm64'
328+
# '-arch arm64 -arch x86_64'
329+
if darwin_cpus:
330+
if len(darwin_cpus) > 1:
331+
raise ValueError(
332+
'Fat/universal %r build not supported' % (darwin_cpus,)
333+
)
334+
darwin_cpu = darwin_cpus[0]
335+
build_command += [
336+
f'--cpu=darwin_{darwin_cpu}',
337+
f'--macos_cpus={darwin_cpu}',
338+
]
339+
if sys.platform == 'win32':
340+
# Disable the constexpr mutex constructor which is incompatible with
341+
# older versions of msvcp140.dll.
364342
#
365-
# This is used in conjunction with cibuildwheel to first perform an
366-
# in-tree build of the extension module in order to take advantage of
367-
# Bazel caching:
343+
# https://developercommunity.visualstudio.com/t/Access-violation-with-std::mutex::lock-a/10664660#T-N10668856
344+
build_command += ['--copt=/D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR']
345+
346+
# Disable newer exception handling from Visual Studio 2019, since it
347+
# requires a newer C++ runtime than shipped with Python.
368348
#
369-
# https://github.com/pypa/pip/pull/9091
370-
# https://github.com/joerick/cibuildwheel/issues/486
371-
built_ext_path = os.path.join(
372-
prebuilt_path, 'tensorstore', os.path.basename(ext_full_path)
373-
)
349+
# https://cibuildwheel.readthedocs.io/en/stable/faq/#importerror-dll-load-failed-the-specific-module-could-not-be-found-error-on-windows
350+
build_command += ['--copt=/d2FH4-']
351+
else:
352+
# Build with hidden visibility for more efficient code generation.
353+
# Note that this also hides most symbols, but ultimately has no effect
354+
# on symbol visibility because a separate linker option is already
355+
# used to hide all extraneous symbols anyway.
356+
build_command += ['--copt=-fvisibility=hidden']
374357

375-
os.makedirs(os.path.dirname(ext_full_path), exist_ok=True)
376-
print(
377-
'Copying extension %s -> %s'
378-
% (
379-
built_ext_path,
380-
ext_full_path,
381-
)
358+
print(f'Executing {shlex.join(build_command)} with env {env}')
359+
360+
if not self.dry_run:
361+
subprocess.check_call(build_command, env=env)
362+
363+
suffix = '.pyd' if os.name == 'nt' else '.so'
364+
built_ext_path = os.path.join(
365+
'bazel-bin/python/tensorstore/_tensorstore' + suffix
366+
)
367+
else:
368+
# If `TENSORSTORE_PREBUILT_DIR` is set, the extension module is assumed
369+
# to have already been built a prior call to `build_ext -b
370+
# $TENSORSTORE_PREBUILT_DIR`.
371+
#
372+
# This is used in conjunction with cibuildwheel to first perform an
373+
# in-tree build of the extension module in order to take advantage of
374+
# Bazel caching:
375+
#
376+
# https://github.com/pypa/pip/pull/9091
377+
# https://github.com/joerick/cibuildwheel/issues/486
378+
built_ext_path = os.path.join(
379+
prebuilt_path, 'tensorstore', os.path.basename(ext_full_path)
382380
)
383-
shutil.copyfile(built_ext_path, ext_full_path)
381+
382+
if self.dry_run:
383+
print('Dry run, skipping build')
384+
return
385+
386+
os.makedirs(os.path.dirname(ext_full_path), exist_ok=True)
387+
print(
388+
'Copying extension %s -> %s'
389+
% (
390+
built_ext_path,
391+
ext_full_path,
392+
)
393+
)
394+
shutil.copyfile(built_ext_path, ext_full_path)
384395

385396

386397
class InstallCommand(setuptools.command.install.install):

0 commit comments

Comments
 (0)