Files
wiicompiled/Launcher/Prepare-NativePrebuilt.sh
T
theofficialgman 6eba523d70 Switch back to LLVM 22 so build can succeed on at least some systems (#141)
two upstream LLVM bugs currently prevent building on some of the newest distros. There is no current LLVM release that works on them so we are pending fixes from LLVM
https://github.com/patchzyy/Wiicompiled/issues/136
2026-09-05 10:17:21 +02:00

591 lines
28 KiB
Bash
Executable File

#!/usr/bin/env bash
# Builds the redistributable precompiled aurora + third-party package for native Linux: aurora
# (~43% of local build CPU time per Prepare-NativePrebuilt.ps1) and vendored Crypto++ are identical
# for every user under the pinned toolchain prepare-portable-tools.sh bundles, so this configures
# runtime/ against that toolchain, builds just that closure, and harvests the archives plus a
# generated CMake description into an output package - the Linux counterpart to
# Launcher/Prepare-NativePrebuilt.ps1, consumed by the same platform-agnostic
# runtime/cmake/NativePrebuilt.cmake either script's package works with unmodified.
#
# Not a byte-for-byte port of the Windows script: Linux needs no offline pinned dependency cache.
# Every FetchContent dependency in aurora-main/extern/CMakeLists.txt is a fixed-version URL already
# (verified directly), and aurora-main/CMakeLists.txt's own _default_linkage is "static" on any
# non-Windows platform. Windows pins Launcher/artifacts/dependencies because its installer ships
# pre-fetched sources to end users for a fully offline build; this harvest only ever runs on a
# maintainer's own machine (network access needed once, here, not shipped to anyone), so a plain
# networked configure is exactly as reproducible - what actually makes the harvested archives safe
# to link into any consumer's own build is the pinned compiler below, not an offline source cache.
set -euo pipefail
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
workspace=$(cd "$script_dir/.." && pwd)
arch=""
output_dir=""
stage_dir="$workspace/build/native-prebuilt-stage"
keep_stage=0
reuse_stage=0
parallel=0
print_fingerprint_only=0
usage() {
cat <<'EOF'
Usage: Prepare-NativePrebuilt.sh --arch {x86_64|aarch64} [options]
--arch ARCH Target architecture; selects the matching bundled toolchain (required)
--output-dir DIR Where the package is written (default: Launcher/artifacts/native-prebuilt-ARCH)
--stage-dir DIR Staging build directory (default: build/native-prebuilt-stage)
--keep-stage Do not delete the staging build directory afterward
--reuse-stage Reuse an existing staging build directory (maintainer iteration aid: a
re-harvest does not recompile aurora from scratch)
--parallel N Ninja build parallelism (default: nproc)
--print-fingerprint-only Print the four provenance inputs (compiler_sha256, flag_fingerprint,
aurora_fingerprint, third_party_fingerprint) as "key=value" lines and
exit, without configuring/building/harvesting anything - lets a caller
(build-appimage.sh) decide whether an existing package is still current
without paying for a full aurora rebuild just to find out.
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--arch) arch=$2; shift 2 ;;
--output-dir) output_dir=$2; shift 2 ;;
--stage-dir) stage_dir=$2; shift 2 ;;
--keep-stage) keep_stage=1; shift ;;
--reuse-stage) reuse_stage=1; shift ;;
--parallel) parallel=$2; shift 2 ;;
--print-fingerprint-only) print_fingerprint_only=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Prepare-NativePrebuilt.sh: unknown argument: $1" >&2; exit 1 ;;
esac
done
case "$arch" in
x86_64|aarch64) ;;
*) echo "Prepare-NativePrebuilt.sh: --arch must be x86_64 or aarch64" >&2; usage; exit 1 ;;
esac
fail() { echo "Prepare-NativePrebuilt.sh: error: $*" >&2; exit 1; }
assert_file() { [[ -f "$1" ]] || fail "$2 is missing: $1"; }
assert_dir() { [[ -d "$1" ]] || fail "$2 is missing: $1"; }
sha256_of() { sha256sum "$1" | awk '{print $1}'; }
normalize() { readlink -f "$1"; }
[[ -n "$output_dir" ]] || output_dir="$script_dir/artifacts/native-prebuilt-$arch"
[[ "$stage_dir" = /* ]] || stage_dir="$workspace/$stage_dir"
toolchain_dir="$script_dir/artifacts/portable-tools/toolchain-$arch"
cc="$toolchain_dir/bin/clang"
cxx="$toolchain_dir/bin/clang++"
cmake_bin="$toolchain_dir/bin/cmake"
ninja_bin="$toolchain_dir/bin/ninja"
runtime_source="$workspace/runtime"
aurora_source="$workspace/aurora-main"
assert_file "$cmake_bin" "Portable CMake (run prepare-portable-tools.sh --arch $arch first)"
assert_file "$ninja_bin" "Portable Ninja"
assert_file "$cc" "Portable C compiler"
assert_file "$cxx" "Portable C++ compiler"
assert_dir "$aurora_source" "aurora-main source tree"
clang_binary=$(normalize "$toolchain_dir/bin/clang-22")
assert_file "$clang_binary" "Portable clang driver binary"
(( parallel > 0 )) || parallel=$(nproc)
fingerprint_tree() {
# $1 = root dir, remaining args = top-level subdirectory names to exclude
local root=$1; shift
root=$(normalize "$root")
[[ -d "$root" ]] || return 0
local find_args=("$root")
local ex
for ex in "$@"; do find_args+=(-path "$root/$ex" -prune -o); done
find_args+=(-type f -print)
find "${find_args[@]}" | LC_ALL=C sort | while IFS= read -r abs; do
printf '%s %s\n' "${abs#$root/}" "$(sha256_of "$abs")"
done | sha256sum | awk '{print $1}'
}
# The fixed (path-independent) half of the configure command line - identical for every
# harvest, which is what lets one package be valid regardless of where it was built.
# -DBUILD_SHARED_LIBS=OFF: aurora-main/extern/CMakeLists.txt derives its own _USE_SHARED from
# whether BUILD_SHARED_LIBS is *defined at all* (not its value), so leaving it unset would default
# zlib/libpng to shared. -DAURORA_SDL3_PROVIDER=vendor: without it, "auto" resolves to "system" on
# any machine that happens to have an SDL3 dev package installed. -DCMAKE_DISABLE_FIND_PACKAGE_*:
# absl/PNG/Freetype each call find_package() unconditionally, with no provider flag to gate them
# (unlike SDL3/Dawn) - verified directly that this machine's system libpng-dev/freetype-dev get
# linked in shared instead of the pinned vendored source otherwise. Disabling find_package for
# these three forces the same FetchContent-vendored, statically-built result regardless of what a
# given maintainer's machine happens to have installed. ZLIB is deliberately NOT disabled the same
# way: libpng's own vendored CMakeLists.txt calls find_package(ZLIB REQUIRED) internally even when
# zlib came from aurora's own FetchContent (extern/CMakeLists.txt writes a redirect config for
# exactly this), and CMAKE_DISABLE_FIND_PACKAGE_ZLIB errors out on any REQUIRED call site outright
# (verified directly) - it cannot be scoped to only aurora's own initial, non-required check.
# Dawn stays a prebuilt package regardless (Linux x86_64/aarch64 always auto-resolve to "package" -
# see AuroraDawnProvider.cmake).
fixed_configure_flags=(
-DCMAKE_BUILD_TYPE=Release
-DBUILD_SHARED_LIBS=OFF
-DAURORA_SDL3_PROVIDER=vendor
-DCMAKE_DISABLE_FIND_PACKAGE_absl=ON
-DCMAKE_DISABLE_FIND_PACKAGE_PNG=ON
-DCMAKE_DISABLE_FIND_PACKAGE_Freetype=ON
# Freetype's own vendored CMakeLists.txt separately probes for system BZip2 (optional
# bzip2-compressed-font support aurora-main never asked for) regardless of the Freetype
# find_package disable above, since that only stops aurora's own outer find_package(Freetype)
# from picking up a system Freetype - it does not reach into the FetchContent-built copy's own
# internal find_package(BZip2) call. FT_DISABLE_BZIP2 is Freetype's own documented flag for
# exactly this (verified in its CMakeLists.txt), unlike the ZLIB/libpng situation where no such
# source-level flag exists.
-DFT_DISABLE_BZIP2=ON
-DCMAKE_POLICY_DEFAULT_CMP0168=NEW
)
flag_fingerprint=$(printf '%s\n' "${fixed_configure_flags[@]}" | sha256sum | awk '{print $1}')
# extern/ is excluded because the payload ships that tree separately (aurora-main/extern is bundled
# whole by build-appimage.sh); build/ is a plain developer build directory.
aurora_fingerprint=$(fingerprint_tree "$aurora_source" extern build)
[[ -n "$aurora_fingerprint" ]] || fail "The aurora source tree could not be fingerprinted: $aurora_source"
# The harvested Crypto++ archive is consumed against this tree's headers, so it is fingerprinted
# for the same reason as aurora above. No exclusions: unlike aurora's extern/, nothing under
# runtime/third_party is shipped separately.
third_party_fingerprint=$(fingerprint_tree "$runtime_source/third_party")
[[ -n "$third_party_fingerprint" ]] || fail "The vendored third-party tree could not be fingerprinted: $runtime_source/third_party"
compiler_sha256=$(sha256_of "$clang_binary")
if [[ "$print_fingerprint_only" -eq 1 ]]; then
printf 'compiler_sha256=%s\n' "$compiler_sha256"
printf 'flag_fingerprint=%s\n' "$flag_fingerprint"
printf 'aurora_fingerprint=%s\n' "$aurora_fingerprint"
printf 'third_party_fingerprint=%s\n' "$third_party_fingerprint"
exit 0
fi
# The package must never contain a stale mixture of two builds.
rm -rf "$output_dir"
mkdir -p "$output_dir/lib" "$output_dir/bin" "$output_dir/include"
# The staging build has to be configured without the package present, otherwise the runtime would
# consume the very package this script is producing.
if [[ "$reuse_stage" -eq 0 ]]; then rm -rf "$stage_dir"; fi
export_dir="$stage_dir/export"
mkdir -p "$export_dir"
# fixed_configure_flags/flag_fingerprint were already computed above (needed before the
# --print-fingerprint-only early exit).
echo "Prepare-NativePrebuilt.sh: configuring the aurora/third-party staging build..."
"$cmake_bin" -S "$runtime_source" -B "$stage_dir" -G Ninja \
"${fixed_configure_flags[@]}" \
-DCMAKE_C_COMPILER="$cc" -DCMAKE_CXX_COMPILER="$cxx" \
-DCMAKE_MAKE_PROGRAM="$ninja_bin" \
-DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \
-DMKW_NATIVE_PREBUILT_EXPORT_DIR="$export_dir"
# mkw_np_probe links exactly what mkw_runtime_common and the public products link, so building it
# compiles the whole redistributable closure and nothing else - and a successful link proves the
# harvested archives are complete.
echo "Prepare-NativePrebuilt.sh: building the aurora/third-party closure..."
"$cmake_bin" --build "$stage_dir" --target mkw_np_probe --parallel "$parallel"
# ---------------------------------------------------------------------------
# Read the description CMake wrote, plus the resolved command lines Ninja holds.
# ---------------------------------------------------------------------------
meta_path="$export_dir/meta.txt"
assert_file "$meta_path" "Native prebuilt export metadata"
get_meta() { awk -F= -v k="$1" '$0 ~ "^" k "=" { sub(/^[^=]*=/, ""); print; exit }' "$meta_path"; }
build_ninja="$stage_dir/build.ninja"
assert_file "$build_ninja" "Generated build.ninja"
extract_ninja_vars() {
# $1 = ninja file, $2 = exact rule name. Prints "KEY\tVALUE" for every " KEY = VALUE" line
# following the first "build ...: RULE ..." statement that uses that rule.
awk -v rule="$2" '
BEGIN { in_stmt = 0 }
/^build / {
if (in_stmt) exit
colon = index($0, ": ")
if (colon == 0) next
rest = substr($0, colon + 2)
sp = index(rest, " ")
stmt_rule = (sp > 0) ? substr(rest, 1, sp - 1) : rest
if (stmt_rule == rule) in_stmt = 1
next
}
in_stmt {
if (substr($0, 1, 2) != " ") exit
line = substr($0, 3)
eq = index(line, " = ")
if (eq == 0) exit
print substr(line, 1, eq - 1) "\t" substr(line, eq + 3)
}
' "$1"
}
declare -A probe_compile=() control_compile=() probe_link=() control_link=()
load_vars() {
local -n dest=$1
local k v
while IFS=$'\t' read -r k v; do dest["$k"]=$v; done < <(extract_ninja_vars "$build_ninja" "$2")
}
load_vars probe_compile "CXX_COMPILER__mkw_np_probe_unscanned_Release"
load_vars control_compile "CXX_COMPILER__mkw_np_probe_control_unscanned_Release"
load_vars probe_link "CXX_EXECUTABLE_LINKER__mkw_np_probe_Release"
load_vars control_link "CXX_EXECUTABLE_LINKER__mkw_np_probe_control_Release"
[[ -n "${probe_compile[INCLUDES]+x}" ]] || fail "No Ninja statement used rule CXX_COMPILER__mkw_np_probe_unscanned_Release."
[[ -n "${probe_link[LINK_LIBRARIES]+x}" ]] || fail "No Ninja statement used rule CXX_EXECUTABLE_LINKER__mkw_np_probe_Release."
split_list() {
# $1 = string value, $2 = name of the array to fill (nameref)
local -n out=$2
out=()
[[ -n "$1" ]] || return 0
read -ra out <<< "$1"
}
subtract_multiset() {
# $1 = "all" array name, $2 = "remove" array name, $3 = result array name (all namerefs)
local -n all_ref=$1 remove_ref=$2 result_ref=$3
local -A pending=()
local item
for item in "${remove_ref[@]}"; do
pending["$item"]=$(( ${pending["$item"]:-0} + 1 ))
done
result_ref=()
for item in "${all_ref[@]}"; do
if [[ "${pending["$item"]:-0}" -gt 0 ]]; then
pending["$item"]=$(( pending["$item"] - 1 ))
continue
fi
result_ref+=("$item")
done
}
split_list "${probe_compile[INCLUDES]:-}" _probe_includes
split_list "${control_compile[INCLUDES]:-}" _control_includes
subtract_multiset _probe_includes _control_includes include_arguments
split_list "${probe_compile[DEFINES]:-}" _probe_defines
split_list "${control_compile[DEFINES]:-}" _control_defines
subtract_multiset _probe_defines _control_defines define_arguments
split_list "${probe_compile[FLAGS]:-}" _probe_flags
split_list "${control_compile[FLAGS]:-}" _control_flags
subtract_multiset _probe_flags _control_flags compile_options_raw
split_list "${probe_link[LINK_LIBRARIES]:-}" _probe_link
split_list "${control_link[LINK_LIBRARIES]:-}" _control_link
subtract_multiset _probe_link _control_link link_items
[[ ${#include_arguments[@]} -gt 0 ]] || fail "The aurora compile interface is empty; the probe did not link aurora."
[[ ${#link_items[@]} -gt 0 ]] || fail "The aurora link interface is empty; the probe did not link aurora."
# ---------------------------------------------------------------------------
# Harvest the built libraries.
# ---------------------------------------------------------------------------
binary_root=$(normalize "$stage_dir")
aurora_root=$(normalize "$(get_meta aurora_dir)")
runtime_root=$(normalize "$(get_meta runtime_dir)")
generated_include_index=0
copy_harvested() {
# $1 = source path, $2 = subdirectory under the package. Echoes "subdir/name".
local source=$1 subdir=$2
local name destination
name=$(basename "$source")
destination="$output_dir/$subdir/$name"
[[ ! -e "$destination" ]] || fail "Two harvested files collide on the name $name: $source"
cp "$source" "$destination"
printf '%s/%s' "$subdir" "$name"
}
declare -A generated_include_tokens=()
convert_to_token() {
# $1 = absolute path, $2 = 'include' or another kind. Sets $TOKEN_RESULT - NOT echoed/command-
# substituted: this needs to mutate generated_include_tokens/generated_include_index, and a
# $(...) call runs in a subshell, silently discarding that mutation once it returns (verified
# directly: every build-tree include directory collided into the same "generated01" until this
# was written this way instead).
local path kind=$2
path=$(normalize "$1")
case "$path" in
"$aurora_root"/*) TOKEN_RESULT="@AURORA@/${path#$aurora_root/}"; return ;;
"$runtime_root"/*) TOKEN_RESULT="@RUNTIME@/${path#$runtime_root/}"; return ;;
"$binary_root"/*)
[[ "$kind" == include ]] || fail "Unhandled build-tree artifact: $path"
if [[ -n "${generated_include_tokens[$path]:-}" ]]; then
TOKEN_RESULT=${generated_include_tokens[$path]}
return
fi
generated_include_index=$((generated_include_index + 1))
local name destination
name=$(printf 'generated%02d' "$generated_include_index")
destination="$output_dir/include/$name"
mkdir -p "$destination"
cp -a "$path/." "$destination/"
TOKEN_RESULT="@PKG@/include/$name"
generated_include_tokens[$path]=$TOKEN_RESULT
return ;;
*) fail "Path escapes every shippable root ($kind): $path" ;;
esac
}
declare -A linker_file_to_reference=()
shared_import_targets=() shared_import_runtime=() shared_import_implib=()
targets_txt="$export_dir/targets.txt"
assert_file "$targets_txt" "Native prebuilt export targets list"
while IFS='|' read -r name type file linkerfile; do
[[ -n "$name" ]] || continue
[[ -f "$linkerfile" ]] || continue # not part of the closure mkw_np_probe pulled in
linkerfile=$(normalize "$linkerfile")
relative_linker=$(copy_harvested "$linkerfile" lib)
if [[ "$type" == "SHARED_LIBRARY" ]]; then
file_abs=$(normalize "$file")
# Unlike Windows (a .dll + a separate .dll.a import library), a Linux shared object's
# TARGET_FILE and TARGET_LINKER_FILE are the same path - one file, harvested once.
if [[ "$file_abs" == "$linkerfile" ]]; then
relative_runtime=$relative_linker
else
[[ -f "$file_abs" ]] || fail "Shared library $name has no runtime file: $file_abs"
relative_runtime=$(copy_harvested "$file_abs" bin)
fi
shared_import_targets+=("mkw_np::$name")
shared_import_runtime+=("$relative_runtime")
shared_import_implib+=("$relative_linker")
linker_file_to_reference["$linkerfile"]="mkw_np::$name"
else
linker_file_to_reference["$linkerfile"]="@PKG@/$relative_linker"
fi
done < "$targets_txt"
# Unlike Windows (SDL/zlib/libpng ship as DLLs by default), everything here was forced static above
# and Dawn's own Linux package (verified directly) ships libwebgpu_dawn.a, also static - so zero
# shared imports is the expected, normal outcome, not a failure.
echo "Prepare-NativePrebuilt.sh: harvested ${#linker_file_to_reference[@]} archive(s) (${#shared_import_targets[@]} shared)"
dawn_linker_file="" dawn_runtime_file=""
dawn_txt="$export_dir/dawn.txt"
if [[ -s "$dawn_txt" ]]; then
IFS='|' read -r _ dawn_runtime_file dawn_linker_file < "$dawn_txt"
dawn_runtime_file=$(normalize "$dawn_runtime_file")
dawn_linker_file=$(normalize "$dawn_linker_file")
fi
[[ -n "$dawn_linker_file" ]] && linker_file_to_reference["$dawn_linker_file"]="dawn::webgpu_dawn"
# ---------------------------------------------------------------------------
# Rewrite the compile/link interface into workspace-relative tokens.
# ---------------------------------------------------------------------------
package_include_dirs=()
include_count=${#include_arguments[@]}
i=0
while (( i < include_count )); do
entry=${include_arguments[i]}
case "$entry" in
-I*) convert_to_token "${entry#-I}" include; package_include_dirs+=("$TOKEN_RESULT") ;;
-isystem)
i=$((i + 1))
(( i < include_count )) || fail "Trailing -isystem with no argument"
convert_to_token "${include_arguments[i]}" include; package_include_dirs+=("$TOKEN_RESULT") ;;
-isystem*) convert_to_token "${entry#-isystem}" include; package_include_dirs+=("$TOKEN_RESULT") ;;
*) fail "Unexpected include argument: $entry" ;;
esac
i=$((i + 1))
done
package_definitions=()
for entry in "${define_arguments[@]}"; do
case "$entry" in
# Ninja records a quoted define's value with its quotes backslash-escaped (verified
# directly: IMGUI_USER_CONFIG=\"aurora/imgui_config.h\" in build.ninja) regardless of
# platform - format_cmake_block below re-escapes for CMake's own string syntax, so the
# literal backslash has to come out here first or the result is double-escaped and the
# define expands to literal backslash-quote characters instead of a quoted string.
-D*) package_definitions+=("${entry#-D}") ;;
*) fail "Unexpected define argument: $entry" ;;
esac
done
package_definitions=("${package_definitions[@]//\\\"/\"}")
# fmt's `-include cstdlib` (and anything like it) is recorded from a C++ compile line, so re-scope
# it to C++. The runtime also assembles generated .S blobs through the same targets, and a forced
# C++ header include would break them.
package_compile_options=()
for entry in "${compile_options_raw[@]}"; do
package_compile_options+=("\$<\$<COMPILE_LANGUAGE:CXX>:$entry>")
done
package_link_items=()
for item in "${link_items[@]}"; do
case "$item" in
-*) package_link_items+=("$item"); continue ;;
esac
if [[ "$item" = /* ]]; then item_abs=$(normalize "$item"); else item_abs=$(normalize "$stage_dir/$item"); fi
ref=${linker_file_to_reference["$item_abs"]:-}
if [[ -n "$ref" ]]; then
package_link_items+=("$ref")
continue
fi
case "$item_abs" in
*/libz.so*)
# The one unavoidable system reference: libpng's own vendored CMakeLists.txt calls
# find_package(ZLIB REQUIRED) internally even when zlib came from aurora's own
# FetchContent (extern/CMakeLists.txt writes a redirect config for exactly this case),
# and CMAKE_DISABLE_FIND_PACKAGE_ZLIB errors out on any REQUIRED call site outright
# (verified directly), so it cannot be forced to vendor/static the way absl/PNG/Freetype
# are above. zlib is as close to a universal baseline as a Linux shared library gets
# (glibc-adjacent - practically every distro has it already), so this is recorded as a
# portable `-lz` link flag instead of the harvesting machine's absolute path.
package_link_items+=("-lz")
continue ;;
esac
fail "Link item is neither a system library nor a harvested archive: $item"
done
# ---------------------------------------------------------------------------
# Emit the consumer-facing CMake description.
# ---------------------------------------------------------------------------
format_cmake_block() {
# $1 = CMake variable name, remaining args = list items
local name=$1; shift
if [[ $# -eq 0 ]]; then
printf 'set(%s "")\n' "$name"
return
fi
printf 'set(%s\n' "$name"
local item escaped
for item in "$@"; do
escaped=${item//\\/\\\\}
escaped=${escaped//\"/\\\"}
printf ' "%s"\n' "$escaped"
done
printf ')\n'
}
dawn_config_dir_meta=$(get_meta dawn_config_dir)
dawn_config_token=""
if [[ -n "$dawn_config_dir_meta" ]]; then
dawn_config_dir_abs=$(normalize "$dawn_config_dir_meta")
case "$dawn_config_dir_abs" in
"$binary_root"/*)
# Dawn's find_package() config directory (lib/cmake/Dawn under its own fetched package
# root) cannot go through the generic single-directory copy other build-tree artifacts
# use: DawnConfig.cmake/DawnTargets.cmake derive _IMPORT_PREFIX/PACKAGE_PREFIX_DIR from
# their OWN file location by walking up three parent directories (verified directly), so
# the whole package root - include/, lib/, lib/cmake/Dawn/ together - must be copied as
# one self-contained unit for that relative navigation to still resolve once moved.
dawn_package_root=$(normalize "$dawn_config_dir_abs/../../..")
dawn_config_relative=${dawn_config_dir_abs#$dawn_package_root/}
mkdir -p "$output_dir/include/dawn_package"
cp -a "$dawn_package_root/." "$output_dir/include/dawn_package/"
dawn_config_token="@PKG@/include/dawn_package/$dawn_config_relative"
;;
*) convert_to_token "$dawn_config_dir_abs" include; dawn_config_token=$TOKEN_RESULT ;;
esac
fi
generated_cmake="$output_dir/native_prebuilt.cmake"
{
echo "# Generated by Launcher/Prepare-NativePrebuilt.sh - do not edit."
echo "#"
echo "# Describes the precompiled aurora + third-party archives that replace a"
echo "# from-source aurora-main build. Every path is a token resolved against the"
echo "# consuming workspace, because the source trees still ship next to this"
echo "# package and the runtime compiles against their headers."
echo ""
echo 'if(NOT MKW_NP_PACKAGE_DIR OR NOT MKW_NP_AURORA_DIR OR NOT MKW_NP_RUNTIME_DIR OR NOT MKW_NP_DEPS_DIR)'
echo ' message(FATAL_ERROR "native_prebuilt.cmake must be included by runtime/cmake/NativePrebuilt.cmake")'
echo 'endif()'
echo ""
format_cmake_block MKW_NP_INCLUDE_DIRECTORIES "${package_include_dirs[@]}"
format_cmake_block MKW_NP_COMPILE_DEFINITIONS "${package_definitions[@]}"
format_cmake_block MKW_NP_COMPILE_OPTIONS "${package_compile_options[@]}"
format_cmake_block MKW_NP_LINK_LIBRARIES "${package_link_items[@]}"
format_cmake_block MKW_NP_AURORA_TARGETS "aurora::gx" "aurora::pad" "aurora::si" "aurora::vi" "aurora::mtx"
echo ""
printf 'set(MKW_NP_DAWN_CONFIG_DIR "%s")\n' "$dawn_config_token"
printf 'set(MKW_NP_DAWN_VERSION "%s")\n' "$(get_meta aurora_dawn_version)"
echo ""
echo "# Shared third-party libraries keep imported SHARED targets so that"
echo '# $<TARGET_RUNTIME_DLLS> still copies them next to the game executable.'
for idx in "${!shared_import_targets[@]}"; do
printf 'add_library(%s SHARED IMPORTED GLOBAL)\n' "${shared_import_targets[$idx]}"
printf 'set_target_properties(%s PROPERTIES\n' "${shared_import_targets[$idx]}"
printf ' IMPORTED_LOCATION "${MKW_NP_PACKAGE_DIR}/%s"\n' "${shared_import_runtime[$idx]}"
printf ' IMPORTED_IMPLIB "${MKW_NP_PACKAGE_DIR}/%s")\n' "${shared_import_implib[$idx]}"
done
} > "$generated_cmake"
# ---------------------------------------------------------------------------
# Provenance: the pinned toolchain is what makes a precompiled archive interchangeable with
# locally compiled objects (bit-for-bit the compiler and flag set the user's machine will use);
# LocalBuild.ps1's Windows equivalent re-checks both before consuming a package, and a Linux
# consumer-side check (once local-build.sh gains --native-prebuilt-dir) should do the same.
# compiler_sha256/flag_fingerprint/aurora_fingerprint/third_party_fingerprint were already computed
# above (needed before the --print-fingerprint-only early exit).
# ---------------------------------------------------------------------------
dawn_runtime_sha256=""
[[ -n "$dawn_runtime_file" && -f "$dawn_runtime_file" ]] && dawn_runtime_sha256=$(sha256_of "$dawn_runtime_file")
[[ -n "$dawn_runtime_sha256" ]] || fail "The Dawn runtime could not be hashed: $dawn_runtime_file"
compiler_version=$(get_meta cxx_compiler_version)
sdl3_target=$(get_meta aurora_sdl3_target)
dawn_version=$(get_meta aurora_dawn_version)
harvested_count=${#linker_file_to_reference[@]}
python3 - "$output_dir" "$compiler_sha256" "$compiler_version" "$flag_fingerprint" \
"$dawn_version" "$dawn_runtime_sha256" "$aurora_fingerprint" "$third_party_fingerprint" \
"$sdl3_target" "$harvested_count" <<'PY'
import hashlib, json, os, sys, datetime
(output_dir, compiler_sha256, compiler_version, flag_fingerprint, dawn_version,
dawn_runtime_sha256, aurora_fingerprint, third_party_fingerprint, sdl3_target,
harvested_count) = sys.argv[1:]
contents = []
for root, dirs, files in os.walk(output_dir):
dirs.sort()
for name in sorted(files):
if name == "provenance.json":
continue
path = os.path.join(root, name)
rel = os.path.relpath(path, output_dir).replace(os.sep, "/")
with open(path, "rb") as fh:
digest = hashlib.sha256(fh.read()).hexdigest()
contents.append({"Path": rel, "Bytes": os.path.getsize(path), "Sha256": digest})
contents.sort(key=lambda c: c["Path"])
provenance = {
"SchemaVersion": 1,
"BuiltUtc": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z",
"CompilerSha256": compiler_sha256,
"CompilerVersion": compiler_version,
"FlagFingerprint": flag_fingerprint,
"DawnVersion": dawn_version,
"DawnRuntimeSha256": dawn_runtime_sha256,
"AuroraSourceFingerprint": aurora_fingerprint,
"ThirdPartySourceFingerprint": third_party_fingerprint,
"Sdl3Target": sdl3_target,
"HarvestedLibraryCount": int(harvested_count),
"Contents": contents,
}
with open(os.path.join(output_dir, "provenance.json"), "w", encoding="utf-8") as fh:
json.dump(provenance, fh, indent=2)
fh.write("\n")
total_bytes = sum(c["Bytes"] for c in contents)
print(f" files: {len(contents)}; size: {total_bytes / (1024 * 1024):.1f} MiB")
PY
if [[ "$keep_stage" -eq 0 ]]; then rm -rf "$stage_dir"; fi
echo ""
echo "Native prebuilt package: $output_dir"
echo " archives: $(find "$output_dir/lib" -maxdepth 1 -type f | wc -l); shared imports: ${#shared_import_targets[@]}"
echo " flag fingerprint: $flag_fingerprint"