Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions cpython-unix/build-cpython.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,20 @@ replace_in_all("-L%s/deps/lib" % tools_path, "")
# See https://github.com/python/cpython/issues/145810#issuecomment-4068139183
replace_in_all("-LModules/_hacl", "")

# Strip toolchain bin directory prefix from sysconfig artifacts to avoid exposing
# build-time paths. This primarily fixes AR (e.g., /tools/llvm/bin/llvm-ar -> llvm-ar),
# which is not normalized by CPython, and also catches RANLIB and similar tools.
# See https://github.com/astral-sh/python-build-standalone/issues/1073
toolchain = os.environ["TOOLCHAIN"]
toolchain_bin = os.path.normpath(os.path.join(tools_path, toolchain, "bin"))
toolchain_bin_norm = toolchain_bin + "/"
replace_in_all(toolchain_bin_norm, "")

# Also catch resolved symlinks (e.g., macOS /var vs /private/var).
toolchain_bin_real = os.path.realpath(toolchain_bin) + "/"
if toolchain_bin_real != toolchain_bin_norm:
replace_in_all(toolchain_bin_real, "")

EOF

${BUILD_PYTHON} "${ROOT}/hack_sysconfig.py" "${ROOT}/out/python"
Expand Down
58 changes: 58 additions & 0 deletions test_ar_normalization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""Test that AR normalization works correctly."""
import os

def test_ar_normalization():
"""Simulate the string replacement to verify it works."""
# Simulated sysconfig data
test_cases = [
# (input, expected_output, description)
("AR = /tools/llvm/bin/llvm-ar", "AR = llvm-ar", "Basic AR case"),
("RANLIB = /tools/llvm/bin/llvm-ranlib", "RANLIB = llvm-ranlib", "RANLIB case"),
("CC = /tools/llvm/bin/clang -pthread", "CC = clang -pthread", "CC with flags"),
("CXX = /tools/llvm/bin/clang++ -pthread", "CXX = clang++ -pthread", "CXX with flags"),
# Edge cases
("PATH=/tools/llvm/bin:/usr/bin", "PATH=/tools/llvm/bin:/usr/bin", "PATH unchanged (no trailing /)"),
("Some random text", "Some random text", "No match - unchanged"),
# Path normalization: our search pattern is normalized, so double-slash
# in sysconfig data won't match (but that's OK - sysconfig should be normalized)
("AR = /tools//llvm/bin/llvm-ar", "AR = /tools//llvm/bin/llvm-ar", "Double slash in data won't match (expected)"),
# Empty value after replacement (edge case)
("AR = /tools/llvm/bin/", "AR = ", "Trailing slash creates empty value (acceptable)"),
]

tools_path = "/tools"
toolchain = "llvm"

# Use os.path.normpath to handle edge cases like double slashes
toolchain_bin = os.path.normpath(os.path.join(tools_path, toolchain, "bin"))
search = toolchain_bin + "/"
replace = ""

print(f"Testing replacement: '{search}' -> '{replace}'")
print("-" * 60)

all_passed = True
for input_str, expected, description in test_cases:
output = input_str.replace(search, replace)
passed = output == expected
status = "✓" if passed else "✗"

print(f"{status} {description}")
if not passed:
print(f" Input: {input_str}")
print(f" Expected: {expected}")
print(f" Got: {output}")
all_passed = False

print("-" * 60)
if all_passed:
print("All tests passed!")
return 0
else:
print("Some tests failed!")
return 1

if __name__ == "__main__":
import sys
sys.exit(test_ar_normalization())