[nanvix] E: Build _ssl/_hashlib/_ctypes as .so#738
Closed
esaurez wants to merge 10 commits into
Closed
Conversation
Updates `Makefile.nanvix` so that `python.elf` correctly serves as the "main module" against which extension `.so`s (numpy, ssl, lxml, future pip-installed wheels, ...) resolve their C and C++ runtime symbols at dlopen() time. This is the consumer-side companion to the Nanvix loader's STB_WEAK support (esaurez/nanvix#22) and is gated on the new libposix `pathconf` / `fpathconf` stubs (esaurez/nanvix#23) for the configure conftest to even produce an executable. Three coordinated link-flag changes to the `CONFIGURE_ENV` block: 1. `LIBS` segment 1 -- new `--whole-archive ... --no-whole-archive` block ahead of the existing `--start-group`. Forces every object from libposix, libc, libm, libstdc++, and libgcc into python.elf so the runtime symbols extension `.so`s depend on are embedded (and re-exported via `-Wl,--export-dynamic`, already present). Without this, the static linker drops unreferenced objects (e.g. `fscanf`, `longjmp`, `strtold_l` for numpy; `operator new/delete[]`, `__cxa_*`, `_Unwind_*`, `std::type_info` vtables for any C++ extension) and subsequent dlopen() of those `.so`s fails with "symbol not found". 2. `LIBS` segment 2 -- the existing `--start-group` is trimmed to just the external add-on libraries (sqlite3, ssl, crypto, z, bz2, lzma, ffi). It no longer re-lists libposix / libc / libm: those archives are already fully included by segment 1, so the external libs can resolve their references against the already-embedded objects. 3. Two new top-level Makefile vars `LIBSTDCXX := -lstdc++` and `LIBGCC := -lgcc`. The GCC driver resolves them against its built- in search paths (libgcc lives under a versioned `lib/gcc/i686- nanvix/<gcc-version>/` directory, which would be fragile to hardcode). Defined once at top level because the `-l` form is identical between the docker and host build paths. `LDFLAGS` is unchanged. The existing `-Wl,--allow-multiple-definition` flag is kept and the surrounding comment is expanded to honestly enumerate the duplicate-symbol categories the flag is masking (newlib long-double math helpers, libposix/libc env+isatty overlaps, libc/libm math helper overlaps, libgcc internal `__x86.get_pc_thunk.*` duplicates, etc.) -- the set is large and toolchain-build-version- dependent, and is the only practical workaround until the contributing upstreams are fixed. `.nanvix/config.py::configure_env()` -- an unused helper that mirrors `Makefile.nanvix`'s `CONFIGURE_ENV` -- is kept in sync (same `--whole-archive` LIBS, same LDFLAGS) and gains a docstring calling out the dead-code status. A separate small cleanup PR can delete the helper entirely. Validated end-to-end on the Nanvix microvm: CPython 3.12 + numpy 1.26.4 runs `import numpy`, `np.arange`, `np.dot`, `reshape`, `flatten`, broadcasting, all producing `NUMPY_TEST_OK`. Hello.py and the existing single-process / multi-process / standalone modes are unaffected by the change because the linker flags are not mode-conditional. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stacked on top of the prior `[nanvix] E: Embed C/C++ runtime in
python.elf for .so dlopen support` PR.
Adds `libnvx_crt0.a` -- the executable-startup archive introduced by
the Nanvix `nvx-crt0` crate split -- to python.elf's `--whole-archive`
LIBS segment. This makes python.elf forward-compatible with the
planned Nanvix upstream change that removes `_start` / `_do_start` /
`c_trampoline` from `libposix.a`: once libposix drops the duplicate,
`libnvx_crt0.a` becomes the sole provider of those symbols.
What changed in `Makefile.nanvix`:
- New `LIBNVX_CRT0` variable (defined in both the docker and
host-build branches): absolute path to the sysroot copy of
`libnvx_crt0.a`.
- Existence check: parse-time error if `$(LIBNVX_CRT0)` is missing
from the sysroot, with a clear "update your sysroot" hint. Gated
on `MAKECMDGOALS` so `clean` and `distclean` still work against
older sysroots.
- `LIBS` line: prepend `$(LIBNVX_CRT0)` to the `--whole-archive`
group. Listed FIRST so that under the existing
`-Wl,--allow-multiple-definition` LDFLAG, the linker picks
`libnvx_crt0`'s `_start` over the duplicate copy `libposix.a`
currently still ships. This is an intentional behaviour change:
python.elf today and python.elf against a future stripped-down
libposix.a both use the same `_start` source (the standalone crt0
crate), avoiding subtle differences in startup behaviour across
the migration window.
- Comment block extended to document the ordering rationale and the
expected future state where libposix no longer carries startup
symbols.
`.nanvix/config.py::configure_env()` (the dead-code helper kept in
sync as documented in PR-10) is updated to mirror the new LIBS line.
Validated end-to-end:
- `./z build` succeeds; python.elf grows by ~500 bytes (the crt0
objects added under `--whole-archive`).
- `nm python.elf` shows `T _start` and `T _do_start` resolved.
- numpy 1.26.4 import + arithmetic + broadcasting test produces
`NUMPY_TEST_OK` on the Nanvix microvm.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds `ninja-build`, `python3-pip`, and `Cython<3` to the
toolchain-python docker image so that meson- and Cython-based Python
extension cross-builds (numpy, scipy, ...) work out-of-the-box,
without an apt/pip preamble on every `docker run` invocation.
What changed in `.nanvix/docker/Dockerfile`:
- Added `python3-pip` and `ninja-build` to the apt install list.
- Added `pip3 install --break-system-packages 'Cython<3'` (pinned for
numpy 1.26.x compatibility; lift the pin when bumping numpy).
- Added `rm -rf /usr/include/python3.12` after the install. The
`python3-pip`/`ninja-build` apt packages transitively pull in
`libpython3.12-dev`, whose headers under `/usr/include/python3.12`
would otherwise be picked up by meson's regen step ahead of the
Nanvix cross sysroot headers and silently corrupt the cross-build.
- Comment block explaining the rationale for each addition and the
`/usr/include/python3.12` purge.
Why this matters:
The numpy `.so` cross-build (validated end-to-end on 2026-05-27 with
the STB_WEAK loader fix landed) requires two tools that were not
present in the image as shipped:
- `ninja` — meson's default backend; missing it makes every
meson-based Python extension build fail immediately.
- `Cython` — used by `numpy/_build_utils/tempita.py` to template
`.pyx.in` files; without it the `numpy.random` codegen step fails.
Before this change, the workaround was to inject:
```bash
apt-get update -qq
apt-get install -qq -y --no-install-recommends ninja-build python3-pip
pip3 install --quiet --break-system-packages 'Cython<3'
rm -rf /usr/include/python3.12
```
into every numpy build invocation, which (a) was fragile, (b) required
the docker container to have outbound network access on every build
(non-hermetic), and (c) re-paid the apt install cost in CI every run.
Validated locally:
- `docker build -f .nanvix/docker/Dockerfile -t toolchain-python:pr13
.nanvix/docker/` succeeds.
- `docker run --rm <image> bash -c 'ninja --version'` → `1.11.1`.
- `docker run --rm <image> bash -c 'python3 -c "import Cython;
print(Cython.__version__)"'` → `0.29.37`.
- `docker run --rm <image> bash -c 'ls /usr/include/python3.12'` →
exits non-zero / "No such file or directory".
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… and 'origin/feat/toolchain-python-bake-ninja-cython' into phase0-array
Adds a small bash wrapper that sits in front of the real `i686-nanvix-gcc` and `i686-nanvix-g++` driver binaries in the toolchain-python docker image. The wrapper detects whether the invocation is producing an executable or a shared library and applies the correct linker flags for each case.
This mirrors the well-established `emcc` pattern used by emscripten and Pyodide, where the compiler-driver wrapper is what knows the difference between main-module and side-module builds, so consumers (cpython's Makefile.nanvix, future numpy / scipy / lxml meson builds, etc.) can use a single `LDFLAGS` env var without needing to encode the exe-vs-shared distinction themselves.
## Why this exists
`Makefile.nanvix` sets a single `LDFLAGS` on `./configure` that contains executable-specific linker flags:
- `-T <sysroot>/lib/user.ld` — executable layout script.
- `-no-pie` — disable PIE for executables.
- `-Wl,--no-dynamic-linker` — executable-only marker.
- `-Wl,--export-dynamic` — populate the main executable's `.dynsym`.
cpython propagates that same `LDFLAGS` to BOTH the main `python.elf` link AND every extension-module `.so` link via `PY_LDFLAGS`. For `.so` outputs these exe-only flags are wrong:
- `-T user.ld` tells `ld` to use an executable layout. When applied to a `-shared` link, `ld` treats the output as an exe and rejects undefined symbols, even those that should resolve at `dlopen()` time against the main exe's `.dynsym` (the Python C API symbols every extension references).
- `-no-pie` is incompatible with `-shared` (shared libraries must be PIC).
- `-Wl,--no-dynamic-linker` is meaningless for `.so`.
- `-Wl,--export-dynamic` is exe-only.
There is no clean place in cpython 3.12's `Modules/Setup` system to express "use this LDFLAGS for the exe link and that LDFLAGS for shared modules". cpython expects a single `LDFLAGS` shared between both.
The cleanest fix is to install a compiler-driver wrapper that does the split transparently: forwards exe builds unchanged, and strips exe-only flags + adds `-fPIC` for shared builds. That way `LDFLAGS` stays the same for everyone and the wrapper does the right thing per-invocation.
## What changed in `.nanvix/docker/`
- **New file `cc-wrapper.sh`** (~110 lines bash). Detects compile-only mode (`-c` / `-S` / `-E`), exe-link mode (no `-shared`), or shared-link mode (`-shared` present). Compile-only and exe modes forward to the real binary unchanged via `exec "$real_bin" "$@"`. Shared mode iterates the args and:
- Strips `-T <script>` (both `-T <script>` and `-T<script>` forms), `-no-pie`, `-Wl,--no-dynamic-linker`, `-Wl,--export-dynamic`, `-Wl,-T,<script>`, and bare `*.ld` argument files.
- Adds `-fPIC` if not already present.
- Uses a bash `filtered=()` array (not a string) so argv boundaries and quoting are preserved across the rewrite — `exec "$real_bin" "${filtered[@]}"` is argv-preserving for arguments containing spaces, empty strings, or glob metacharacters.
- **Dockerfile updated** to install the wrapper. The script is copied to `/opt/nanvix/bin/i686-nanvix-cc-wrapper.sh`, made executable, and the real `i686-nanvix-gcc` / `i686-nanvix-g++` binaries are renamed to `<name>.real`. Symlinks `<name>` -> `i686-nanvix-cc-wrapper.sh` are then installed. The wrapper picks the right `.real` binary based on `argv[0]`.
The install pattern is defensive: if the upstream base image already has a wrapper symlinked (some local-build flavours of `toolchain-python` carry an earlier wrapper), the symlink is removed and replaced — but only after asserting that the matching `<name>.real` file already exists, so a missing `.real` aborts the install rather than stranding the toolchain. If the real binary has not yet been renamed, it is moved to `<name>.real` in the same step.
## Validation
Built the image locally with the additions and smoke-tested all three wrapper modes against a trivial `int main(){return 0;}`:
- **Test 1 (exe link, no `-shared`):** wrapper transparent; real gcc handles normally.
- **Test 2 (simple `-shared`):** wrapper detects shared mode, adds `-fPIC`, link succeeds.
- **Test 3 (`-shared` plus the toxic exe-only flags `-T <script>` `-no-pie` `-Wl,--no-dynamic-linker`):** wrapper strips the toxic flags and the link succeeds with no spurious "cannot create executables" error.
Build-side end-to-end smoke test with cpython: applied a Phase-0-style change to `Modules/Setup.local` adding `*shared*\narray arraymodule.c`. With the wrapper in place, `array.cpython-312-i686-nanvix.so` (~190 KB) is produced and installed at the canonical `lib/python3.12/lib-dynload/` location; `PyInit_array` no longer appears in `python.elf`. Full `./z build` succeeds.
## What this unblocks
This wrapper is the foundational prerequisite for the broader `.a` -> `.so` migration documented in `nanvix-todo/cpython-static-to-shared-migration.md`. Every subsequent phase of that plan (peeling stdlib extension modules off `python.elf` and shipping them as `.so` files loaded via dlopen, exactly as upstream CPython works) depends on this wrapper being in place. Without it, every per-module conversion would need a per-call LDFLAGS hack.
## Backward compatibility
This change is purely additive at the image level — it adds the wrapper script and rewrites the gcc/g++ entry points to point at it. Existing build paths that don't pass `-shared` see no behavioural change (the wrapper falls through to the real binary unchanged). Existing `.so` build paths that DID work before (e.g., when LDFLAGS happened not to include `-T user.ld`) continue to work because the wrapper's strip-then-add-fPIC produces a strict superset of what bare `gcc -shared` would have done.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
First step of the .a -> .so migration plan documented in
`nanvix-todo/cpython-static-to-shared-migration.md`. Converts `array`
from a static built-in module into a shared `.so` loaded via dlopen
at runtime, matching upstream CPython's layout for stdlib extension
modules.
## Changes
* `.nanvix/docker.py` + `.nanvix/lxml.py` — `Setup.local` generation:
- Group the existing static modules under an explicit `*static*`
directive (was the implicit `#` comment that makesetup tolerated).
- Add a `*shared*` group with `array arraymodule.c` so cpython's
`setup.py build_ext` produces
`array.cpython-312-i686-nanvix.so` at
`lib/python3.12/lib-dynload/`.
* `.nanvix/test.py` — extend the `test_hello.py` smoke test to
`import array`, assert it is NOT in `sys.builtin_module_names`, and
exercise a tiny array operation. This proves the dlopen path
end-to-end on every test run; if the `.so` fails to load (loader
bug, missing PIE relocation, symbol-resolution issue, ...) the
smoke test fails immediately rather than silently regressing.
## Validation
`./z build` and `./z test`:
- `array.cpython-312.so` is produced at
`<sysroot>/lib/python3.12/lib-dynload/array.cpython-312.so`.
- Hello smoke prints
`CPYTHON_TEST_ARRAY_SO: array loaded via dlopen from
/lib/python3.12/lib-dynload/array.cpython-312.so`.
- lxml + HTTP server smoke continue to PASS.
## Dependencies
This PR depends on the following prereq PRs landing first:
- #682 — `--whole-archive` + `--export-dynamic` in
python.elf LIBS.
- #683 — bake `ninja` + `Cython` into the toolchain
image (needed by future meson-based extensions; harmless for
`array`).
- #684 — link `libnvx_crt0.a` into python.elf (will
become unnecessary once nanvix/nanvix#2453 lands but harmless
meanwhile).
- #687 — cc-wrapper for `-shared` vs exe link mode
(the `.so` link uses it).
- nanvix/nanvix#2450 — loader honours `STB_WEAK` undefined symbols.
- nanvix/nanvix#2453 — `libposix.a` is the sole owner of `sysalloc`
state (Fix 2 v3); without this, the first `dlopen` collides with
the heap.
Reviewers: please wait for those PRs (and the matching
`ghcr.io/nanvix/toolchain-python:latest` rebuild) before testing
this one.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Builds 39 CPython stdlib extension modules as runtime-loaded .so files under lib/python3.12/lib-dynload/<name>.cpython-312.so instead of statically linking them into python.elf. Generalises the *shared* Setup.local flow first proven by feat/phase0-array-so. Modules built as .so -------------------- - Data primitives (no external deps): _bisect, _heapq, _struct, _random, _opcode, _queue, _csv, binascii, _json, _pickle, _zoneinfo. - Math and memory (libm symbols resolved against python.elf): math, cmath, _statistics, mmap, _contextvars. - Text codecs (no external deps): unicodedata, _multibytecodec, _codecs_cn/hk/iso2022/jp/kr/tw. - With bundled-in-cpython C deps (each .so bundles its own .a, same as upstream cpython's default ./configure run): _asyncio, _datetime, _decimal, pyexpat, _elementtree, _md5, _sha1, _sha2, _sha3, _blake2, select, _socket, _posixsubprocess, fcntl, termios. For the modules with bundled-in-cpython C deps (_decimal, pyexpat, _sha2), each .so bundles its own copy of the vendored .a via cpython's normal MODULE_*_LDFLAGS machinery -- exactly the behavior of cpython's default ./configure run on Linux without --with-system-libmpdec / --with-system-expat. mpdec / expat / libHacl_Hash_SHA2 are stateless C APIs with at most one consumer each (pyexpat exposes a PyCapsule that _elementtree calls through, so libexpat lives in pyexpat.so only), so duplication into python.elf would buy nothing. --with-libm= is cleared so libm symbols stay in python.elf -- math / cmath resolve them via the existing --whole-archive of libm.a in LIBNVX_CRT0. Infrastructure -------------- - .nanvix/setup_local.py (new): SETUP_LOCAL_ENTRIES data table + render_setup_local() -- single source of truth for Modules/Setup.local, consumed by both the host (.nanvix/lxml.py) and Docker (.nanvix/docker.py) build paths. - .nanvix/test.py: _SO_MODULE_SANITY_CHECKS table + _render_so_sanity_snippets() emit smoke-test snippets that exercise every migrated module via import + a trivial method call and assert each module is no longer in sys.builtin_module_names. - Makefile.nanvix: --with-libm= cleared (Phase 1B math/cmath modules resolve libm symbols against python.elf .dynsym at dlopen time via the existing --whole-archive of libm.a in LIBNVX_CRT0). Runtime dependencies (already merged upstream) ---------------------------------------------- - nanvix/nanvix#2472 -- libm visibility fix. - nanvix/nanvix#2473 -- dlfcn init-array + DT_RUNPATH support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…FLAGS When --with-system-libmpdec / --with-system-expat is *not* given, the bundled-library code paths in configure.ac (lines 3831, 3915) hardcoded a literal `-lm` in: LIBEXPAT_LDFLAGS="-lm $(LIBEXPAT_A)" LIBMPDEC_LDFLAGS="-lm $(LIBMPDEC_A)" On Linux this happens to work because LIBM defaults to `-lm`, so the result is a no-op. On Nanvix we pass `--with-libm=` (empty) to keep libm.a out of every Setup.local `.so` -- libm is whole-archived into python.elf instead. The literal `-lm` defeats that and bundles a full copy of libm.a into both `_decimal.so` and `pyexpat.so` -- about ~400 KB of redundant code per .so, plus a symbol-collision risk that forces --allow-multiple-definition at every other .so link. Switching the literal to `$(LIBM)` is equivalent on Linux (LIBM=-lm by default) and correctly drops the duplicate libm when LIBM is empty. Both `configure.ac` and the generated `configure` are patched in lockstep so no autoreconf is required. Bug surfaced by the cpython-on-Nanvix .so management audit; tracked for a follow-up upstream contribution to python/cpython once the Nanvix port stabilizes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Converts the three stdlib extensions whose external dependencies are Nanvix-ported libraries that already ship as .so (libssl/libcrypto from openssl, libffi) from *static* (linked into python.elf) to *shared* (lib/python3.12/lib-dynload/<name>.cpython-312.so), each emitting DT_NEEDED for the corresponding sysroot library: _ctypes.cpython-312.so -> libffi.so _ssl.cpython-312.so -> libssl.so -> libcrypto.so _hashlib.cpython-312.so -> libcrypto.so (shared with _ssl, deduped) This is exactly how upstream cpython builds these modules on a Linux distro with --with-system-* detection enabled (the default). The Nanvix dynamic loader walks the DT_NEEDED chain at dlopen time (the openssl chain forms a diamond at libcrypto.so) and UND symbols in each .so bind to python.elf .dynsym. _ssl and _hashlib previously embedded their own copies of libcrypto (~5.5 MB each); routing both through the single libcrypto.so ends the OpenSSL init-order bug where the two copies maintained separate provider state and the first openssl_sha256() call failed. python.elf LIBS drops -lssl -lcrypto -lffi. _bz2 / _lzma / zlib / _sqlite3 are intentionally NOT moved here: the Nanvix port repos for libbz2 / liblzma / libz / libsqlite3 do not yet ship .so builds, so those four extensions stay statically built into python.elf (cpython upstream default) until the follow-up PR that lands alongside the Wave 6 port-repo .so PRs. Infrastructure -------------- - .nanvix/runtime_sos.py (new): REQUIRED_RUNTIME_SOS single source of truth (libffi.so, libcrypto.so, libssl.so) + stage_runtime_sos(), consumed by .nanvix/test.py and .nanvix/package.py to copy the .so files from the buildroot into the test / release sysroot. - .nanvix/setup_local.py: _ssl / _hashlib / _ctypes shared entries. - .nanvix/test.py: CPYTHON_TEST_EXTERNAL_DEPS smoke checks. - .nanvix/z.py: _DEP_EXPECTED_LIBS validates libffi.so + libssl.so / libcrypto.so installed into the buildroot at `./z setup` time. - Makefile.nanvix: LIBS drops -lssl -lcrypto -lffi. Runtime dependencies (already merged upstream) ---------------------------------------------- - nanvix/nanvix#2473 -- dlfcn init-array + DT_RUNPATH support. - nanvix/nanvix#2478 -- diamond DT_NEEDED handling (openssl chain). - nanvix/nanvix#2481 -- pthread_once (critical: OpenSSL routes every internal one-time init through pthread_once). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Jun 17, 2026
ppenna
force-pushed
the
feat/wave5-pr-a-stdlib-so
branch
from
July 16, 2026 01:22
10289fb to
44512fc
Compare
|
Closing the pre-SDK implementation rather than carrying its GCC/Newlib assumptions forward. The product goal remains valid, but the current OpenSSL/libffi SDK packages ship only static archives, so correct |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Converts the three stdlib extensions whose external dependencies are Nanvix-ported libraries that already ship as
.so(libssl/libcryptofrom openssl,libffi) from*static*(linked intopython.elf) to*shared*(lib/python3.12/lib-dynload/<name>.cpython-312.so), each emittingDT_NEEDEDfor the corresponding sysroot library.This is exactly how upstream CPython builds these modules on a Linux distro with
--with-system-*detection enabled (the default).DT_NEEDED chains
_ctypes.cpython-312.so→DT_NEEDED libffi.so_ssl.cpython-312.so→DT_NEEDED libssl.so→DT_NEEDED libcrypto.so_hashlib.cpython-312.so→DT_NEEDED libcrypto.soThe Nanvix dynamic loader walks the chain at
dlopen()time (the openssl chain forms a diamond atlibcrypto.so), and UND symbols in each.sobind topython.elf .dynsym. Same flow Linux distros use._ssland_hashlibpreviously embedded their own copies oflibcrypto(~5.5 MB each); routing both through the singlelibcrypto.soends the OpenSSL init-order bug where the two copies maintained separate provider state and the firstopenssl_sha256()call failed.Scope
python.elfLIBS drops-lssl -lcrypto -lffi._bz2/_lzma/zlib/_sqlite3are intentionally not moved here — the Nanvix port repos forlibbz2/liblzma/libz/libsqlite3do not yet ship.sobuilds, so those four extensions stay statically built intopython.elf(CPython upstream default) until those port repos ship.sobuilds and a follow-up PR switches the four extensions toDT_NEEDED.lxml is not part of this PR. lxml is a third-party package, not a CPython stdlib module, and the way it is currently integrated on Nanvix (a flat-name built-in shim) diverges from how upstream CPython loads third-party extensions. That divergence is addressed separately — this PR stays focused on the stdlib modules that match upstream's system-library
.soflow.Mechanics
.nanvix/runtime_sos.py(new)REQUIRED_RUNTIME_SOSsingle source of truth (libffi.so,libcrypto.so,libssl.so) +stage_runtime_sos(), consumed by.nanvix/test.pyand.nanvix/package.pyto copy the.sofiles from the buildroot into the test / release sysroot..nanvix/setup_local.py_ssl/_hashlib/_ctypesshared entries..nanvix/test.pyCPYTHON_TEST_EXTERNAL_DEPSsmoke checks (import+ trivial attribute access)..nanvix/z.py_DEP_EXPECTED_LIBSvalidateslibffi.so+libssl.so/libcrypto.soinstalled into the buildroot at./z setuptime.Makefile.nanvix-lssl -lcrypto -lffi.Dependencies
Base branch:
feat/wave5-pr-a-stdlib-so(#732).Port-repo PRs that produce the required
.sofiles (already filed upstream):.solibffi.solibcrypto.so,libssl.soRuntime dependencies (already merged upstream):
dlfcninit-array + DT_RUNPATH support.libcrypto.soboth vialibssl.soand directly from_hashlib).pthread_once(critical: OpenSSL routes every internal one-time init throughpthread_once; without it everyEVP_*call fails).