File PKGBUILD of Package tools-fish_pgo
# Maintainer: neycrol <330578697@qq.com>
pkgname=fish-git-pgo-bolt
pkgver=4.2.1.r0.g53e6758cc3
pkgrel=17
pkgdesc="Fish Shell (Rust) - PGO + Fat LTO + Codegen=1 + BOLT Optimized"
arch=(x86_64)
url="https://fishshell.com"
license=(GPL2)
depends=(glibc gcc-libs ncurses pcre2)
makedepends=(git cmake ninja llvm-god-mlgo rust gcc-git-god)
provides=(fish)
conflicts=(fish fish-git)
source=(
"fish-shell.tar.gz"
"vendor.tar.gz"
)
sha256sums=('SKIP' 'SKIP')
_write_cargo_vendor_config() {
local _root="$1"
mkdir -p "$_root/.cargo"
cat > "$_root/.cargo/config.toml" <<'EOF'
[source.crates-io]
replace-with = "vendored-sources"
[source."git+https://github.com/fish-shell/rust-pcre2?tag=0.2.9-utf32"]
git = "https://github.com/fish-shell/rust-pcre2"
tag = "0.2.9-utf32"
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
EOF
}
_sync_cargo_with_vendor() {
local _root="$srcdir/fish-shell"
[[ -d "$_root" ]] || return 0
_write_cargo_vendor_config "$_root"
(
cd "$_root"
local _vendor_root="$PWD/vendor"
if [[ -d "$_vendor_root/vendor" ]]; then
_vendor_root="$_vendor_root/vendor"
fi
[[ -d "$_vendor_root" ]] || exit 0
# Some upstream dependency constraints may drift ahead of vendored crates.
# Pre-sync known hotspot: nix.
local _vendored_nix_ver=""
local _vendored_nix_sum=""
if [[ -f "$_vendor_root/nix/Cargo.toml" ]]; then
_vendored_nix_ver=$(sed -n 's/^version = \"\\(.*\\)\"/\\1/p' "$_vendor_root/nix/Cargo.toml" | head -n1)
if [[ -f "$_vendor_root/nix/.cargo-checksum.json" ]]; then
_vendored_nix_sum=$(sed -n 's/.*\"package\":\"\\([0-9a-f]*\\)\".*/\\1/p' "$_vendor_root/nix/.cargo-checksum.json" | head -n1)
fi
fi
if [[ -n "$_vendored_nix_ver" ]]; then
local _nix_toml
for _nix_toml in "$PWD/Cargo.toml" "$PWD/crates/common/Cargo.toml"; do
[[ -f "$_nix_toml" ]] || continue
sed -E -i \
-e "s/^([[:space:]]*nix[[:space:]]*=[[:space:]]*)\"[^\"]+\"/\\1\"^${_vendored_nix_ver}\"/" \
-e "s/(nix[[:space:]]*=[[:space:]]*\\{[^}]*version[[:space:]]*=[[:space:]]*)\"[^\"]+\"/\\1\"^${_vendored_nix_ver}\"/" \
"$_nix_toml"
done
if [[ -f Cargo.lock ]]; then
awk -v c="nix" -v v="$_vendored_nix_ver" -v s="$_vendored_nix_sum" '
BEGIN { in_pkg=0; is_target=0 }
/^\[\[package\]\]/ { in_pkg=1; is_target=0 }
in_pkg && $0 == "name = \"" c "\"" { is_target=1 }
in_pkg && is_target && /^version = / { $0 = "version = \"" v "\"" }
in_pkg && is_target && s != "" && /^checksum = / { $0 = "checksum = \"" s "\"" }
{ print }
' Cargo.lock > Cargo.lock.new && mv Cargo.lock.new Cargo.lock
fi
fi
# Keep Cargo.lock aligned with vendored crates for offline builds.
# For git-replaced crates, Cargo requires an existing lockfile, so we heal
# mismatched entries in-place using cargo metadata diagnostics.
[[ -f Cargo.lock ]] || exit 0
local _i _meta _crate _cand _sum
for _i in {1..30}; do
_meta=$(CARGO_NET_OFFLINE=true cargo metadata --format-version 1 --locked --offline 2>&1 >/dev/null) && break
_crate=$(printf '%s\n' "$_meta" | sed -n 's/.*requirement .\([^ =]*\) = .*/\1/p' | head -n1)
_cand=$(printf '%s\n' "$_meta" | sed -n "s/.*candidate versions found which didn't match: \\([^ ,)]*\\).*/\\1/p" | head -n1)
if [[ -z "$_crate" || -z "$_cand" ]]; then
break
fi
_sum=""
if [[ -f "$_vendor_root/$_crate/.cargo-checksum.json" ]]; then
_sum=$(sed -n 's/.*\"package\":\"\\([0-9a-f]*\\)\".*/\\1/p' "$_vendor_root/$_crate/.cargo-checksum.json" | head -n1)
fi
awk -v c="$_crate" -v v="$_cand" -v s="$_sum" '
BEGIN { in_pkg=0; is_target=0 }
/^\[\[package\]\]/ { in_pkg=1; is_target=0 }
in_pkg && $0 == "name = \"" c "\"" { is_target=1 }
in_pkg && is_target && /^version = / { $0 = "version = \"" v "\"" }
in_pkg && is_target && s != "" && /^checksum = / { $0 = "checksum = \"" s "\"" }
{ print }
' Cargo.lock > Cargo.lock.new && mv Cargo.lock.new Cargo.lock
done
) || true
}
pkgver() {
local _ver _ts
if [[ -f "${srcdir}/fish-shell.obsinfo" ]]; then
_ver=$(sed -n 's/^version: //p' "${srcdir}/fish-shell.obsinfo" | head -n1)
fi
if [[ -z "$_ver" && -f "${srcdir}/._servicedata" ]]; then
_ver=$(sed -n 's/.*<param name="version">\(.*\)<\/param>.*/\1/p' "${srcdir}/._servicedata" | head -n1)
fi
if [[ -z "$_ver" && -d "${srcdir}/fish-shell" ]]; then
_ts=$(find "${srcdir}/fish-shell" -type f -printf '%T@\n' 2>/dev/null | sort -n | tail -n1 | cut -d. -f1)
if [[ -n "$_ts" ]]; then
_ver=$(date -u -d "@${_ts}" +%Y%m%d.%H%M%S 2>/dev/null)
fi
fi
if [[ -z "$_ver" ]]; then
_ver="${pkgver}"
fi
echo "${_ver//-/_}"
}
prepare() {
mkdir -p "$srcdir/bolt_data"
if [ ! -d "$srcdir/fish-shell" ]; then
_src_dir=$(find "$srcdir" -maxdepth 1 -type d -name "fish-shell-*" | head -n 1)
if [ -z "$_src_dir" ]; then
echo "Missing source dir for fish-shell"
return 1
fi
mv "$_src_dir" "$srcdir/fish-shell"
fi
if [ -d "$srcdir/vendor" ]; then
rm -rf "$srcdir/fish-shell/vendor"
mv "$srcdir/vendor" "$srcdir/fish-shell/vendor"
fi
_sync_cargo_with_vendor
}
build() {
# Prefer llvm-god-mlgo tools when available.
for d in /opt/llvm-god/bin /usr/lib/llvm*/bin /usr/lib/llvm*; do
if [[ -x "$d/llvm-bolt" && -x "$d/merge-fdata" && -x "$d/llvm-profdata" ]]; then
export PATH="$d:$PATH"
break
fi
done
# OBS often reuses srcdir and may skip prepare(); enforce vendored Rust sync here.
_sync_cargo_with_vendor
# fish's test helper target is not needed for runtime packaging and fails to
# link under our GCC/LTO toolchain in OBS. Drop tests from the CMake graph.
if [[ -f "$srcdir/fish-shell/CMakeLists.txt" ]]; then
sed -i '/^include(cmake\/Tests\.cmake)$/d' "$srcdir/fish-shell/CMakeLists.txt"
fi
# Keep workspace nix requirement aligned with the currently vendored crate.
# This runs every build because OBS may reuse srcdir and skip prepare().
local _nix_ver=""
local _nix_sum=""
local _nix_dir=""
if [[ -f "$srcdir/fish-shell/vendor/nix/Cargo.toml" ]]; then
_nix_dir="$srcdir/fish-shell/vendor/nix"
elif [[ -f "$srcdir/fish-shell/vendor/vendor/nix/Cargo.toml" ]]; then
_nix_dir="$srcdir/fish-shell/vendor/vendor/nix"
fi
if [[ -n "$_nix_dir" ]]; then
_nix_ver=$(sed -n 's/^version = \"\\(.*\\)\"/\\1/p' "$_nix_dir/Cargo.toml" | head -n1)
if [[ -f "$_nix_dir/.cargo-checksum.json" ]]; then
_nix_sum=$(sed -n 's/.*\"package\":\"\\([0-9a-f]*\\)\".*/\\1/p' "$_nix_dir/.cargo-checksum.json" | head -n1)
fi
fi
if [[ -n "$_nix_ver" && -f "$srcdir/fish-shell/Cargo.toml" ]]; then
sed -E -i \
-e "s/^([[:space:]]*nix[[:space:]]*=[[:space:]]*)\"[^\"]+\"/\\1\"^${_nix_ver}\"/" \
-e "s/^([[:space:]]*nix[[:space:]]*=[[:space:]]*\\{[^}]*version[[:space:]]*=[[:space:]]*)\"[^\"]+\"/\\1\"^${_nix_ver}\"/" \
"$srcdir/fish-shell/Cargo.toml"
msg2 "Forced nix workspace dependency to ^${_nix_ver}"
fi
if [[ -n "$_nix_ver" && -f "$srcdir/fish-shell/Cargo.lock" ]]; then
awk -v c="nix" -v v="$_nix_ver" -v s="$_nix_sum" '
BEGIN { in_pkg=0; is_target=0 }
/^\[\[package\]\]/ { in_pkg=1; is_target=0 }
in_pkg && $0 == "name = \"" c "\"" { is_target=1 }
in_pkg && is_target && /^version = / { $0 = "version = \"" v "\"" }
in_pkg && is_target && s != "" && /^checksum = / { $0 = "checksum = \"" s "\"" }
{ print }
' "$srcdir/fish-shell/Cargo.lock" > "$srcdir/fish-shell/Cargo.lock.new" && mv "$srcdir/fish-shell/Cargo.lock.new" "$srcdir/fish-shell/Cargo.lock"
fi
# Heal remaining lockfile drifts against vendored crates until metadata resolves.
(
cd "$srcdir/fish-shell"
local _vendor_lock_root="$PWD/vendor"
if [[ -d "$_vendor_lock_root/vendor" ]]; then
_vendor_lock_root="$_vendor_lock_root/vendor"
fi
local _i _meta _crate _cand _sum
for _i in {1..80}; do
_meta=$(CARGO_NET_OFFLINE=true cargo metadata --format-version 1 --locked --offline 2>&1 >/dev/null) && break
_crate=$(printf '%s\n' "$_meta" | sed -n 's/.*requirement .\([^ =]*\) = .*/\1/p' | head -n1)
_cand=$(printf '%s\n' "$_meta" | sed -n "s/.*candidate versions found which didn't match: \\([^ ,)]*\\).*/\\1/p" | head -n1)
if [[ -z "$_crate" || -z "$_cand" ]]; then
break
fi
_sum=""
if [[ -f "$_vendor_lock_root/$_crate/.cargo-checksum.json" ]]; then
_sum=$(sed -n 's/.*\"package\":\"\\([0-9a-f]*\\)\".*/\\1/p' "$_vendor_lock_root/$_crate/.cargo-checksum.json" | head -n1)
fi
msg2 "Adjusting Cargo.lock ${_crate} -> ${_cand}"
awk -v c="$_crate" -v v="$_cand" -v s="$_sum" '
BEGIN { in_pkg=0; is_target=0 }
/^\[\[package\]\]/ { in_pkg=1; is_target=0 }
in_pkg && $0 == "name = \"" c "\"" { is_target=1 }
in_pkg && is_target && /^version = / { $0 = "version = \"" v "\"" }
in_pkg && is_target && s != "" && /^checksum = / { $0 = "checksum = \"" s "\"" }
{ print }
' Cargo.lock > Cargo.lock.new && mv Cargo.lock.new Cargo.lock
done
) || true
# Require llvm-bolt/merge-fdata from current llvm toolchain.
if ! command -v llvm-bolt >/dev/null 2>&1 || ! command -v merge-fdata >/dev/null 2>&1; then
echo "Missing llvm-bolt or merge-fdata in PATH"
return 1
fi
local LLVM_PROFDATA_BIN
LLVM_PROFDATA_BIN="$(command -v llvm-profdata || true)"
if [[ -z "$LLVM_PROFDATA_BIN" ]]; then
echo "Missing llvm-profdata in PATH"
return 1
fi
msg2 "✅ BOLT tools ready: $(llvm-bolt --version 2>&1 | head -1 || echo 'not found')"
# === 1. 环境准备 ===
if [ ! -x /opt/gcc-git-god/bin/gcc ]; then
echo "gcc-git-god missing in /opt/gcc-git-god"
return 1
fi
export CC="/opt/gcc-git-god/bin/gcc"
export CXX="/opt/gcc-git-god/bin/g++"
export AR="/opt/gcc-git-god/bin/gcc-ar"
export NM="/opt/gcc-git-god/bin/gcc-nm"
export RANLIB="/opt/gcc-git-god/bin/gcc-ranlib"
export CFLAGS="-O3 -march=alderlake -flto=auto -pipe"
export CXXFLAGS="$CFLAGS"
export LDFLAGS="-L/opt/gcc-git-god/lib64 -Wl,-rpath,/opt/gcc-git-god/lib64 -flto=auto -Wl,--emit-relocs"
export LD_LIBRARY_PATH="/opt/gcc-git-god/lib64:$LD_LIBRARY_PATH"
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="/opt/gcc-git-god/bin/gcc"
export CARGO_NET_OFFLINE=true
# === 2. Stage 1: PGO 插桩编译 ===
msg2 "🚀 Starting PGO Stage 1: Instrumentation..."
rm -rf build-pgo
export RUSTFLAGS="-Cprofile-generate=$srcdir/pgo_data -Ctarget-cpu=alderlake -Copt-level=3 -Clink-arg=-Wl,-rpath,/opt/gcc-git-god/lib64 -Clink-arg=-L/opt/gcc-git-god/lib64 -Clink-arg=-Wl,--emit-relocs -Clinker=/opt/gcc-git-god/bin/gcc"
cmake -B build-pgo -S fish-shell -G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_MESSAGE_LOCALIZATION=OFF
cmake --build build-pgo
# === 3. Stage 2: PGO Training ===
msg2 "🏋️ Training Fish (PGO)..."
export LLVM_PROFILE_FILE="$srcdir/pgo_data/fish-%p-%m.profraw"
echo 'for i in (seq 1 5000); string match -r ".*" "test_$i" >/dev/null; end' > train.fish
for i in {1..20}; do
./build-pgo/fish --no-config train.fish > /dev/null 2>&1 || true
./build-pgo/fish --no-config -c "complete -C 'git comm'" > /dev/null 2>&1 || true
done
# === 4. Stage 3: PGO Use + Fat LTO ===
msg2 "🔥 Starting Stage 3: Extreme Compilation..."
# Use llvm-profdata from active llvm toolchain.
"$LLVM_PROFDATA_BIN" merge -output="$srcdir/fish.profdata" "$srcdir/pgo_data"
export RUSTFLAGS="-Cprofile-use=$srcdir/fish.profdata -Ctarget-cpu=alderlake -Copt-level=3 -Clto=fat -Ccodegen-units=1 -Cpanic=abort -Clink-arg=-Wl,-rpath,/opt/gcc-git-god/lib64 -Clink-arg=-L/opt/gcc-git-god/lib64 -Clink-arg=-Wl,--emit-relocs -Clinker=/opt/gcc-git-god/bin/gcc"
rm -rf build-pgo
cmake -B build-pgo -S fish-shell -G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_MESSAGE_LOCALIZATION=OFF
cmake --build build-pgo
# === 5. Stage 4: BOLT Optimization ===
msg2 "⚡ Starting BOLT Optimization..."
# Create instrumented binary
msg2 "Creating BOLT instrumented binary..."
if ! llvm-bolt build-pgo/fish -o fish.inst \
-instrument \
-instrumentation-file="$srcdir/bolt_data/fish.fdata" \
-instrumentation-file-append-pid; then
msg2 "⚠️ BOLT instrumentation failed, skipping BOLT"
return 0
fi
# Run training
msg2 "Training BOLT instrumented binary..."
./fish.inst --no-config -c 'echo "BOLT training"' 2>/dev/null || true
./fish.inst --no-config -c 'for i in (seq 1 100); echo $i >/dev/null; end' 2>/dev/null || true
./fish.inst --no-config -c 'string match -r ".*" "hello world"' 2>/dev/null || true
./fish.inst --no-config train.fish 2>/dev/null || true
# Merge profile data
if ls "$srcdir/bolt_data"/fish.fdata.* &>/dev/null; then
merge-fdata "$srcdir/bolt_data"/fish.fdata.* > "$srcdir/bolt_data/fish.fdata.merged"
mv "$srcdir/bolt_data/fish.fdata.merged" "$srcdir/bolt_data/fish.fdata"
fi
# Apply BOLT
if [[ -s "$srcdir/bolt_data/fish.fdata" ]]; then
msg2 "Applying BOLT optimizations..."
if llvm-bolt build-pgo/fish -o fish.bolt \
-data="$srcdir/bolt_data/fish.fdata" \
-reorder-blocks=ext-tsp \
-reorder-functions=hfsort \
-split-functions \
-split-all-cold \
-icf=1 \
-dyno-stats; then
mv fish.bolt build-pgo/fish
msg2 "✅ BOLT optimization complete!"
else
msg2 "⚠️ BOLT optimization failed, using PGO binary"
fi
else
msg2 "⚠️ No BOLT profile data, skipping"
fi
}
package() {
DESTDIR="$pkgdir" cmake --install build-pgo
}