Pass nm/ar/objcopy paths from CMake to localize_rust_c_symbols.sh

The script used to call `llvm-nm` via $PATH and derive `llvm-ar`'s path
from `llvm-objcopy` by basename substitution. Both lookups were fragile:
they failed when `llvm-nm` was missing from $PATH and silently picked
the wrong archiver when the toolchain's naming did not match.

Resolve all three tools (`llvm-nm`, `llvm-ar`, `llvm-objcopy`) via
`ch_find_program` in `cmake/tools.cmake` and pass the full paths as
script arguments, mirroring how `cmake/strip_rust_symbols.sh` is
invoked.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
Raúl Marín
2026-05-13 12:49:00 +02:00
co-authored by Claude Opus 4.7
parent 50adbc2a1a
commit 9df07df5a0
3 changed files with 24 additions and 24 deletions
+15 -23
View File
@@ -12,15 +12,22 @@
# our own implementations instead. All other symbols (Rust-mangled, crate
# FFI, etc.) are left untouched.
#
# Usage: localize_rust_c_symbols.sh <library.a> <objcopy>
# Usage: localize_rust_c_symbols.sh <library.a> <ar> <objcopy> <nm>
#
# The ar/objcopy/nm tools must come from a compatible LLVM toolchain
# (e.g. llvm-ar, llvm-objcopy, llvm-nm). CMake resolves them via
# ch_find_program and passes the full paths so this script never has to
# search $PATH or infer one tool's name from another.
set -eu
LIB_PATH="$1"
OBJCOPY="$2"
LIB_PATH="${1:-}"
AR="${2:-}"
OBJCOPY="${3:-}"
NM="${4:-}"
if [ -z "$LIB_PATH" ] || [ -z "$OBJCOPY" ]; then
echo "Usage: $0 <library.a> <objcopy>" >&2
if [ -z "$LIB_PATH" ] || [ -z "$AR" ] || [ -z "$OBJCOPY" ] || [ -z "$NM" ]; then
echo "Usage: $0 <library.a> <ar> <objcopy> <nm>" >&2
exit 1
fi
@@ -80,22 +87,17 @@ WORK_DIR=""
cleanup() { rm -f "$TMPFILE"; [ -n "$WORK_DIR" ] && rm -rf "$WORK_DIR"; true; }
trap cleanup EXIT
if ! command -v llvm-nm >/dev/null 2>&1; then
echo "Error: llvm-nm not found in PATH (required for Rust C-symbol localization)" >&2
exit 1
fi
# Get all global defined symbols from the library. llvm-nm may print per-member errors for non-ELF archive
# Get all global defined symbols from the library. nm may print per-member errors for non-ELF archive
# members (e.g. debug metadata objects) - those are non-fatal as long as at least one ELF member is read.
# A truly broken/missing archive produces empty output and is caught below.
llvm-nm "$LIB_PATH" 2>/dev/null \
"$NM" "$LIB_PATH" 2>/dev/null \
| grep -E '^[0-9a-f]+ [TDBCWV] ' \
| awk '{print $3}' \
| sort -u \
> "$TMPFILE" || true
if [ ! -s "$TMPFILE" ]; then
echo "Error: llvm-nm produced no symbols for $LIB_PATH; cannot localize Rust C symbols" >&2
echo "Error: $NM produced no symbols for $LIB_PATH; cannot localize Rust C symbols" >&2
exit 1
fi
@@ -113,16 +115,6 @@ if [ -n "$LOCALIZE_FLAGS" ]; then
# that cause llvm-objcopy to fail. In that case, fall back to extracting
# individual members, processing only valid ELF objects, and repacking.
if ! $OBJCOPY $LOCALIZE_FLAGS "$LIB_PATH" 2>/dev/null; then
# Substitute only inside the basename so a directory containing `objcopy`
# is not rewritten and a versioned name like `llvm-objcopy-21` still maps
# to `llvm-ar-21`.
OBJCOPY_NAME="${OBJCOPY##*/}"
AR_NAME="${OBJCOPY_NAME/objcopy/ar}"
if [ "$OBJCOPY_NAME" = "$OBJCOPY" ]; then
AR="$AR_NAME"
else
AR="${OBJCOPY%/*}/$AR_NAME"
fi
WORK_DIR=$(mktemp -d)
(cd "$WORK_DIR" && "$AR" x "$LIB_PATH")
+8
View File
@@ -98,6 +98,14 @@ else ()
message (FATAL_ERROR "Cannot find objcopy.")
endif ()
# nm (used by helper scripts that inspect symbol tables, e.g. cmake/localize_rust_c_symbols.sh)
ch_find_program (NM_PATH NAMES "llvm-nm-${COMPILER_VERSION_MAJOR}" "llvm-nm" "nm")
if (NM_PATH)
message (STATUS "Using nm: ${NM_PATH}")
else ()
message (FATAL_ERROR "Cannot find nm.")
endif ()
# Strip
ch_find_program (STRIP_PATH NAMES "llvm-strip-${COMPILER_VERSION_MAJOR}" "llvm-strip" "strip")
if (STRIP_PATH)
+1 -1
View File
@@ -293,7 +293,7 @@ function(clickhouse_config_crate_flags target_name)
add_custom_target(localize_rust_c_${target_name}
COMMAND bash "${ClickHouse_SOURCE_DIR}/cmake/localize_rust_c_symbols.sh"
"${_rust_lib_path}" "${CMAKE_OBJCOPY}"
"${_rust_lib_path}" "${CMAKE_AR}" "${CMAKE_OBJCOPY}" "${NM_PATH}"
COMMENT "Localizing C-namespace symbols in ${target_name}"
VERBATIM
)