cd: bundle all runtime dylibs on Windows/macOS; version from workspace

Windows: tooling/package/bundle-dylibs-windows.sh collects the MSYS2
runtime DLLs (libstdc++, libgcc, OpenColorIO, ...) with ntldd -R,
iterated to a fixpoint over freshly copied DLLs; a packager resources
glob places them next to the executables in the NSIS installer.

macOS: tooling/package/bundle-dylibs-macos.sh copies every non-system
dylib otool reports into Contents/Frameworks, rewrites the install
names to @executable_path/../Frameworks to a fixpoint, and ad-hoc
re-signs every modified Mach-O (rewriting invalidates the seal).

The CD package version no longer comes from the git tag: the root
Cargo.toml gains [workspace.package] version = "0.5.0", the oak
package inherits it (version.workspace = true — which cargo-packager
also picks up), and the Linux container packaging parses that field.
This commit is contained in:
2026-08-21 12:53:24 +08:00
parent 498669509a
commit d9dc16ec26
4 changed files with 182 additions and 6 deletions
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
# Oak Video Editor - Non-Linear Video Editor
# Copyright (C) 2026 Oak Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Bundle every non-system dynamic library an .app depends on into
# Contents/Frameworks and rewrite the install names to
# @executable_path/../Frameworks, so the app runs on machines without
# Homebrew. (FFmpeg/OCIO are already static; what remains are the
# Homebrew codec/filter dylibs the static FFmpeg references.)
#
# System libraries (/usr/lib, /System) are never copied. The set is
# computed to a fixpoint: freshly copied dylibs can themselves reference
# further non-system dylibs. @executable_path resolves to Contents/MacOS
# even when the reference lives in a Frameworks dylib, so one rewrite
# pattern fits both the executables and the libraries.
#
# Every modified Mach-O is ad-hoc re-signed afterwards: rewriting install
# names invalidates the code signature, and unsigned-but-damaged binaries
# are killed at launch on Apple Silicon.
#
# Usage: tooling/package/bundle-dylibs-macos.sh path/to/Oak.app
set -euo pipefail
APP="${1:?usage: bundle-dylibs-macos.sh path/to/Oak.app}"
MACOS_DIR="$APP/Contents/MacOS"
FW_DIR="$APP/Contents/Frameworks"
[ -d "$MACOS_DIR" ] || { echo "$APP: no Contents/MacOS directory" >&2; exit 1; }
mkdir -p "$FW_DIR"
is_system() {
case "$1" in
/usr/lib/*|/System/*|@*) return 0 ;;
*) return 1 ;;
esac
}
# Rewrite every non-system reference of the Mach-O file $1 to
# @executable_path/../Frameworks, copying the target in when new.
collect() {
local file="$1" dep base
otool -L "$file" | awk 'NR>1 {print $1}' | while read -r dep; do
is_system "$dep" && continue
[ -f "$dep" ] || continue
base=$(basename "$dep")
if [ ! -f "$FW_DIR/$base" ]; then
cp -L "$dep" "$FW_DIR/$base" # -L: follow Homebrew's symlinks
chmod u+w "$FW_DIR/$base"
echo "bundled $base"
fi
install_name_tool -change "$dep" "@executable_path/../Frameworks/$base" "$file"
done
}
# Fixpoint over the executables plus whatever the previous round copied.
prev=-1
for round in 1 2 3 4 5; do
count=$(find "$FW_DIR" -name '*.dylib' | wc -l | tr -d ' ')
[ "$count" = "$prev" ] && break
prev=$count
for f in "$MACOS_DIR"/*; do
[ -f "$f" ] && collect "$f"
done
for f in "$FW_DIR"/*.dylib; do
[ -f "$f" ] && collect "$f"
done
done
# Re-sign: install_name_tool invalidates the seal. Per-file signing
# instead of `codesign --deep` (deprecated and unreliable with dylibs).
find "$FW_DIR" "$MACOS_DIR" -type f -exec codesign --force --sign - {} \;
codesign --force --sign - "$APP"
echo "bundled $prev dylibs into $FW_DIR"
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Oak Video Editor - Non-Linear Video Editor
# Copyright (C) 2026 Oak Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Collect every MSYS2/MinGW runtime DLL the given executables depend on
# into a staging directory. cargo packager's NSIS/WiX resources then
# place them next to the .exe — the first place Windows resolves DLLs
# from — so the installer works on machines without MSYS2.
#
# ntldd -R already recurses through a binary's own dependency tree; the
# outer loop reaches the fixpoint for DLLs copied in earlier rounds (a
# freshly copied DLL can itself reference further MSYS2 DLLs that the
# initial scan did not surface through the executables alone).
# C:\Windows\System32 entries are filtered out by the mingw/ucrt/clang
# path match — only the toolchain runtime lands in the package.
#
# Must run inside the MSYS2 UCRT64 shell with
# mingw-w64-ucrt-x86_64-ntldd installed.
#
# Usage: tooling/package/bundle-dylibs-windows.sh <out-dir> <exe>...
set -euo pipefail
OUT="${1:?usage: bundle-dylibs-windows.sh <out-dir> <exe>...}"
shift
[ "$#" -ge 1 ] || { echo "no executables given" >&2; exit 1; }
mkdir -p "$OUT"
if ! command -v ntldd >/dev/null; then
echo "ntldd not found; install with: pacman -S mingw-w64-ucrt-x86_64-ntldd" >&2
exit 1
fi
for round in 1 2 3 4 5; do
changed=0
# shellcheck disable=SC2046
while IFS= read -r dep; do
[ -n "$dep" ] || continue
unix_dep=$(cygpath -u "$dep")
base=$(basename "$unix_dep")
if [ ! -f "$OUT/$base" ]; then
cp -v "$unix_dep" "$OUT/$base"
changed=1
fi
done < <(ntldd -R "$@" $(ls "$OUT"/*.dll 2>/dev/null) 2>/dev/null \
| grep -E 'mingw|ucrt|clang' | cut -d'>' -f2 | cut -d' ' -f2 | sort -u)
[ "$changed" = 1 ] || break
done
echo "bundled $(ls "$OUT" | wc -l | tr -d ' ') DLLs into $OUT"