Splux Linux

source-based Linux using SPS

SPS · log · files · refs · tags · releases · people · languages · GitHub · commit

eeb6e68


Load target libraries when just-built modules are imported.

Date
Commiteeb6e6897eda99130912ee39c6ed43968f704a48
GitHubmirror

Parents

Stat

 PACKAGE-MAINTAINER.md | 12 ++++++++++++
 bin/mkiso             | 15 ++++++++++++++-
 bin/mkpkg             | 43 ++++++++++++++++++++++++++++++++++++++++---
 bin/setup             | 23 ++++++++++++++++++++---
 lib/mkiso/seed-bins   |  2 ++
 tests/test_build.sh   | 42 +++++++++++++++++++++++++++++++++++++++++-
 tests/test_mkiso.sh   |  8 ++++++++
 tests/test_setup.sh   |  6 ++++++
 8 files changed, 143 insertions(+), 8 deletions(-)

Diff

diff --git a/PACKAGE-MAINTAINER.md b/PACKAGE-MAINTAINER.md
index 5cccaaa..ffbfd77 100644
--- a/PACKAGE-MAINTAINER.md
+++ b/PACKAGE-MAINTAINER.md
@@ -138,6 +138,7 @@ The phase environment provides:
 | `SRC` | Downloaded/copied sources and support trees |
 | `PKG` | Package staging root |
 | `MAKEJOBS` | Positive parallel-job count |
+| `SPS_TARGET_LIBRARY_PATH` | Target `lib64`/`lib` dirs when `SPS_ROOT` is not `/` |
 
 Typical build-system records look like:
 
@@ -166,6 +167,17 @@ Use the upstream project's intended build system and supported options. Build
 commands run on the host; `mkpkg` is not a chroot and cannot prevent a bad
 command from modifying paths outside `$PKG`.
 
+When `SPS_ROOT` is a mounted disk (live `setup`), `mkpkg` puts that root on
+`LD_LIBRARY_PATH` so a just-built interpreter can import its own extensions
+against libraries already unpacked into the target. CPython's
+`check_extension_modules` will otherwise load the live disc's older
+`libsqlite3`, rename `_sqlite3` to `_sqlite3_failed`, and then `make install`
+dies on `sharedinstall`. Host `gcc`, `python3`, `meson`, and `git` wrappers
+restore the previous `LD_LIBRARY_PATH` so those tools do not load a
+half-installed libc from the disk. Shared libraries belong in `lib64` on
+this architecture; pass `--libdir=/usr/lib64` (or Meson's `--libdir=lib64`)
+instead of relying on Autoconf's `/usr/lib` default.
+
 ## Local files and patches
 
 A real `files/` directory is copied to `$SRC/files`; a real `patches/` directory
diff --git a/bin/mkiso b/bin/mkiso
index 63c3de0..4a3c4d8 100755
--- a/bin/mkiso
+++ b/bin/mkiso
@@ -804,6 +804,19 @@ mkiso_verify_live()
 		fi
 	fi
 
+	if [ -e /usr/sbin/efibootmgr ] || [ -L /usr/sbin/efibootmgr ] ||
+		[ -e /usr/bin/efibootmgr ] || [ -L /usr/bin/efibootmgr ]
+	then
+		if [ ! -e "$mkiso_live/usr/sbin/efibootmgr" ] &&
+			[ ! -L "$mkiso_live/usr/sbin/efibootmgr" ] &&
+			[ ! -e "$mkiso_live/usr/bin/efibootmgr" ] &&
+			[ ! -L "$mkiso_live/usr/bin/efibootmgr" ]
+		then
+			sps_die "$SPS_EX_PACKAGE" \
+				"seeded live image is missing efibootmgr"
+		fi
+	fi
+
 	mkiso_verify_compiler
 	mkiso_verify_plasma
 	mkiso_verify_setup_catalog
@@ -1608,7 +1621,7 @@ fi
 printf '%s: copying disk tools for setup\n' "$sps_prog" >&2
 for mkiso_cmd in lsblk blkid sfdisk cfdisk fdisk wipefs mkfs.ext4 mke2fs \
 	mkfs.vfat mkswap partprobe udevadm udevd grub-install grub-mkconfig \
-	dhcpcd
+	efibootmgr dhcpcd
 do
 	mkiso_copy_host_cmd "$mkiso_cmd" || :
 done
diff --git a/bin/mkpkg b/bin/mkpkg
index 477b5cd..031106f 100755
--- a/bin/mkpkg
+++ b/bin/mkpkg
@@ -713,6 +713,17 @@ shell_quote()
 	printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
 }
 
