Skip to content

Commit c96a209

Browse files
Enrique SaurezCopilot
andcommitted
[nanvix] E: Build _ssl/_hashlib/_ctypes + lxml extensions as .so
Builds 3 stdlib extensions (_ssl, _hashlib, _ctypes) and the 2 lxml extensions as runtime-loaded .so files, and confirms that libffi / libssl / libcrypto / libxml2 / libxslt / libexslt / lxml ship as standalone .so files referenced via DT_NEEDED. This matches upstream cpython's default behavior on every Linux distro (system-library detection enabled): cpython's normal MODULE_*_LDFLAGS machinery wires each extension's per-module *_LIBS env var ("-L/-l" form) into its .so link line, producing a proper DT_NEEDED entry rather than embedding the .a. Modules covered --------------- - _ssl.cpython-312.so -> DT_NEEDED libssl.so -> libcrypto.so - _hashlib.cpython-312.so -> DT_NEEDED libcrypto.so - _ctypes.cpython-312.so -> DT_NEEDED libffi.so - _lxml_etree.cpython-312.so + _lxml_elementpath.cpython-312.so: thin dlopen shims (see lxml shim layer note below). python.elf LIBS drops -lssl -lcrypto -lffi (those symbols come from the standalone .so files now). _ssl and _hashlib previously embedded their own copies of libcrypto.a (~5.5 MB each); the deduplication ends the OpenSSL init-order bug where the two copies maintained separate provider state and the first openssl_sha256() call failed. Out of scope: _bz2 / _lzma / zlib / _sqlite3. Their Nanvix port repos do not yet ship .so builds (the Wave 6 port-repo PRs add those), so those four extensions stay statically linked into python.elf for now -- the same shape upstream cpython produces without --with-system-* flags. The follow-up cpython PR migrates them once Wave 6 lands. lxml shim layer --------------- The lxml port repo (nanvix/lxml) currently emits Cython outputs as system shared libraries (/lib/liblxml_*.so) rather than as native cpython extension modules (site-packages/lxml/etree.cpython-312-*.so, the upstream pip-installed layout). Until the port is fixed, Modules/lxml_etree_builtin.c and Modules/lxml_elementpath_builtin.c remain in place as thin dlopen shims (via the new Modules/lxml_dlopen_shim.h helper) that load the system libraries at runtime and forward the cpython PyInit_* symbol. The handle is intentionally leaked on success because lxml.etree owns process-lifetime parser state -- unloading would invalidate live xmlNodePtr values in the Python heap. RTLD_GLOBAL lets a hypothetical future libxml2/libxslt consumer (e.g., xmlsec) resolve its references against the symbols this dlopen publishes. This shim layer is a Nanvix-specific stopgap; once the lxml port emits native cpython extensions, the entire shim layer goes away and cpython's standard importer loads lxml.etree directly. Tracked in nanvix-todo/lxml-port-ship-as-native-cpython-extensions.md. Mechanics --------- - .nanvix/setup_local.py: adds 3 *shared* entries (_ssl, _hashlib, _ctypes); flips _lxml_etree / _lxml_elementpath from a static-link form to bare-source entries (the shim now dlopens the .so chain at runtime). - .nanvix/config.py: drops -lssl -lcrypto -lffi from python.elf LIBS. - Makefile.nanvix: LIBS drops -lssl -lcrypto -lffi. Per-module *_LIBS env vars (LIBSQLITE3_LIBS, ZLIB_LIBS, BZIP2_LIBS, LIBLZMA_LIBS, LIBFFI_LIBS) stay in -L/-l form -- same as upstream cpython's system-library detection produces. - .nanvix/runtime_sos.py (new): REQUIRED_RUNTIME_SOS + helper to stage the 8 .so files (libxml2, libxslt, libexslt, liblxml_etree, liblxml_elementpath, libffi, libcrypto, libssl) from buildroot/lib/ into sysroot/lib/, with fail-fast FileNotFoundError on a missing dep. Consumed by both .nanvix/test.py and .nanvix/package.py. - .nanvix/test.py: adds one row to _SO_MODULE_SANITY_CHECKS for _ssl / _hashlib / _ctypes. - .nanvix/z.py: _DEP_EXPECTED_LIBS["libffi"] adds libffi.so; _DEP_EXPECTED_LIBS["openssl"] adds libssl.so + libcrypto.so. - Modules/lxml_dlopen_shim.h (new): shared dlopen helper used by both lxml shim .c files. - Modules/lxml_etree_builtin.c and lxml_elementpath_builtin.c: each shrinks to ~10 lines wrapping a single lxml_dlopen_shim() call. Runtime dependencies -------------------- - nanvix/nanvix#2472 -- libm visibility fix (inherited from PR-A). - nanvix/nanvix#2473 -- dlfcn init-array + DT_RUNPATH support. Two additional Nanvix loader fixes are required for this PR to function at run time and must land upstream before this PR is mergeable: - A loader fix for diamond DT_NEEDED chains so libcrypto.so reached via libssl.so and directly from _hashlib.cpython-312.so resolves to a single mapped instance. - A pthread_once fix in libposix so OpenSSL's lazy provider init does not hang on first call. Companion port-lib repos: the Nanvix port libraries must be the versions that produce the corresponding .so files (libffi, openssl, libxml2, libxslt, lxml). Already pinned in cpython's nanvix.toml and consumed via the buildroot snapshot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 10289fb commit c96a209

