Skip to content

Commit 660adf7

Browse files
committed
fix(macos): Added sysconfig-based Python link flags for sdist builds
Pass per-package LIBS/LDFLAGS env overrides into pip wheel so dbus-python can link against the active CPython on macOS CI.
1 parent c08dd38 commit 660adf7

4 files changed

Lines changed: 67 additions & 1 deletion

File tree

_helper_functions.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
#
66
from __future__ import annotations
77

8+
import os
89
import platform
910
import re
1011
import sys
12+
import sysconfig
1113

1214
from colorama import Fore
1315
from colorama import Style
16+
from packaging.requirements import InvalidRequirement
1417
from packaging.requirements import Requirement
1518
from packaging.utils import InvalidWheelFilename
1619
from packaging.utils import canonicalize_name
@@ -107,6 +110,52 @@ def get_no_binary_args(requirement_name: str) -> list:
107110
return []
108111

109112

113+
def get_pip_wheel_env_overrides(requirement_line: str) -> dict[str, str]:
114+
"""Per-package environment overrides for `pip wheel` builds.
115+
116+
Keep this narrowly scoped: used for CI-only build quirks where upstream sdists expect platform-specific
117+
Python link flags.
118+
"""
119+
try:
120+
req = Requirement(str(requirement_line).strip())
121+
except InvalidRequirement:
122+
return {}
123+
124+
# dbus-python on macOS: its autoconf configure can fail to link a test program against CPython.
125+
# Provide explicit LIBS/LDFLAGS derived from sysconfig so the build can locate the active Python library
126+
# regardless of whether Python is a framework build or a shared library build.
127+
if canonicalize_name(req.name) == canonicalize_name("dbus-python") and platform.system() == "Darwin":
128+
libdir = sysconfig.get_config_var("LIBDIR") or ""
129+
ldlibrary = sysconfig.get_config_var("LDLIBRARY") or "" # e.g. libpython3.11.dylib
130+
131+
# Prefer an explicit absolute library path when available; it is the most robust across layouts.
132+
libs_fragment = ""
133+
if libdir and ldlibrary:
134+
candidate = os.path.join(libdir, ldlibrary)
135+
if os.path.exists(candidate):
136+
libs_fragment = candidate
137+
138+
# Fallback to -L/-l if we can't find the actual library file.
139+
if not libs_fragment:
140+
maj, min = sys.version_info[:2]
141+
libs_fragment = (f"-L{libdir} " if libdir else "") + f"-lpython{maj}.{min}"
142+
143+
# Append to any existing flags, don't overwrite.
144+
existing_libs = os.environ.get("LIBS", "").strip()
145+
existing_ldflags = os.environ.get("LDFLAGS", "").strip()
146+
147+
new_libs = (libs_fragment + (" " + existing_libs if existing_libs else "")).strip()
148+
new_ldflags = existing_ldflags
149+
if libdir:
150+
rpath_flag = f"-Wl,-rpath,{libdir}"
151+
if rpath_flag not in new_ldflags:
152+
new_ldflags = (rpath_flag + (" " + new_ldflags if new_ldflags else "")).strip()
153+
154+
return {"LIBS": new_libs, "LDFLAGS": new_ldflags} if (new_libs or new_ldflags) else {}
155+
156+
return {}
157+
158+
110159
def _safe_text_for_stdout(text: str) -> str:
111160
"""Avoid UnicodeEncodeError when printing pip/tool output on Windows (e.g. cp1252 console)."""
112161
encoding = getattr(sys.stdout, "encoding", None) or "utf-8"

build_wheels.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
from _helper_functions import get_current_platform
2929
from _helper_functions import get_no_binary_args
30+
from _helper_functions import get_pip_wheel_env_overrides
3031
from _helper_functions import merge_requirements
3132
from _helper_functions import print_color
3233
from yaml_list_adapter import YAMLListAdapter
@@ -293,6 +294,9 @@ def build_wheels(requirements: set, local_links: bool = True) -> dict:
293294
argument = match.group(1).strip()
294295
arg_param = match.group(2).strip()
295296
if arg_param in requirement.name:
297+
env_overrides = get_pip_wheel_env_overrides(str(requirement))
298+
env = os.environ.copy()
299+
env.update(env_overrides)
296300
out = subprocess.run(
297301
[
298302
f"{sys.executable}",
@@ -311,6 +315,7 @@ def build_wheels(requirements: set, local_links: bool = True) -> dict:
311315
f"{argument}",
312316
f"{arg_param}",
313317
],
318+
env=env if env_overrides else None,
314319
stdout=subprocess.PIPE,
315320
stderr=subprocess.PIPE,
316321
)
@@ -323,6 +328,9 @@ def build_wheels(requirements: set, local_links: bool = True) -> dict:
323328
# requirement wheel build
324329
# Get no-binary args for packages that should be built from source
325330
no_binary_args = get_no_binary_args(requirement.name)
331+
env_overrides = get_pip_wheel_env_overrides(str(requirement))
332+
env = os.environ.copy()
333+
env.update(env_overrides)
326334

327335
out = subprocess.run(
328336
[
@@ -341,6 +349,7 @@ def build_wheels(requirements: set, local_links: bool = True) -> dict:
341349
"--no-build-isolation",
342350
]
343351
+ no_binary_args,
352+
env=env if env_overrides else None,
344353
stdout=subprocess.PIPE,
345354
stderr=subprocess.PIPE,
346355
)

build_wheels_from_file.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from packaging.utils import canonicalize_name
1818

1919
from _helper_functions import get_no_binary_args
20+
from _helper_functions import get_pip_wheel_env_overrides
2021
from _helper_functions import print_color
2122

2223
# Do not pass --no-binary for these in --force-interpreter-binary mode:
@@ -124,6 +125,9 @@ def _apply_force_interpreter_binary(cli_flag: bool) -> bool:
124125
if _apply_force_interpreter_binary(args.force_interpreter_binary)
125126
else []
126127
)
128+
env_overrides = get_pip_wheel_env_overrides(requirement)
129+
env = os.environ.copy()
130+
env.update(env_overrides)
127131

128132
out = subprocess.run(
129133
[
@@ -139,6 +143,7 @@ def _apply_force_interpreter_binary(cli_flag: bool) -> bool:
139143
]
140144
+ no_binary_args
141145
+ force_interpreter_args,
146+
env=env if env_overrides else None,
142147
stdout=subprocess.PIPE,
143148
stderr=subprocess.PIPE,
144149
)
@@ -173,6 +178,9 @@ def _apply_force_interpreter_binary(cli_flag: bool) -> bool:
173178
if _apply_force_interpreter_binary(args.force_interpreter_binary)
174179
else []
175180
)
181+
env_overrides = get_pip_wheel_env_overrides(requirement)
182+
env = os.environ.copy()
183+
env.update(env_overrides)
176184

177185
out = subprocess.run(
178186
[
@@ -188,6 +196,7 @@ def _apply_force_interpreter_binary(cli_flag: bool) -> bool:
188196
]
189197
+ no_binary_args
190198
+ force_interpreter_args,
199+
env=env if env_overrides else None,
191200
stdout=subprocess.PIPE,
192201
stderr=subprocess.PIPE,
193202
)

exclude_list.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
platform: 'darwin'
2323
python: '>3.11'
2424

25-
2625
- package_name: 'pygobject'
2726
python: '==3.8'
2827

0 commit comments

Comments
 (0)