+# Host tools must load the live disc's libraries, not SPS_ROOT. CPython's
+# `make` imports just-built _sqlite3.so against the sqlite on the target;
+# that needs LD_LIBRARY_PATH. gcc loading a half-installed libc from the
+# disk would abort the compiler. Restore the caller's LD_LIBRARY_PATH.
+write_host_ld_restore()
+{
+	printf '%s\n' 'LD_LIBRARY_PATH=$SPS_HOST_LD_LIBRARY_PATH'
+	printf '%s\n' 'export LD_LIBRARY_PATH'
+	printf '%s\n' '[ -n "$LD_LIBRARY_PATH" ] || unset LD_LIBRARY_PATH'
+}
+
 # gcc on PATH must inject -L/-isystem itself. Autoconf often runs `gcc`
 # without LDFLAGS, which is how alsa-utils printed "No linkable libasound
 # was found" after alsa-lib was already in SPS_ROOT.
@@ -723,6 +734,7 @@ write_cc_wrapper()
 	[ -n "$real_cc" ] && [ -x "$real_cc" ] || return 0
 	{
 		printf '%s\n' '#!/bin/sh'
+		write_host_ld_restore
 		printf 'exec %s -isystem %s -L%s -L%s -L%s -L%s -Wl,-rpath-link,%s -Wl,-rpath-link,%s "$@"\n' \
 			"$(shell_quote "$real_cc")" \
 			"$(shell_quote "$target_inc")" \
@@ -736,6 +748,19 @@ write_cc_wrapper()
 	chmod 755 "$wrapper_path"
 }
 
+write_host_tool_wrapper()
+{
+	wrapper_path=$1
+	real_tool=$2
+	[ -n "$real_tool" ] && [ -x "$real_tool" ] || return 0
+	{
+		printf '%s\n' '#!/bin/sh'
+		write_host_ld_restore
+		printf 'exec %s "$@"\n' "$(shell_quote "$real_tool")"
+	} >"$wrapper_path"
+	chmod 755 "$wrapper_path"
+}
+
 # A controlled build root runs each phase with the root's /usr/bin and /bin
 # ahead of the host PATH and exposes the root as $SYSROOT.  Recipes building a
 # staged toolchain use this to ensure their compiler, linker, and headers are
@@ -764,8 +789,11 @@ fi
 # target, not only live /usr. Exporting LDFLAGS is not enough: autoconf
 # AC_CHECK_LIB often invokes `gcc conftest.c -lasound` with a cleared
 # environment. Wrappers named gcc/g++ on PATH inject -L/-isystem instead.
-# Do not set LD_LIBRARY_PATH to the target; that makes host gcc load a
-# half-installed libc from the disk.
+# CPython then *runs* the new _sqlite3.so (check_extension_modules) and
+# renames it to _sqlite3_failed if the loader picked the live disc's
+# older libsqlite3. LD_LIBRARY_PATH must include SPS_ROOT for that
+# import. Host gcc/python3/meson/git wrappers restore the previous
+# LD_LIBRARY_PATH so they do not load a half-installed libc from the disk.
 if [ -n "${SPS_ROOT:-}" ] && [ "$SPS_ROOT" != / ]; then
 	target_root=$SPS_ROOT
 	target_inc=$target_root/usr/include
