feat(pkg): phase 15 - a package can carry a native library
native "<target>" "<path>" in a package's package.ludic; the compiler records the libraries of every package a program imports and writes them into the IR (; ludic-native:), so ludicc -o, ludic build, ludic test and ludic bundle all link one list. macOS: an rpath to the package and to Contents/Frameworks, where ludic bundle copies and signs each library and drops the build machine's rpath. Windows: the import library, the .dll copied beside the exe (--natives-out for the bundle). tools/native/lib.sh builds from a pinned, checksummed source with clang on both machines; ludic.nativeecho is the worked example; the shim rules are in packages/README.md. Linked at build time rather than dlopen (docs/PACKAGES.md says why). Reseeded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5df0747642
commit
5d3a799e33
25 changed files with 54474 additions and 51707 deletions
81
tools/native/lib.sh
Normal file
81
tools/native/lib.sh
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# tools/native/lib.sh - what every package's native/build.sh shares (phase 15). Sourced, not run.
|
||||
#
|
||||
# A native library is built here from a pinned source, never downloaded as a binary: the upstream
|
||||
# tag is fetched, its SHA-256 checked, and it and the package's shim compiled with clang into
|
||||
# lib/<target>/. The same script runs on the Mac (Terminal) and on the PC (Git Bash, with the LLVM
|
||||
# installer's clang), so there is one recipe per library, not two.
|
||||
set -eu
|
||||
|
||||
# macos-arm64, macos-x64, windows-x64 or linux-x64 - the names `native` lines use
|
||||
native_target() {
|
||||
if [ -n "${LUDIC_NATIVE_TARGET:-}" ]; then echo "$LUDIC_NATIVE_TARGET"; return; fi
|
||||
case "$(uname -s)" in
|
||||
Darwin) if [ "$(uname -m)" = arm64 ]; then echo macos-arm64; else echo macos-x64; fi ;;
|
||||
MINGW*|MSYS*|CYGWIN*) echo windows-x64 ;;
|
||||
*) echo linux-x64 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# the clang that builds: $LUDIC_CC, else clang on PATH, else the LLVM installer's on Windows
|
||||
native_cc() {
|
||||
if [ -n "${LUDIC_CC:-}" ]; then echo "$LUDIC_CC"; return; fi
|
||||
if command -v clang >/dev/null 2>&1; then echo clang; return; fi
|
||||
if [ -x "/c/Program Files/LLVM/bin/clang.exe" ]; then echo "/c/Program Files/LLVM/bin/clang.exe"; return; fi
|
||||
echo "native: no clang (set LUDIC_CC)" >&2; exit 1
|
||||
}
|
||||
native_cxx() {
|
||||
local cc; cc="$(native_cc)"
|
||||
case "$cc" in *clang.exe) echo "${cc%clang.exe}clang++.exe" ;; *clang) echo "${cc}++" ;; *) echo "$cc" ;; esac
|
||||
}
|
||||
|
||||
native_sha256() {
|
||||
if command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1
|
||||
else sha256sum "$1" | cut -d' ' -f1; fi
|
||||
}
|
||||
|
||||
# native_fetch <dir> <url> <sha256>: the archive at url, checked, unpacked into <dir> (its one
|
||||
# top-level directory stripped). A checksum that does not match stops the build.
|
||||
native_fetch() {
|
||||
local dir="$1" url="$2" want="$3"
|
||||
local tgz="$dir.tar.gz"
|
||||
mkdir -p "$(dirname "$dir")"
|
||||
if [ ! -f "$tgz" ]; then curl -fsSL "$url" -o "$tgz.part" && mv "$tgz.part" "$tgz"; fi
|
||||
local got; got="$(native_sha256 "$tgz")"
|
||||
if [ "$got" != "$want" ]; then
|
||||
echo "native: $url is $got, pinned $want" >&2; rm -f "$tgz"; exit 1
|
||||
fi
|
||||
if [ ! -d "$dir" ]; then
|
||||
mkdir -p "$dir.part" && tar -xzf "$tgz" -C "$dir.part" --strip-components 1 && mv "$dir.part" "$dir"
|
||||
fi
|
||||
}
|
||||
|
||||
# native_link <package dir> <name> <objects...>: lib<name>.dylib (install name @rpath, so the
|
||||
# executable finds it beside itself, in Contents/Frameworks or in lib/<target> while developing)
|
||||
# or <name>.dll with its import library <name>.lib, into <package>/lib/<target>/
|
||||
native_link() {
|
||||
local pkg="$1" name="$2"; shift 2
|
||||
local t; t="$(native_target)"
|
||||
local out="$pkg/lib/$t"
|
||||
mkdir -p "$out"
|
||||
local cxx; cxx="$(native_cxx)"
|
||||
case "$t" in
|
||||
macos-*)
|
||||
"$cxx" -dynamiclib -O2 -Wl,-install_name,@rpath/lib$name.dylib -Wl,-dead_strip "$@" -o "$out/lib$name.dylib"
|
||||
echo "native: $out/lib$name.dylib" ;;
|
||||
windows-*)
|
||||
"$cxx" -shared -O2 "$@" -o "$out/$name.dll" -Wl,/implib:"$out/$name.lib"
|
||||
echo "native: $out/$name.dll + $name.lib" ;;
|
||||
*)
|
||||
"$cxx" -shared -O2 -fPIC -Wl,-soname,lib$name.so "$@" -o "$out/lib$name.so"
|
||||
echo "native: $out/lib$name.so" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# the flags every object is compiled with: optimised, position independent, symbols hidden unless
|
||||
# the shim exports them
|
||||
native_cflags() {
|
||||
case "$(native_target)" in
|
||||
windows-*) echo "-O2" ;;
|
||||
*) echo "-O2 -fPIC -fvisibility=hidden" ;;
|
||||
esac
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue