|
| 1 | +#!/usr/bin/env bash |
| 2 | +# requires: elf gcc |
| 3 | +# 251_pack_library_shared.sh — a `kind = "shared"` package carries BOTH of the |
| 4 | +# library's names, and a consumer can actually start. |
| 5 | +# |
| 6 | +# A shared library is LINKED by `lib<target>.so` and FOUND at run time by its |
| 7 | +# SONAME, and those are two different filenames. The first version of this |
| 8 | +# packer shipped only the built file: the consumer linked, and then mcpp's own |
| 9 | +# runtime-closure check reported |
| 10 | +# |
| 11 | +# libmathkit.so.1 not found on the search path this artifact will actually use |
| 12 | +# |
| 13 | +# which is the good outcome only because that check exists. Without it the |
| 14 | +# program would have failed to start with a loader error naming a file the user |
| 15 | +# never asked for. |
| 16 | +set -e |
| 17 | + |
| 18 | +TMP=$(mktemp -d) |
| 19 | +trap "rm -rf $TMP" EXIT |
| 20 | +cd "$TMP" |
| 21 | + |
| 22 | +mkdir -p mathkit/src |
| 23 | +cat > mathkit/src/mathkit.cppm <<'EOF' |
| 24 | +export module mathkit; |
| 25 | +export namespace mk { int answer(); } |
| 26 | +EOF |
| 27 | +cat > mathkit/src/impl.cpp <<'EOF' |
| 28 | +module mathkit; |
| 29 | +namespace mk { int answer() { return 42; } } |
| 30 | +EOF |
| 31 | +cat > mathkit/mcpp.toml <<'EOF' |
| 32 | +[package] |
| 33 | +name = "mathkit" |
| 34 | +version = "0.1.0" |
| 35 | +[build] |
| 36 | +sources = ["src/*.cppm", "src/*.cpp"] |
| 37 | +[targets.mathkit-shared] |
| 38 | +kind = "shared" |
| 39 | +soname = "libmathkit.so.1" |
| 40 | +EOF |
| 41 | + |
| 42 | +cd mathkit |
| 43 | +"$MCPP" pack mathkit-shared > pack.log 2>&1 || { cat pack.log; echo "shared pack failed"; exit 1; } |
| 44 | +pkg="$TMP/mathkit/$(find target/dist -maxdepth 1 -type d -name 'mathkit-0.1.0-*' | head -1)" |
| 45 | + |
| 46 | +libdir="$(dirname "$(find "$pkg/lib" -name 'libmathkit-shared.so' | head -1)")" |
| 47 | +[[ -n "$libdir" ]] || { echo "no .so in the package"; find "$pkg" -type f; exit 1; } |
| 48 | +# Both names. The SONAME one may be a symlink or a copy — either is fine, its |
| 49 | +# absence is not. |
| 50 | +[[ -e "$libdir/libmathkit.so.1" ]] || { |
| 51 | + echo "FAIL: the package does not carry the SONAME the loader will ask for" |
| 52 | + ls -l "$libdir"; exit 1; } |
| 53 | + |
| 54 | +# The manifest declares it as a shared library and gives a runtime search dir: |
| 55 | +# link_library_dirs is not rpath, and a shared package needs both. |
| 56 | +grep -q 'role *= *"shared-library"' "$pkg/mcpp.toml" || { |
| 57 | + cat "$pkg/mcpp.toml"; echo "artifact is not recorded as a shared library"; exit 1; } |
| 58 | +grep -q 'runtime_search_dirs' "$pkg/mcpp.toml" || { |
| 59 | + cat "$pkg/mcpp.toml"; echo "no runtime_search_dirs — the consumer could not find it"; exit 1; } |
| 60 | + |
| 61 | +cd "$TMP" |
| 62 | +mkdir -p app/src |
| 63 | +cat > app/src/main.cpp <<'EOF' |
| 64 | +#include <cstdio> |
| 65 | +import mathkit; |
| 66 | +int main(){ std::printf("ok=%d\n", mk::answer()); return 0; } |
| 67 | +EOF |
| 68 | +cat > app/mcpp.toml <<EOF |
| 69 | +[package] |
| 70 | +name = "app" |
| 71 | +version = "0.1.0" |
| 72 | +[dependencies] |
| 73 | +mathkit = { path = "$pkg" } |
| 74 | +[targets.app] |
| 75 | +kind = "bin" |
| 76 | +main = "src/main.cpp" |
| 77 | +EOF |
| 78 | + |
| 79 | +# `run`, not `build`: linking proves nothing here — the whole point is that the |
| 80 | +# process starts and the loader resolves the SONAME. |
| 81 | +( cd app && "$MCPP" run > run.log 2>&1 ) || { cat app/run.log; echo "consumer failed to run"; exit 1; } |
| 82 | +grep -q 'ok=42' app/run.log || { cat app/run.log; echo "wrong answer"; exit 1; } |
| 83 | + |
| 84 | +exe="$(find app/target -name app -type f | head -1)" |
| 85 | +readelf -d "$exe" 2>/dev/null | grep -q 'libmathkit.so.1' || { |
| 86 | + readelf -d "$exe"; echo "the consumer does not NEED the soname"; exit 1; } |
| 87 | + |
| 88 | +echo "PASS: a shared library package carries both names and the consumer starts" |
0 commit comments