@@ -794,7 +822,11 @@ if [ -n "${SPS_ROOT:-}" ] && [ "$SPS_ROOT" != / ]; then
 	C_INCLUDE_PATH=$target_inc${C_INCLUDE_PATH:+:$C_INCLUDE_PATH}
 	CPLUS_INCLUDE_PATH=$target_inc${CPLUS_INCLUDE_PATH:+:$CPLUS_INCLUDE_PATH}
 	LIBRARY_PATH=$target_libpath${LIBRARY_PATH:+:$LIBRARY_PATH}
-	export CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH LIBRARY_PATH
+	SPS_HOST_LD_LIBRARY_PATH=${LD_LIBRARY_PATH-}
+	SPS_TARGET_LIBRARY_PATH=$target_libpath
+	LD_LIBRARY_PATH=$target_libpath${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+	export CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH LIBRARY_PATH \
+		SPS_HOST_LD_LIBRARY_PATH SPS_TARGET_LIBRARY_PATH LD_LIBRARY_PATH
 
 	CPPFLAGS="$target_cflags${CPPFLAGS:+ $CPPFLAGS}"
 	CFLAGS="$target_cflags${CFLAGS:+ $CFLAGS}"
@@ -839,6 +871,11 @@ if [ -n "${SPS_ROOT:-}" ] && [ "$SPS_ROOT" != / ]; then
 		CXX=$build_dir/run/g++
 		export CXX
 	fi
+	for host_tool in python3 python meson cmake git curl wget perl; do
+		host_tool_path=$(PATH=$host_path command -v "$host_tool" 2>/dev/null) ||
+			host_tool_path=
+		write_host_tool_wrapper "$build_dir/run/$host_tool" "$host_tool_path"
+	done
 
 	# Autoconf sources CONFIG_SITE before AC_CHECK_LIB. AM_PATH_ALSA
 	# (alsa-utils) only adds -L when --with-alsa-prefix is set; this
diff --git a/bin/setup b/bin/setup
index 2d0f4fe..3574b6e 100755
--- a/bin/setup
+++ b/bin/setup
@@ -2162,10 +2162,27 @@ if [ "$setup_install_bootloader" -eq 1 ]; then
 			"--install-bootloader requires --disk; refusing to guess. See /root/sps-bootloader.txt"
 	printf '%s: grub-install %s (explicit)\n' "$sps_prog" "$setup_disk" >&2
 	if [ -d "$setup_root/boot/efi" ]; then
-		grub-install --target=x86_64-efi --efi-directory="$setup_root/boot/efi" \
-			--bootloader-id=SPS --boot-directory="$setup_root/boot" \
+		# Firmware fallback path: \EFI\BOOT\BOOTX64.EFI. This does not
+		# need efibootmgr or working NVRAM, which QEMU often lacks.
+		printf '%s: grub-install EFI removable (EFI/BOOT/BOOTX64.EFI)\n' \
+			"$sps_prog" >&2
+		grub-install --target=x86_64-efi \
+			--efi-directory="$setup_root/boot/efi" \
+			--boot-directory="$setup_root/boot" \
+			--removable --no-nvram \
 			"$setup_disk" ||
-			setup_fail "$SPS_EX_BUILD" "grub-install (EFI) failed"
+			setup_fail "$SPS_EX_BUILD" "grub-install (EFI removable) failed"
+		if command -v efibootmgr >/dev/null 2>&1; then
+			printf '%s: grub-install EFI Boot#### via efibootmgr\n' \
+				"$sps_prog" >&2
+			grub-install --target=x86_64-efi \
+				--efi-directory="$setup_root/boot/efi" \
+				--bootloader-id=SPS \
+				--boot-directory="$setup_root/boot" \
+				"$setup_disk" ||
+				printf '%s: efibootmgr NVRAM update failed; EFI/BOOT/BOOTX64.EFI is in place\n' \
+					"$sps_prog" >&2
+		fi
 	else
 		grub-install --target=i386-pc --boot-directory="$setup_root/boot" \
 			"$setup_disk" ||
diff --git a/lib/mkiso/seed-bins b/lib/mkiso/seed-bins
index 9697f5f..41d7747 100644
--- a/lib/mkiso/seed-bins
+++ b/lib/mkiso/seed-bins
@@ -121,6 +121,8 @@
 /usr/bin/patch
 /usr/bin/diff
 /usr/sbin/grub-install
+/usr/sbin/efibootmgr
+/usr/bin/efibootmgr
 /usr/bin/grub-mkconfig
 /usr/sbin/grub-mkconfig
 /usr/bin/grub-probe
diff --git a/tests/test_build.sh b/tests/test_build.sh
index 6ae05cb..55b3ccb 100755
--- a/tests/test_build.sh
+++ b/tests/test_build.sh
@@ -261,8 +261,10 @@ description Confirms PATH gcc injects SPS_ROOT -L even without LDFLAGS
 configure   unset LDFLAGS CFLAGS CPPFLAGS LIBRARY_PATH
 configure   printf '%s\n' '#include <spsprobe.h>' 'int main(void){return sps_probe_lib();}' >"$WORK/probe.c"
 configure   gcc "$WORK/probe.c" -lspsprobe -o "$WORK/probe"
-install     mkdir -p "$PKG/usr/bin"
+configure   sed -n '1,20p' "$CC" >"$WORK/ccwrap"
+install     mkdir -p "$PKG/usr/bin" "$PKG/usr/share/target-cc-wrapper-probe"
 install     cp "$WORK/probe" "$PKG/usr/bin/target-cc-wrapper-probe"
+install     cp "$WORK/ccwrap" "$PKG/usr/share/target-cc-wrapper-probe/gcc"
 install     chmod 755 "$PKG/usr/bin/target-cc-wrapper-probe"
 EOF
 	wrap_artifact=$(run_mkpkg --no-download --output "$tmp/wrap-out" \
@@ -272,6 +274,44 @@ EOF
 	tar -xf "$wrap_artifact" -C "$tmp/wrap-extract"
 	[ -x "$tmp/wrap-extract/usr/bin/target-cc-wrapper-probe" ] ||
 		fail "wrapper probe binary was not staged"
+	grep -q SPS_HOST_LD_LIBRARY_PATH \
+		"$tmp/wrap-extract/usr/share/target-cc-wrapper-probe/gcc" ||
+		fail "gcc wrapper must restore the host LD_LIBRARY_PATH"
+
+	# CPython's check_extension_modules *runs* _sqlite3.so. Linking is
+	# not enough: the loader must find the sqlite in SPS_ROOT, not the
+	# live disc. Host gcc must not see that LD_LIBRARY_PATH.
+	mkdir -p "$tmp/run-recipe" "$tmp/run-out"
+	cat >"$tmp/run-recipe/recipe" <<'EOF'
+name        target-runtime-lib-probe
+version     1.0
+release     1
+arch        any
+description Confirms just-built binaries load libraries from SPS_ROOT
+configure   printf '%s\n' "$LD_LIBRARY_PATH" >"$WORK/ldpath"
+configure   printf '%s\n' "$SPS_TARGET_LIBRARY_PATH" >"$WORK/targetld"
+configure   printf '%s\n' '#include <spsprobe.h>' 'int main(void){return sps_probe_lib();}' >"$WORK/probe.c"
+configure   gcc "$WORK/probe.c" -lspsprobe -o "$WORK/probe"
+configure   "$WORK/probe"
+install     mkdir -p "$PKG/usr/share/target-runtime-lib-probe" "$PKG/usr/bin"
+install     cp "$WORK/ldpath" "$WORK/targetld" "$PKG/usr/share/target-runtime-lib-probe/"
+install     cp "$WORK/probe" "$PKG/usr/bin/target-runtime-lib-probe"
+install     chmod 755 "$PKG/usr/bin/target-runtime-lib-probe"
+EOF
+	run_artifact=$(run_mkpkg --no-download --output "$tmp/run-out" \
+		"$tmp/run-recipe/recipe") ||
+		fail "target-root runtime library probe failed (just-built binaries must load SPS_ROOT libs)"
+	mkdir "$tmp/run-extract"
+	tar -xf "$run_artifact" -C "$tmp/run-extract"
+	case "$(cat "$tmp/run-extract/usr/share/target-runtime-lib-probe/ldpath")" in
+		"$tmp/root/usr/lib64:"*) : ;;
+		*) fail "LD_LIBRARY_PATH did not start with the target libdir" ;;
+	esac
+	assert_equal "$tmp/root/usr/lib64:$tmp/root/usr/lib:$tmp/root/lib64:$tmp/root/lib" \
+		"$(cat "$tmp/run-extract/usr/share/target-runtime-lib-probe/targetld")" \
+		"SPS_TARGET_LIBRARY_PATH was not the target libdirs"
+	[ -x "$tmp/run-extract/usr/bin/target-runtime-lib-probe" ] ||
+		fail "runtime probe binary was not staged"
 fi
 
 printf '%s\n' 'test_build: ok'
