[posix] E: Add libposix pathconf/fpathconf stubs#23
Open
esaurez wants to merge 1 commit into
Open
Conversation
POSIX defines `pathconf(2)` / `fpathconf(2)` as queryable per-path
configurable system limits. libstdc++'s `std::filesystem` code
(`cow-fs_ops.cc`, `fs_ops.cc`) emits strong undefined references to
`pathconf` -- specifically, `std::filesystem::current_path()` calls it
to size the buffer for `getcwd()`. When the consumer of libstdc++
(e.g. CPython linking against `libstdc++.a`) tries to link, those
references go unresolved and the link fails with "undefined reference
to `pathconf'".
This patch adds minimal `extern "C"` stubs for both functions to
`src/libs/posix/src/dummy.rs`, matching the convention used by the
other "not implemented" stubs in that module:
- `pathconf(path, name) -> c_long` always returns `-1` with
`errno = ENOSYS` (via `ErrorCode::InvalidSysCall`).
- `fpathconf(fd, name) -> c_long` always returns `-1` with
`errno = ENOSYS` (via `ErrorCode::InvalidSysCall`).
This is sufficient to satisfy the libstdc++ link. libstdc++'s
filesystem code checks `pathconf(...) == -1` and falls back to a
compile-time `PATH_MAX` default, so observable behaviour is unchanged
from "limit not advertised".
A future implementation should return real, selector-aware values
(`_PC_PATH_MAX = 4096`, `_PC_NAME_MAX = 255`, `_PC_LINK_MAX = 1`,
etc.) and only set `errno = EINVAL` for genuinely unrecognised
selectors, following the musl `src/conf/pathconf.c` pattern.
Validated end-to-end: CPython 3.12 + numpy 1.26.4 link cleanly against
a libstdc++.a that previously failed on `pathconf`, run `hello.py`,
and produce `NUMPY_TEST_OK` on the Nanvix microvm.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ppenna
pushed a commit
to nanvix/cpython
that referenced
this pull request
Jun 8, 2026
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>
ppenna
pushed a commit
to nanvix/cpython
that referenced
this pull request
Jun 10, 2026
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>
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
Adds minimal
extern "C"stubs forpathconf(2)andfpathconf(2)to libposix'ssrc/libs/posix/src/dummy.rs. Both stubs return-1witherrno = ENOSYS, matching the convention already used by every other "not implemented" stub in that module (popen,wordexp,glob,ftw,realpath, ...).Why this is required
libstdc++'s
std::filesystemcode emits a strong undefined reference topathconffrom at least two compilation units:libstdc++-v3/src/c++17/cow-fs_ops.cc—std::filesystem::current_path(std::error_code&)libstdc++-v3/src/c++17/fs_ops.cc—std::filesystem::current_path[abi:cxx11](std::error_code&)std::filesystem::current_path()callspathconf("/", _PC_PATH_MAX)to size the buffer it passes togetcwd(). Without a definition forpathconfanywhere in the link, any executable that links libstdc++ (CPython, any C++ user binary that touchesstd::filesystem) fails withundefined reference to 'pathconf'. Concretely, this blocks./z buildofnanvix/cpython:There is no existing implementation of either function in libposix today (verified by
grep -r 'fn pathconf' src/libs/posix).What changed
Just
src/libs/posix/src/dummy.rs: two new public extern "C" functions in the "Standalone Functions" block, with full doc comments (Description / Parameters / Returns / Notes / Safety) and the standard#[trace_libcall]attribute. No other files touched. 79 insertions, 0 deletions.Why this stub is sufficient for libstdc++ today
libstdc++'s
std::filesystemcode path is defensive: it checkspathconf(...) == -1and falls back to a compile-timePATH_MAXdefault (getcwdis called with a fixed 1024-byte buffer that grows onERANGE). It does not look aterrno. So returning-1with anyerrnovalue, including theENOSYSwe use here, is sufficient to unblock the link without any observable behaviour change vs. "the system advertises no path-conf limit".Future work (not in this PR)
A real implementation should return concrete, selector-aware values for the well-defined
_PC_*selectors and only seterrno = EINVALfor genuinely unrecognised selectors, following the muslsrc/conf/pathconf.cpattern:_PC_PATH_MAX<limits.h>_PC_NAME_MAX<limits.h>_PC_LINK_MAX_PC_PIPE_BUF_PC_NO_TRUNC-1witherrnounchanged per POSIX "no determinate limit"For now the stub returns
-1witherrno = ENOSYSfor every selector. The doc comment calls this out as a known limitation and points to the future-work direction. Users that rely on real values can follow up separately.Validation
.\z.ps1 build -- format-check rust-lint-check spellcheckis green; pre-commit hook passes.pathconfstrong UND), the resultingpython.elfrunshello.py, andimport numpy; numpy.array(...).sum()viadlopen()of numpy 1.26.4's extension.sos producesNUMPY_TEST_OKon the Nanvix microvm.Compatibility
ENOSYSerrno mirrors every other "not implemented" stub indummy.rsfor consistency. A future PR can refine to selector-aware values as described above without breaking this contract.