-
Notifications
You must be signed in to change notification settings - Fork 31.9k
Expand file tree
/
Copy pathdocker-native-build.sh
More file actions
executable file
·163 lines (143 loc) · 6.45 KB
/
Copy pathdocker-native-build.sh
File metadata and controls
executable file
·163 lines (143 loc) · 6.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env bash
# Inner build script run inside the next-swc-builder docker container.
#
# All toolchains (clang, lld, musl sysroots, node, rust, napi-cli,
# cargo-rustflags) are pre-installed in the image.
#
# RUSTFLAGS are resolved via `cargo rustflags` which merges .cargo/config.toml
# (mounted from the repo) with target-specific --config overrides for cross-
# compilation paths. This avoids duplicating config.toml flags in this script.
#
# Expected env vars (set by CI or docker-native-build.js):
# TARGET - Rust target triple (e.g. x86_64-unknown-linux-gnu)
# ABI - Target ABI (gnu or musl)
# ARCH - Target architecture (x86_64 or aarch64)
# BUILD_TASK - Cargo/napi build task name (default: build-native-release)
set -xeo pipefail
# /build is bind-mounted from the host with a uid that differs from the
# container's root user; mark it safe so vergen's `git rev-parse` works.
git config --global --add safe.directory /build
BUILD_TASK="${BUILD_TASK:-build-native-release}"
# Node.js (installed via nodesource) is used only as a build tool (runs
# npm/napi-cli). The output .node shared library's linking is determined
# by cargo's --target, not the node binary.
# --- RUSTFLAGS via cargo-rustflags ---
# We use `linker=clang` + `linker-flavor=gnu-lld-cc` rather than
# `linker=rust-lld` directly. The actual linker is rust-lld in both
# cases, but clang acts as the driver: it handles finding crt files
# (crti.o, crtbeginS.o), libc, and libgcc, and translates --target /
# --sysroot into the correct library search paths.
#
# cargo-rustflags merges these with .cargo/config.toml (cfg(true) base flags,
# musl crt-static, etc.) so we don't duplicate them here.
CROSS_FLAGS="-Clinker=clang -Clinker-flavor=gnu-lld-cc -Clink-arg=-Wl,--icf=all"
HOST_ARCH=$(uname -m)
# Determine if we need --sysroot. Native GNU targets (host == target arch)
# don't need it — clang finds native multiarch headers automatically.
# Cross GNU targets and all musl targets need explicit sysroot paths.
IS_NATIVE_GNU=0
if [ "$ABI" = "gnu" ]; then
case "${HOST_ARCH}-${ARCH}" in
x86_64-x86_64|aarch64-aarch64) IS_NATIVE_GNU=1 ;;
esac
fi
case "$TARGET" in
x86_64-unknown-linux-gnu)
CROSS_FLAGS="$CROSS_FLAGS -Clink-arg=--target=x86_64-linux-gnu"
# For cross builds, DON'T pass --sysroot to the linker — lld can't
# resolve absolute paths inside libc.so linker scripts when --sysroot
# is set (it double-prepends the sysroot). Instead, pass -L to point
# at the cross libs directly. --sysroot is passed via CFLAGS for C
# compilation (build scripts like jemalloc).
if [ "$IS_NATIVE_GNU" = "0" ]; then
CROSS_FLAGS="$CROSS_FLAGS -Clink-arg=-L/usr/x86_64-linux-gnu/lib"
fi
;;
aarch64-unknown-linux-gnu)
CROSS_FLAGS="$CROSS_FLAGS -Clink-arg=--target=aarch64-linux-gnu"
if [ "$IS_NATIVE_GNU" = "0" ]; then
CROSS_FLAGS="$CROSS_FLAGS -Clink-arg=-L/usr/aarch64-linux-gnu/lib"
fi
;;
x86_64-unknown-linux-musl)
CROSS_FLAGS="$CROSS_FLAGS -Clink-arg=--target=x86_64-linux-musl -Clink-arg=--sysroot=/opt/x86_64-linux-musl-cross/x86_64-linux-musl -Clink-arg=--gcc-toolchain=/opt/x86_64-linux-musl-cross" ;;
aarch64-unknown-linux-musl)
CROSS_FLAGS="$CROSS_FLAGS -Clink-arg=--target=aarch64-linux-musl -Clink-arg=--sysroot=/opt/aarch64-linux-musl-cross/aarch64-linux-musl -Clink-arg=--gcc-toolchain=/opt/aarch64-linux-musl-cross" ;;
*) echo "Unknown target: $TARGET"; exit 1 ;;
esac
# Build the --config argument as a TOML inline value
CROSS_CONFIG="target.${TARGET}.rustflags=[$(echo "$CROSS_FLAGS" | sed 's/\([^ ]*\)/"\1"/g; s/ /, /g')]"
# Resolve merged RUSTFLAGS (config.toml base + cross overrides)
RUSTFLAGS=$(cargo rustflags --target "$TARGET" --config "$CROSS_CONFIG")
export RUSTFLAGS
# --- rust-lld symlink ---
# rustc's gcc-ld/ dir has ld.lld but no 'ld' shim. gnu-lld-cc passes
# -B<gcc-ld-dir> to clang, which looks for 'ld' there.
SYSROOT=$(rustc --print sysroot)
GCC_LD="$SYSROOT/lib/rustlib/${TARGET}/bin/gcc-ld"
if [ -d "$GCC_LD" ] && [ ! -e "$GCC_LD/ld" ]; then
ln -sf ../rust-lld "$GCC_LD/ld"
fi
# --- CC/CXX for build scripts (jemalloc, ring, etc.) ---
TARGET_US=$(echo "$TARGET" | tr '-' '_')
unset "CC_${TARGET_US}" "CXX_${TARGET_US}" "CFLAGS_${TARGET_US}"
export "CC_${TARGET_US}=clang"
export "CXX_${TARGET_US}=clang++"
case "$TARGET" in
x86_64-unknown-linux-gnu)
if [ "$HOST_ARCH" = "x86_64" ]; then
export "CFLAGS_${TARGET_US}=--target=x86_64-linux-gnu"
else
export "CFLAGS_${TARGET_US}=--target=x86_64-linux-gnu --sysroot=/usr/x86_64-linux-gnu"
fi ;;
aarch64-unknown-linux-gnu)
if [ "$HOST_ARCH" = "aarch64" ]; then
export "CFLAGS_${TARGET_US}=--target=aarch64-linux-gnu"
else
export "CFLAGS_${TARGET_US}=--target=aarch64-linux-gnu --sysroot=/usr/aarch64-linux-gnu"
fi ;;
x86_64-unknown-linux-musl)
export "CFLAGS_${TARGET_US}=--target=x86_64-linux-musl --sysroot=/opt/x86_64-linux-musl-cross/x86_64-linux-musl --gcc-toolchain=/opt/x86_64-linux-musl-cross" ;;
aarch64-unknown-linux-musl)
export "CFLAGS_${TARGET_US}=--target=aarch64-linux-musl --sysroot=/opt/aarch64-linux-musl-cross/aarch64-linux-musl --gcc-toolchain=/opt/aarch64-linux-musl-cross" ;;
esac
# aarch64 needs larger page size for jemalloc
if [ "$ARCH" = "aarch64" ]; then
export JEMALLOC_SYS_WITH_LG_PAGE=16
fi
# Verify sccache is available if RUSTC_WRAPPER is set to it.
# Cached docker images may not have sccache installed yet.
if [ "${RUSTC_WRAPPER:-}" = "sccache" ] && ! command -v sccache &>/dev/null; then
echo "WARNING: RUSTC_WRAPPER=sccache but sccache not found — disabling"
unset RUSTC_WRAPPER
fi
echo "--- Build environment ---"
node -v
rustc --version
echo "Target: $TARGET"
echo "RUSTFLAGS: $RUSTFLAGS"
echo "RUSTC_WRAPPER: ${RUSTC_WRAPPER:-<unset>}"
echo "-------------------------"
rustup target add "$TARGET"
cd packages/next-swc
npm run "$BUILD_TASK" -- --target "$TARGET"
llvm-strip -x native/next-swc.*.node
# Show sccache stats if available
if command -v sccache &>/dev/null; then
echo "--- sccache stats ---"
sccache --show-stats || true
fi
# Post-build verification
echo "--- Dynamic libraries ---"
readelf -d native/next-swc.*.node | grep NEEDED
case "$ABI" in
gnu)
echo "--- GLIBC symbols by version ---"
objdump -T native/next-swc.*.node \
| grep 'GLIBC_' \
| sed 's/.*\(GLIBC_[^ ]*\) \+/\1 /' \
| sort -t. -k2,2n -k3,3n \
| awk '{vers[$1] = vers[$1] ? vers[$1] ", " $2 : $2} END {for (v in vers) print v ": " vers[v]}' \
| sort -t. -k2,2n -k3,3n
;;
esac