diff --git a/tests/test_mkiso.sh b/tests/test_mkiso.sh
index d058c2a..4047d3f 100755
--- a/tests/test_mkiso.sh
+++ b/tests/test_mkiso.sh
@@ -241,6 +241,10 @@ grep -q 'copying disk tools for setup' "$mkiso" ||
 	fail 'mkiso must copy partition tools by command name'
 grep -q grub-install "$mkiso" ||
 	fail 'mkiso must copy grub-install by command name for setup'
+grep -q efibootmgr "$mkiso" ||
+	fail 'mkiso must copy efibootmgr by command name for EFI NVRAM'
+grep -q /usr/sbin/efibootmgr "$project_dir/lib/mkiso/seed-bins" ||
+	fail 'seed-bins must list efibootmgr'
 grep -q 'system-local.conf' "$mkiso" ||
 	fail 'mkiso must bake a live D-Bus system-local.conf'
 grep -q '<user>root</user>' "$project_dir/lib/mkiso/live-plasma" ||
@@ -349,6 +353,10 @@ grep -q 'using .* for headers, libraries, and pkg-config' "$project_dir/bin/mkpk
 	fail 'mkpkg must compile against SPS_ROOT so setup can link target libs'
 grep -q write_cc_wrapper "$project_dir/bin/mkpkg" ||
 	fail 'mkpkg must wrap gcc so autoconf finds libraries in SPS_ROOT'
