Files
datastore/cmake/strip_rust_symbols.sh
Alexey MilovidovandClaude Opus 4.6 52634d4a90 Strip internal symbols from PRQL static library
After cargo builds the PRQL library, run a post-build step that:
1. Extracts .o files from the .a archive
2. Partial-links them into a single .o (resolving all internal references)
3. Localizes all symbols except `prql_to_sql` and `prql_free_pointer`
4. Strips symbols not needed for relocations
5. Repackages as .a

This reduces the library from 69 MB to 51 MB and leaves only 2 visible
global symbols. The ~67K internal symbols (including deeply nested chumsky
parser combinator types) are eliminated from the symbol table.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 04:45:23 +01:00

58 lines
1.7 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Strip internal symbols from a Rust static library (.a), keeping only
# the specified public symbols visible.
#
# This dramatically reduces symbol table bloat from Rust libraries like prqlc,
# whose parser combinator (chumsky) generates deeply nested generic types
# with very long symbol names.
#
# The process:
# 1. Extract .o files from the .a archive
# 2. Partial-link them into a single .o (resolves all internal cross-references)
# 3. Localize all symbols except the specified public ones
# 4. Strip symbols not needed for relocations
# 5. Repackage as .a
#
# Usage: strip_rust_symbols.sh <library.a> <ar> <objcopy> <ld> <symbol1> [symbol2] ...
#
# The ar/objcopy/ld tools must be from a compatible LLVM toolchain
# (e.g., llvm-ar, llvm-objcopy, ld.lld) to avoid LLVM version mismatches
# with Rust-compiled code.
set -e
LIB_PATH=$(realpath "$1")
AR="$2"
OBJCOPY="$3"
LD="$4"
shift 4
if [ -z "$LIB_PATH" ] || [ $# -eq 0 ]; then
echo "Usage: $0 <library.a> <ar> <objcopy> <ld> <symbol1> [symbol2] ..." >&2
exit 1
fi
WORK_DIR=$(mktemp -d)
trap "rm -rf '$WORK_DIR'" EXIT
# Extract object files
mkdir "$WORK_DIR/objs"
(cd "$WORK_DIR/objs" && "$AR" x "$LIB_PATH")
# Partial link: combine all .o into one, resolving internal cross-references.
"$LD" -r -o "$WORK_DIR/combined.o" "$WORK_DIR"/objs/*.o
# Build objcopy flags to keep only the specified public symbols
KEEP_FLAGS=""
for sym in "$@"; do
KEEP_FLAGS="$KEEP_FLAGS --keep-global-symbol=$sym"
done
# Localize all symbols except the public ones, then strip unneeded locals
"$OBJCOPY" $KEEP_FLAGS --strip-unneeded "$WORK_DIR/combined.o" "$WORK_DIR/stripped.o"
# Repackage as .a (replace original)
rm -f "$LIB_PATH"
"$AR" rcs "$LIB_PATH" "$WORK_DIR/stripped.o"