10 files changed

Lines changed: 253 additions & 42 deletions

File tree

.nanvix/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def configure_env(toolchain: str | Path, sysroot: str | Path) -> dict[str, str]:
109109
f"{tp['libc']} {tp['libm']} "
110110
f"-lstdc++ -lgcc -Wl,--no-whole-archive "
111111
f"-Wl,--start-group "
112-
f"-lsqlite3 -lssl -lcrypto -lz -lbz2 -llzma -lffi -Wl,--end-group"
112+
f"-lsqlite3 -lz -lbz2 -llzma -Wl,--end-group"
113113
),
114114
"LIBSQLITE3_LIBS": f"-L{sr}/lib -lsqlite3",
115115
"LIBSQLITE3_CFLAGS": f"-I{sr}/include",

.nanvix/package.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
build_mod = load_sibling("build", __file__)
2424
lxml_mod = load_sibling("lxml", __file__)
2525
ramfs_mod = load_sibling("ramfs", __file__)
26+
runtime_sos_mod = load_sibling("runtime_sos", __file__)
2627

2728

2829
def _artifact_base(
@@ -166,6 +167,16 @@ def package(
166167
if py_lib.is_dir():
167168
shutil.copytree(py_lib, ramfs_sysroot / config.PYTHON_LIB_DIR)
168169

170+
# Stage the lxml + libxml2/libxslt/libexslt + libffi + libssl/libcrypto
171+
# shared libraries from the buildroot into the release ramfs at
172+
# sysroot/lib/<name>.so so the corresponding C extensions can dlopen
173+
# them at runtime (see .nanvix/runtime_sos.py for the DT_NEEDED chain).
174+
runtime_sos_mod.stage_runtime_sos(
175+
repo_root / ".nanvix" / "buildroot" / "lib",
176+
ramfs_sysroot,
177+
target_label="release",
178+
)
179+
169180
ramfs_mod.trim_sysroot(ramfs_staging)
170181

171182
# --- Include python.elf binary ---

.nanvix/runtime_sos.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright(c) The Maintainers of Nanvix.
2+
# Licensed under the MIT License.
3+
4+
"""Runtime .so staging for Nanvix CPython.
5+
6+
Single source of truth for the list of shared libraries that must be
7+
present under sysroot/lib/ at run time so the corresponding C extension
8+
.so files (lxml.etree, ctypes, ssl, hashlib) can dlopen them.
9+
10+
Consumers:
11+
- .nanvix/test.py::stage -- staged into the test sysroot
12+
- .nanvix/package.py::package -- staged into the release ramfs
13+
"""
14+
15+
from __future__ import annotations
16+
17+
import shutil
18+
from pathlib import Path
19+
from typing import Iterable
20+
21+
# Names of .so files that must exist under .nanvix/buildroot/lib/ after
22+
# `./z setup` and must be staged into the test or release sysroot at
23+
# sysroot/lib/<name>. Failure to find any of these is fatal: the
24+
# corresponding C extension (lxml.etree, ctypes, ssl, hashlib) would
25+
# fail at first import.
26+
#
27+
# The .so files form a DT_NEEDED chain that the Nanvix dynamic loader
28+
# walks at dlopen time:
29+
#
30+
# _lxml_etree.cpython-312.so -> liblxml_etree.so
31+
# liblxml_etree.so -> libxslt.so + libexslt.so + libxml2.so
32+
# libxslt.so / libexslt.so -> libxml2.so
33+
# _lxml_elementpath.cpython-312.so -> liblxml_elementpath.so
34+
# liblxml_elementpath.so -> libxml2.so
35+
# _ctypes.cpython-312.so -> libffi.so
36+
# _ssl.cpython-312.so -> libssl.so + libcrypto.so
37+
# libssl.so -> libcrypto.so
38+
# _hashlib.cpython-312.so -> libcrypto.so
39+
REQUIRED_RUNTIME_SOS: tuple[str, ...] = (
40+
"libxml2.so",
41+
"libxslt.so",
42+
"libexslt.so",
43+
"liblxml_etree.so",
44+
"liblxml_elementpath.so",
45+
"libffi.so",
46+
"libcrypto.so",
47+
"libssl.so",
48+
)
49+
50+
51+
def stage_runtime_sos(
52+
buildroot_lib: Path,
53+
sysroot_lib: Path,
54+
*,
55+
target_label: str,
56+
required: Iterable[str] = REQUIRED_RUNTIME_SOS,
57+
) -> None:
58+
"""Copy every entry in ``required`` from ``buildroot_lib`` to
59+
``sysroot_lib`` (creating the destination if needed).
60+
61+
Raises FileNotFoundError if any required .so is missing from
62+
``buildroot_lib``. ``target_label`` is interpolated into the error
63+
message so the caller's context (test stage vs. release package) is
64+
visible in the traceback.
65+
"""
66+
sysroot_lib.mkdir(parents=True, exist_ok=True)
67+
required = tuple(required)
68+
missing = [name for name in required if not (buildroot_lib / name).is_file()]
69+
if missing:
70+
raise FileNotFoundError(
71+
f"Cannot stage {target_label}: required shared libraries "
72+
f"missing from {buildroot_lib}: {', '.join(missing)}. Run "
73+
"`./z setup` to populate the buildroot, or rebuild the upstream "
74+
"port libraries."
75+
)
76+
for so_name in required:
77+
shutil.copy2(buildroot_lib / so_name, sysroot_lib / so_name)
78+
print(f" Staged {so_name} -> sysroot/lib/")

.nanvix/setup_local.py

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,30 +91,28 @@ class SetupEntry(NamedTuple):
9191
"take precedence."
9292
),
9393
),
94+
# lxml shims: each is a thin .c that dlopens its matching .so from
95+
# lib/liblxml_*.so at runtime (see Modules/lxml_dlopen_shim.h). The
96+
# .so files declare DT_NEEDED entries for libxslt.so + libexslt.so +
97+
# libxml2.so so the Nanvix dynamic loader walks the chain at dlopen
98+
# time and python.elf no longer embeds any lxml/libxml2/libxslt code.
9499
SetupEntry(
95100
name="_lxml_etree",
96101
linkage=Linkage.SHARED,
97-
tokens=(
98-
"lxml_etree_builtin.c",
99-
"-L{sysroot}/lib",
100-
"-llxml_etree",
101-
"-lxslt",
102-
"-lexslt",
103-
"-lxml2",
104-
"-lz",
102+
tokens=("lxml_etree_builtin.c",),
103+
section_header=(
104+
"lxml C extensions as dlopen-from-/lib shims. The actual "
105+
"Cython code lives in liblxml_etree.so + "
106+
"liblxml_elementpath.so staged into sysroot/lib/ by "
107+
".nanvix/test.py and .nanvix/package.py. No per-module "
108+
"-L/-l flags here -- the loader walks the DT_NEEDED chain "
109+
"at dlopen time."
105110
),
106-
section_header=("lxml C extension modules (linked via pre-built archives)."),
107111
),
108112
SetupEntry(
109113
name="_lxml_elementpath",
110114
linkage=Linkage.SHARED,
111-
tokens=(
112-
"lxml_elementpath_builtin.c",
113-
"-L{sysroot}/lib",
114-
"-llxml_elementpath",
115-
"-lxml2",
116-
"-lz",
117-
),
115+
tokens=("lxml_elementpath_builtin.c",),
118116
),
119117
# ---------------- Data primitives (no external deps) ----------------
120118
*(
@@ -275,6 +273,41 @@ class SetupEntry(NamedTuple):
275273
),
276274
SetupEntry(name="fcntl", linkage=Linkage.SHARED, tokens=("fcntlmodule.c",)),
277275
SetupEntry(name="termios", linkage=Linkage.SHARED, tokens=("termios.c",)),
276+
# ---------------- Modules with external Nanvix-ported deps ---------
277+
#
278+
# libffi, libssl, libcrypto each ship as a .so under $(SYSROOT)/lib/
279+
# and the consuming extension .so (_ctypes, _ssl, _hashlib)
280+
# references it via DT_NEEDED. The loader resolves them at dlopen
281+
# time and binds UND symbols against python.elf .dynsym.
282+
#
283+
# _bz2 / _lzma / zlib / _sqlite3 are intentionally NOT moved here:
284+
# the Nanvix port repos for libbz2 / liblzma / libz / libsqlite3 do
285+
# not yet ship .so builds, so those four extensions stay statically
286+
# built into python.elf (cpython upstream default) until the
287+
# follow-up PR that lands alongside the Wave 6 port-repo .so PRs.
288+
SetupEntry(
289+
name="_ssl",
290+
linkage=Linkage.SHARED,
291+
tokens=("_ssl.c",),
292+
section_header=(
293+
"Stdlib modules with external Nanvix-ported deps that are "
294+
"already shipped as .so by their respective port repos. "
295+
"Each .so emits DT_NEEDED for the corresponding sysroot "
296+
"library; the loader walks the chain at dlopen time."
297+
),
298+
),
299+
SetupEntry(name="_hashlib", linkage=Linkage.SHARED, tokens=("_hashopenssl.c",)),
300+
SetupEntry(
301+
name="_ctypes",
302+
linkage=Linkage.SHARED,
303+
tokens=(
304+
"_ctypes/_ctypes.c",
305+
"_ctypes/callbacks.c",
306+
"_ctypes/callproc.c",
307+
"_ctypes/stgdict.c",
308+
"_ctypes/cfield.c",
309+
),
310+
),
278311
)
279312

280313

.nanvix/test.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
build_mod = load_sibling("build", __file__)
3434
lxml_mod = load_sibling("lxml", __file__)
3535
ramfs_mod = load_sibling("ramfs", __file__)
36+
runtime_sos_mod = load_sibling("runtime_sos", __file__)
3637

3738

3839
# ---------------------------------------------------------------------------
@@ -105,6 +106,16 @@
105106
("termios", "hasattr(m, 'tcgetattr')"),
106107
),
107108
),
109+
(
110+
"CPYTHON_TEST_EXTERNAL_DEPS",
111+
(
112+
# libffi / libssl / libcrypto: each consumed via DT_NEEDED of
113+
# the corresponding sysroot/lib/<name>.so.
114+
("_ssl", "hasattr(m, 'RAND_bytes')"),
115+
("_hashlib", "hasattr(m, 'openssl_sha256') or hasattr(m, 'new')"),
116+
("_ctypes", "hasattr(m, 'dlopen')"),
117+
),
118+
),
108119
)
109120

110121

@@ -522,6 +533,16 @@ def stage(
522533

523534
sysroot_dir = staging / "sysroot"
524535

536+
# Stage the lxml/libxml2/libxslt/libexslt + libffi + libssl/libcrypto
537+
# shared libraries from the buildroot into the test sysroot at
538+
# sysroot/lib/<name>.so so the corresponding C extensions can dlopen
539+
# them at runtime (see .nanvix/runtime_sos.py for the DT_NEEDED chain).
540+
runtime_sos_mod.stage_runtime_sos(
541+
repo_root / ".nanvix" / "buildroot" / "lib",
542+
sysroot_dir / "lib",
543+
target_label="test sysroot",
544+
)
545+
525546
# Ensure _sysconfigdata module is present in the installed sysroot.
526547
# make install should copy it from build/<pybuilddir>/ but this can
527548
# silently fail when PYTHON_FOR_BUILD is not available or when the

.nanvix/z.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@
8080
# Map dependency names to the library files they install into buildroot/lib.
8181
_DEP_EXPECTED_LIBS: dict[str, list[str]] = {
8282
"bzip2": ["libbz2.a"],
83-
"libffi": ["libffi.a"],
83+
"libffi": ["libffi.a", "libffi.so"],
8484
"zlib": ["libz.a"],
8585
"sqlite": ["libsqlite3.a"],
86-
"openssl": ["libssl.a", "libcrypto.a"],
86+
"openssl": ["libssl.a", "libcrypto.a", "libssl.so", "libcrypto.so"],
8787
"libxml2": ["libxml2.a"],
8888
"libxslt": ["libxslt.a", "libexslt.a"],
8989
"lxml": ["liblxml_etree.a", "liblxml_elementpath.a"],

Makefile.nanvix

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,17 @@ endif
185185
# which libnvx_crt0 is the sole provider. Listing it first today keeps
186186
# python.elf using a consistent `_start` source across both states.
187187
#
188-
# `LIBS` segment 2 (`--start-group ... --end-group`): the external add-on
189-
# libraries (sqlite3, ssl, crypto, z, bz2, lzma, ffi). The group is needed
190-
# only for their inter-archive circular dependencies; they resolve symbols
191-
# from libposix/libc/libm/libstdc++ against the already-embedded objects
192-
# from segment 1.
188+
# `LIBS` segment 2 (`--start-group ... --end-group`): the external
189+
# Nanvix-ported libraries (`-lsqlite3 -lz -lbz2 -llzma`) whose .a files
190+
# stay statically linked into python.elf. The corresponding extensions
191+
# (_sqlite3, zlib, _bz2, _lzma) remain *static* in Setup.local for now
192+
# because the Nanvix port repos for libbz2 / libz / liblzma /
193+
# libsqlite3 do not yet ship .so builds. The follow-up cpython PR that
194+
# lands alongside the Wave 6 port-repo .so PRs migrates these four
195+
# extensions to *shared* with DT_NEEDED references to lib*.so. -lssl
196+
# / -lcrypto / -lffi are NOT in this list -- they ship as separate .so
197+
# files under sysroot/lib/ and are referenced via DT_NEEDED by their
198+
# consumer .so modules (_ssl, _hashlib, _ctypes).
193199
CONFIGURE_ENV = \
194200
CC="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-gcc" \
195201
CXX="$(TOOLCHAIN_PREFIX)/bin/i686-nanvix-g++" \
@@ -199,7 +205,7 @@ CONFIGURE_ENV = \
199205
CFLAGS="-O3 -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables -I$(SYSROOT_PATH)/include" \
200206
CFLAGS_NODIST="-fno-semantic-interposition" \
201207
LDFLAGS="-L$(SYSROOT_PATH)/lib -T$(SYSROOT_PATH)/lib/user.ld -Wl,--allow-multiple-definition -no-pie -Wl,--export-dynamic -Wl,--no-dynamic-linker" \
202-
LIBS="-Wl,--whole-archive $(LIBNVX_CRT0) $(LIBPOSIX) $(LIBC) $(LIBM) $(LIBSTDCXX) $(LIBGCC) -Wl,--no-whole-archive -Wl,--start-group -lsqlite3 -lssl -lcrypto -lz -lbz2 -llzma -lffi -Wl,--end-group" \
208+
LIBS="-Wl,--whole-archive $(LIBNVX_CRT0) $(LIBPOSIX) $(LIBC) $(LIBM) $(LIBSTDCXX) $(LIBGCC) -Wl,--no-whole-archive -Wl,--start-group -lsqlite3 -lz -lbz2 -llzma -Wl,--end-group" \
203209
LIBSQLITE3_LIBS="-L$(SYSROOT_PATH)/lib -lsqlite3" \
204210
LIBSQLITE3_CFLAGS="-I$(SYSROOT_PATH)/include" \
205211
ZLIB_LIBS="-L$(SYSROOT_PATH)/lib -lz" \

Modules/lxml_dlopen_shim.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* lxml_dlopen_shim.h -- shared helper for the two lxml dlopen shims
3+
* (lxml_etree_builtin.c, lxml_elementpath_builtin.c).
4+
*
5+
* makesetup does not support dotted module names, so the Cython
6+
* extensions are registered under the flat names "_lxml_etree" /
7+
* "_lxml_elementpath" via Modules/Setup.local and bridged back to
8+
* lxml.etree / lxml._elementpath by a pure-Python shim at lxml/etree.py
9+
* (see .nanvix/lxml.py::_ETREE_SHIM).
10+
*
11+
* On Nanvix the Cython-generated code lives in liblxml_etree.so /
12+
* liblxml_elementpath.so under sysroot/lib/, each of which declares
13+
* DT_NEEDED entries for libxslt.so + libexslt.so + libxml2.so (etree)
14+
* or libxml2.so (elementpath). Loading those .so files via dlopen lets
15+
* the Nanvix dynamic loader walk that chain at runtime, so each
16+
* library lives at one address in memory and python.elf does not have
17+
* to embed multiple megabytes of libxml2/libxslt code statically.
18+
*
19+
* The dlopen handle is INTENTIONALLY LEAKED on success: lxml.etree owns
20+
* process-lifetime parser state (xmlInitParser globals), so unloading
21+
* the library would invalidate still-live xmlNodePtr values in the
22+
* Python heap.
23+
*
24+
* RTLD_GLOBAL so subsequently loaded extensions that link back into
25+
* libxml2/libxslt (e.g., a future xmlsec) can resolve their undefined
26+
* references against the symbols this dlopen publishes.
27+
*/
28+
29+
#ifndef NANVIX_LXML_DLOPEN_SHIM_H
30+
#define NANVIX_LXML_DLOPEN_SHIM_H
31+
32+
#include "Python.h"
33+
34+
#include <dlfcn.h>
35+
36+
typedef PyObject *(*lxml_dlopen_init_fn)(void);
37+
38+
static inline PyObject *
39+
lxml_dlopen_shim(const char *so_path, const char *init_symbol)
40+
{
41+
void *handle = dlopen(so_path, RTLD_NOW | RTLD_GLOBAL);
42+
if (handle == NULL) {
43+
PyErr_Format(PyExc_ImportError,
44+
"dlopen(\"%s\") failed: %s", so_path, dlerror());
45+
return NULL;
46+
}
47+
48+
lxml_dlopen_init_fn init =
49+
(lxml_dlopen_init_fn)dlsym(handle, init_symbol);
50+
if (init == NULL) {
51+
const char *err = dlerror();
52+
PyErr_Format(PyExc_ImportError,
53+
"dlsym(\"%s\") in %s failed: %s",
54+
init_symbol, so_path,
55+
err ? err : "symbol not found");
56+
/* Release the handle on this error path. The success path
57+
* intentionally leaks it -- see file header. */
58+
dlclose(handle);
59+
return NULL;
60+
}
61+
62+
return init();
63+
}
64+
65+
#endif /* NANVIX_LXML_DLOPEN_SHIM_H */

Modules/lxml_elementpath_builtin.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
/*
2-
* lxml_elementpath_builtin.c - Shim for lxml._elementpath built-in module.
2+
* lxml_elementpath_builtin.c -- Nanvix dlopen shim for lxml._elementpath.
33
*
4-
* Registers the Cython _elementpath extension under the flat name
5-
* "_lxml_elementpath" for Modules/Setup.local.
4+
* See lxml_dlopen_shim.h for the design rationale.
65
*/
76

8-
#include "Python.h"
7+
#include "lxml_dlopen_shim.h"
98

10-
extern PyObject* PyInit__elementpath(void);
9+
#define LXML_ELEMENTPATH_SO "lib/liblxml_elementpath.so"
1110

1211
PyMODINIT_FUNC
1312
PyInit__lxml_elementpath(void)
1413
{
15-
return PyInit__elementpath();
14+
return lxml_dlopen_shim(LXML_ELEMENTPATH_SO, "PyInit__elementpath");
1615
}

0 commit comments

Comments
 (0)