+grep -q SPS_HOST_LD_LIBRARY_PATH "$project_dir/bin/mkpkg" ||
+	fail 'mkpkg must keep host gcc from loading SPS_ROOT via LD_LIBRARY_PATH'
+grep -q SPS_TARGET_LIBRARY_PATH "$project_dir/bin/mkpkg" ||
+	fail 'mkpkg must put SPS_ROOT on LD_LIBRARY_PATH for just-built test programs'
 grep -q CONFIG_SITE "$project_dir/bin/mkpkg" ||
 	fail 'mkpkg must export CONFIG_SITE so autoconf sees SPS_ROOT LDFLAGS'
 grep -q 'sps_say "unpacking' "$project_dir/bin/pkin" ||
diff --git a/tests/test_setup.sh b/tests/test_setup.sh
index d3528e8..b1b3bca 100755
--- a/tests/test_setup.sh
+++ b/tests/test_setup.sh
@@ -281,6 +281,12 @@ st=$?
 set -e
 [ "$st" -eq 2 ] || fail "--install-bootloader without --disk returned $st"
 contains "$(cat "$tmp/err")" '--disk'
+grep -q -- '--removable' "$setup" ||
+	fail 'EFI grub-install must write EFI/BOOT/BOOTX64.EFI'
+grep -q -- '--no-nvram' "$setup" ||
+	fail 'EFI removable grub-install must not require firmware NVRAM'
+grep -q efibootmgr "$setup" ||
+	fail 'EFI grub-install must use efibootmgr when it is on PATH'
 
 set +e
 "$setup" --non-interactive --no-update --target "$tmp/noformat" \