Skip to content

gh-144942: Link $(MODLIBS) into the macOS shared library and framework - #159966

Merged
itamaro merged 1 commit into
python:mainfrom
itamaro:gh-144942-macos-dylib-modlibs
Oct 22, 2026
Merged

itamaro merged 1 commit into
python:mainfrom
itamaro:gh-144942-macos-dylib-modlibs

Conversation

@itamaro

@itamaro itamaro commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

The rules that link libpython$(LDVERSION).dylib and the macOS and iOS frameworks don't pass $(MODLIBS), unlike the libpython$(LDVERSION).so rule. When a module is built in, for example via Modules/Setup.local, the libraries that module needs are left out:

  • --enable-framework: the build fails with undefined symbols.
  • --enable-shared: the dylib is linked with -undefined dynamic_lookup, so the build succeeds and the failure only shows up at runtime.

To reproduce, build on macOS with this Modules/Setup.local:

*static*
_blake2 blake2module.c

On main:

  • --enable-framework: linking Python.framework fails with 12 undefined _Py_LibHacl_* symbols.
  • --enable-shared: nm -u libpython3.16.dylib lists the same 12 symbols. After make install, python3 -c "import _blake2; _blake2.blake2b(b'abc')" aborts with dyld: missing symbol called, and so does a C program that embeds Python.

With this change, both builds link with no undefined HACL symbols, and _blake2 works as a built-in module. In default builds $(MODLIBS) is empty, so they are unaffected. test_hashlib, test_hmac, test_embed and test_sysconfig pass for shared and framework builds, both with and without the Setup.local above (macOS 14, arm64). I haven't tested the iOS framework rule, which gets the same one-line change.

python-build-standalone already carries the dylib part of this as a patch (astral-sh/python-build-standalone#870). This PR doesn't remove -undefined dynamic_lookup, as the earlier gh-145186 did.

Written with assistance from Claude Code Opus 5.5

…amework

The rules for the libpython dylib and for the macOS and iOS frameworks did
not pass $(MODLIBS), unlike the rule for libpython.so. When a module is
built in (for example via Modules/Setup.local), the libraries it needs,
such as the HACL* objects used by _blake2, were left out. The framework
link then fails with undefined symbols, while the dylib, which is linked
with -undefined dynamic_lookup, fails only when the missing symbol is
called at runtime.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@ambv ambv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix works. I built the PR locally on macOS arm64 with --enable-framework and _blake2, _sha2, pyexpat, and _bz2.

@itamaro
itamaro merged commit 03864a2 into python:main Oct 22, 2026
59 checks passed
@miss-islington-app

Copy link
Copy Markdown

Thanks @itamaro for the PR 🌮🎉.. I'm working now to backport this PR to: 3.14, 3.15.
🐍🍒⛏🤖

@bedevere-app

bedevere-app Bot commented Oct 22, 2026

Copy link
Copy Markdown

GH-160158 is a backport of this pull request to the 3.15 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 bugs and security fixes label Oct 22, 2026
@bedevere-app

bedevere-app Bot commented Oct 22, 2026

Copy link
Copy Markdown

GH-160160 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Oct 22, 2026
itamaro added a commit that referenced this pull request Oct 22, 2026
… framework (GH-159966) (#160160)

gh-144942: Link `$(MODLIBS)` into the macOS shared library and framework (GH-159966)

The rules that link `libpython$(LDVERSION).dylib` and the macOS and iOS frameworks don't pass `$(MODLIBS)`, unlike the `libpython$(LDVERSION).so` rule. When a module is built in, for example via `Modules/Setup.local`, the libraries that module needs are left out:

- **`--enable-framework`:** the build fails with undefined symbols.
- **`--enable-shared`:** the dylib is linked with `-undefined dynamic_lookup`, so the build succeeds and the failure only shows up at runtime.

To reproduce, build on macOS with this `Modules/Setup.local`:

```
*static*
_blake2 blake2module.c
```

On `main`:

- **`--enable-framework`:** linking `Python.framework` fails with 12 undefined `_Py_LibHacl_*` symbols.
- **`--enable-shared`:** `nm -u libpython3.16.dylib` lists the same 12 symbols. After `make install`, `python3 -c "import _blake2; _blake2.blake2b(b'abc')"` aborts with `dyld: missing symbol called`, and so does a C program that embeds Python.

With this change, both builds link with no undefined HACL symbols, and `_blake2` works as a built-in module. In default builds `$(MODLIBS)` is empty, so they are unaffected. `test_hashlib`, `test_hmac`, `test_embed` and `test_sysconfig` pass for shared and framework builds, both with and without the `Setup.local` above (macOS 14, arm64). I haven't tested the iOS framework rule, which gets the same one-line change.

python-build-standalone already carries the dylib part of this as a patch ([astral-sh/python-build-standalone#870](astral-sh/python-build-standalone#870)). This PR doesn't remove `-undefined dynamic_lookup`, as the earlier gh-145186 did.
(cherry picked from commit 03864a2)

Co-authored-by: Itamar Oren <itamarost@gmail.com>
itamaro added a commit that referenced this pull request Oct 22, 2026
… framework (GH-159966) (#160158)

gh-144942: Link `$(MODLIBS)` into the macOS shared library and framework (GH-159966)

The rules that link `libpython$(LDVERSION).dylib` and the macOS and iOS frameworks don't pass `$(MODLIBS)`, unlike the `libpython$(LDVERSION).so` rule. When a module is built in, for example via `Modules/Setup.local`, the libraries that module needs are left out:

- **`--enable-framework`:** the build fails with undefined symbols.
- **`--enable-shared`:** the dylib is linked with `-undefined dynamic_lookup`, so the build succeeds and the failure only shows up at runtime.

To reproduce, build on macOS with this `Modules/Setup.local`:

```
*static*
_blake2 blake2module.c
```

On `main`:

- **`--enable-framework`:** linking `Python.framework` fails with 12 undefined `_Py_LibHacl_*` symbols.
- **`--enable-shared`:** `nm -u libpython3.16.dylib` lists the same 12 symbols. After `make install`, `python3 -c "import _blake2; _blake2.blake2b(b'abc')"` aborts with `dyld: missing symbol called`, and so does a C program that embeds Python.

With this change, both builds link with no undefined HACL symbols, and `_blake2` works as a built-in module. In default builds `$(MODLIBS)` is empty, so they are unaffected. `test_hashlib`, `test_hmac`, `test_embed` and `test_sysconfig` pass for shared and framework builds, both with and without the `Setup.local` above (macOS 14, arm64). I haven't tested the iOS framework rule, which gets the same one-line change.

python-build-standalone already carries the dylib part of this as a patch ([astral-sh/python-build-standalone#870](astral-sh/python-build-standalone#870)). This PR doesn't remove `-undefined dynamic_lookup`, as the earlier gh-145186 did.
(cherry picked from commit 03864a2)

Co-authored-by: Itamar Oren <itamarost@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build The build process and cross-build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants