From 76b6b9742fdcf66fa561f18e78bc5fb7a472ae02 Mon Sep 17 00:00:00 2001 From: Enrique Saurez Date: Tue, 9 Jun 2026 19:04:46 -0700 Subject: [PATCH] [build] E: Build liblzma.so alongside liblzma.a Adds a liblzma.so link step inside the existing build script that links liblzma.so from the (now PIC) static archive via -Wl,--whole-archive so every liblzma entry point becomes part of the .so's .dynsym. Sets DT_SONAME=liblzma.so so consumers that link against it emit a proper DT_NEEDED entry. liblzma is self-contained -- no transitive .so deps -- so the .so records no DT_NEEDED of its own. libc / libm symbols (memcpy, memset, malloc, ...) are left UND via -nostdlib and bind at dlopen time against the host executable's .dynsym, matching the model already used by other Nanvix shared libraries such as libffi.so / libssl.so. xz's autotools libtool does not know about i686-nanvix, so the upstream --enable-shared path is not viable. The configure opts keep --disable-shared --enable-static; the .so is linked manually from the .a after `make install` completes. Changes to .nanvix/z.py: - _configure_env_overrides: append -fPIC to CFLAGS so the same .o files compile into both .a and .so. - build: add a SHAREDLIB link step after `make install DESTDIR=...` that writes liblzma.so directly into the install staging tree alongside liblzma.a. - _stage_artefacts: extend the lib_dir / build_dir copy-out to cover liblzma.so in addition to liblzma.a. - _stage_release_outputs: copy liblzma.so into lib_out() so `./z release` packages it. Adds .gitattributes forcing LF line endings on the vendored Unix shell / autotools scripts (configure, config.*, install-sh, build-aux/*, *.sh, ...). These are already committed as LF; the attribute keeps them LF on checkout regardless of a contributor's core.autocrlf setting, so dash inside the Linux toolchain container does not choke on CRLF. This replaces an earlier runtime CR-stripping workaround that was carried in the build script. Runtime dependency: the shared-library build becomes useful once the loader changes in nanvix/nanvix#2473 ([syscall] E: Run dlopen ctors/dtors and DT_RUNPATH) ship. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitattributes | 17 +++++++++++++++++ .nanvix/z.py | 33 ++++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..bf1c200b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Vendored Unix shell / autotools scripts must keep LF line endings so +# the build runs inside the Linux toolchain container regardless of a +# contributor's git `core.autocrlf` setting. Windows checkouts with +# autocrlf=true otherwise rewrite these to CRLF, which dash rejects +# ("Syntax error: newline unexpected" inside case/esac). +configure text eol=lf +config.guess text eol=lf +config.sub text eol=lf +install-sh text eol=lf +depcomp text eol=lf +missing text eol=lf +compile text eol=lf +ar-lib text eol=lf +ltmain.sh text eol=lf +test-driver text eol=lf +*.sh text eol=lf +build-aux/* text eol=lf diff --git a/.nanvix/z.py b/.nanvix/z.py index 8df067b1..3ae63d01 100644 --- a/.nanvix/z.py +++ b/.nanvix/z.py @@ -154,7 +154,7 @@ def _configure_env_overrides(self) -> dict[str, str]: "RANLIB": f"{bin_}/i686-nanvix-ranlib", "STRIP": f"{bin_}/i686-nanvix-strip", "NM": f"{bin_}/i686-nanvix-nm", - "CFLAGS": f"-O2 -D_GNU_SOURCE -I{sysroot}/include", + "CFLAGS": f"-O2 -fPIC -D_GNU_SOURCE -I{sysroot}/include", "CPPFLAGS": f"-D_GNU_SOURCE -I{sysroot}/include", "LDFLAGS": ( f"-static -T{sysroot}/lib/user.ld -L{sysroot}/lib " @@ -316,13 +316,33 @@ def build(self) -> None: tests_targets = " ".join(_UPSTREAM_TEST_NAMES) # Single shell script: configure -> make -> install -> - # tests-build -> copy test ELFs out to the mounted workspace. + # liblzma.so -> tests-build -> copy test ELFs out to the mounted + # workspace. + # + # liblzma.so is linked from the (now PIC) static archive via + # --whole-archive so every liblzma entry point becomes part of + # the .so's .dynsym. DT_SONAME=liblzma.so so consumers that link + # against it emit a proper DT_NEEDED entry. libc / libm symbols + # (memcpy, memset, malloc, ...) are left UND via -nostdlib and + # bind at dlopen time against the host executable's .dynsym, + # the same model already used by other Nanvix shared libraries + # such as libffi.so / libssl.so. + cc = overrides["CC"] script = "\n".join( [ "set -e", configure_cmd, f"make -j{nproc}", f"make install DESTDIR={shlex.quote(str(stage_container))}", + # Build liblzma.so from the (PIC) liblzma.a libtool produced. + # libtool's shared-library detection does not know about + # i686-nanvix (hence --disable-shared in configure opts), + # so we link the .so ourselves and stage it next to .a. + f"{shlex.quote(cc)} -shared -fPIC -nostdlib " + f" -Wl,-soname,liblzma.so -Wl,-z,noexecstack" + f" -Wl,--whole-archive src/liblzma/.libs/liblzma.a" + f" -Wl,--no-whole-archive" + f" -o {shlex.quote(str(stage_container))}/sysroot/lib/liblzma.so", ( "make -C tests " f"LDFLAGS={shlex.quote(tests_ldflags)} " @@ -390,19 +410,21 @@ def _stage_artefacts(self) -> None: ) # Clear any prior staged outputs but keep _install/ in place. - for name in ("liblzma.a", "include", "lib"): + for name in ("liblzma.a", "liblzma.so", "include", "lib"): target = build_dir / name if target.is_dir(): shutil.rmtree(target) elif target.exists(): target.unlink() - # liblzma.a → build/liblzma.a (and also build/lib/liblzma.a for - # the release packaging step in a later commit). + # liblzma.a / liblzma.so → build/liblzma.{a,so} and also + # build/lib/liblzma.{a,so} for the release packaging step. lib_dir = build_dir / "lib" lib_dir.mkdir(parents=True, exist_ok=True) shutil.copy2(src_root / "lib" / "liblzma.a", lib_dir / "liblzma.a") shutil.copy2(src_root / "lib" / "liblzma.a", build_dir / "liblzma.a") + shutil.copy2(src_root / "lib" / "liblzma.so", lib_dir / "liblzma.so") + shutil.copy2(src_root / "lib" / "liblzma.so", build_dir / "liblzma.so") # liblzma.pc → build/lib/pkgconfig/liblzma.pc pc_src = src_root / "lib" / "pkgconfig" / "liblzma.pc" @@ -445,6 +467,7 @@ def _stage_release_outputs(self) -> None: tst_o.mkdir(parents=True, exist_ok=True) shutil.copy2(lib_dir / "liblzma.a", lib_o / "liblzma.a") + shutil.copy2(lib_dir / "liblzma.so", lib_o / "liblzma.so") shutil.copy2( lib_dir / "pkgconfig" / "liblzma.pc", lib_o / "pkgconfig" / "liblzma.pc",