Skip to content

Commit 8d39d63

Browse files
authored
fix(build): lock musl outputs to fully static linking in build script and CI workflows (#2330)
1 parent da26e72 commit 8d39d63

3 files changed

Lines changed: 90 additions & 12 deletions

File tree

.github/workflows/beta_release.yml

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,32 +67,39 @@ jobs:
6767
goflags: ""
6868
- target: "linux-(mips|mips64|mipsle|mips64le|loong64)-musl*" # musl-compat-family
6969
hash: "md5-linux-musl-mips"
70-
flags: ""
70+
flags: "-ldflags=-linkmode external -extldflags '-static -fpic'"
7171
goflags: ""
72+
musl_static: "true"
7273
- target: "linux-!(arm*|mips|mips64|mipsle|mips64le|loong64)-musl*" # musl-not-arm (exclude compat-family)
7374
hash: "md5-linux-musl"
74-
flags: ""
75+
flags: "-ldflags=-linkmode external -extldflags '-static -fpic'"
7576
goflags: ""
77+
musl_static: "true"
7678
- target: "linux-arm*-musl*" #musl-arm
7779
hash: "md5-linux-musl-arm"
78-
flags: ""
80+
flags: "-ldflags=-linkmode external -extldflags '-static -fpic'"
7981
goflags: ""
82+
musl_static: "true"
8083
- target: "windows-arm64" #win-arm64
8184
hash: "md5-windows-arm64"
8285
flags: ""
8386
goflags: ""
87+
musl_static: "false"
8488
- target: "windows7-*" #win7
8589
hash: "md5-windows7"
8690
flags: ""
8791
goflags: "-tags=sqlite_cgo_compat"
92+
musl_static: "false"
8893
- target: "android-*" #android
8994
hash: "md5-android"
9095
flags: ""
9196
goflags: ""
97+
musl_static: "false"
9298
- target: "freebsd-*" #freebsd
9399
hash: "md5-freebsd"
94100
flags: ""
95101
goflags: ""
102+
musl_static: "false"
96103

97104
name: Beta Release
98105
runs-on: ubuntu-latest
@@ -118,6 +125,7 @@ jobs:
118125
with:
119126
targets: ${{ matrix.target }}
120127
flags: ${{ matrix.flags || '-ldflags=' }}
128+
static-link-for-musl: true
121129
musl-target-format: $os-$musl-$arch
122130
github-token: ${{ secrets.GITHUB_TOKEN }}
123131
out-dir: build
@@ -132,6 +140,24 @@ jobs:
132140
env:
133141
GOFLAGS: ${{ matrix.goflags }}
134142

143+
- name: Verify musl binaries are static
144+
if: matrix.musl_static == 'true'
145+
run: |
146+
set -e
147+
shopt -s nullglob
148+
files=(build/openlist-*-musl-*)
149+
if [ ${#files[@]} -eq 0 ]; then
150+
echo "No musl binaries found"
151+
exit 1
152+
fi
153+
for f in "${files[@]}"; do
154+
if readelf -l "$f" | grep -q "Requesting program interpreter"; then
155+
echo "Dynamic binary detected: $f"
156+
readelf -l "$f" | grep "Requesting program interpreter" || true
157+
exit 1
158+
fi
159+
done
160+
135161
- name: Compress
136162
run: |
137163
bash build.sh zip ${{ matrix.hash }}

.github/workflows/build.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ jobs:
4545
uses: OpenListTeam/cgo-actions@v1.2.2
4646
with:
4747
targets: ${{ matrix.target }}
48+
flags: ${{ contains(matrix.target, '-musl') && '-ldflags=-linkmode external -extldflags ''-static -fpic''' || '-ldflags=' }}
49+
static-link-for-musl: true
4850
musl-target-format: $os-$musl-$arch
4951
github-token: ${{ secrets.GITHUB_TOKEN }}
5052
out-dir: build
@@ -56,6 +58,16 @@ jobs:
5658
github.com/OpenListTeam/OpenList/v4/internal/conf.WebVersion=rolling
5759
output: openlist$ext
5860

61+
- name: Verify musl binary is static
62+
if: contains(matrix.target, '-musl')
63+
run: |
64+
set -e
65+
if readelf -l build/openlist | grep -q "Requesting program interpreter"; then
66+
echo "Dynamic binary detected: build/openlist"
67+
readelf -l build/openlist | grep "Requesting program interpreter" || true
68+
exit 1
69+
fi
70+
5971
- name: Upload artifact
6072
uses: actions/upload-artifact@v4
6173
with:

build.sh

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,41 @@ GetBuildTagsForTarget() {
6161
esac
6262
}
6363

64+
# Keep musl static link flags centralized for all musl build paths.
65+
GetMuslStaticLdflags() {
66+
echo "-linkmode external -extldflags '-static -fpic' $ldflags"
67+
}
68+
69+
# Fail fast if a musl build artifact is not fully static.
70+
AssertStaticBinary() {
71+
local binary="$1"
72+
if [ ! -f "$binary" ]; then
73+
echo "Error: binary not found: $binary"
74+
return 1
75+
fi
76+
77+
if command -v readelf >/dev/null 2>&1; then
78+
if readelf -l "$binary" 2>/dev/null | grep -q "Requesting program interpreter"; then
79+
echo "Error: binary is not fully static: $binary"
80+
readelf -l "$binary" | grep "Requesting program interpreter" || true
81+
return 1
82+
fi
83+
return 0
84+
fi
85+
86+
if command -v file >/dev/null 2>&1; then
87+
if file "$binary" | grep -qi "dynamically linked"; then
88+
echo "Error: binary is dynamically linked: $binary"
89+
file "$binary"
90+
return 1
91+
fi
92+
return 0
93+
fi
94+
95+
echo "Warning: readelf/file not found, skip static verification for $binary"
96+
return 0
97+
}
98+
6499
FetchWebRolling() {
65100
pre_release_json=$(eval "curl -fsSL --max-time 2 $githubAuthArgs -H \"Accept: application/vnd.github.v3+json\" \"https://api.github.com/repos/$frontendRepo/releases/tags/rolling\"")
66101
pre_release_assets=$(echo "$pre_release_json" | jq -r '.assets[].browser_download_url')
@@ -145,7 +180,7 @@ BuildWin7() {
145180
BuildDev() {
146181
rm -rf .git/
147182
mkdir -p "dist"
148-
muslflags="--extldflags '-static -fpic' $ldflags"
183+
muslflags="$(GetMuslStaticLdflags)"
149184
BASE="https://github.com/OpenListTeam/musl-compilers/releases/latest/download/"
150185
FILES=(x86_64-linux-musl-cross aarch64-linux-musl-cross)
151186
for i in "${FILES[@]}"; do
@@ -163,7 +198,8 @@ BuildDev() {
163198
export GOARCH=${os_arch##*-}
164199
export CC=${cgo_cc}
165200
export CGO_ENABLED=1
166-
go build -o ./dist/$appName-$os_arch -ldflags="$muslflags" -tags=jsoniter .
201+
CGO_LDFLAGS="-static" go build -o ./dist/$appName-$os_arch -ldflags="$muslflags" -tags=jsoniter .
202+
AssertStaticBinary "./dist/$appName-$os_arch"
167203
done
168204
xgo -targets=windows/amd64,darwin/amd64,darwin/arm64 -out "$appName" -ldflags="$ldflags" -tags=jsoniter .
169205
mv "$appName"-* dist
@@ -197,7 +233,7 @@ BuildDockerMultiplatform() {
197233
# run PrepareBuildDockerMusl before build
198234
export PATH=$PATH:$PWD/build/musl-libs/bin
199235

200-
docker_lflags="--extldflags '-static -fpic' $ldflags"
236+
docker_lflags="$(GetMuslStaticLdflags)"
201237
export CGO_ENABLED=1
202238

203239
OS_ARCHES=(linux-amd64 linux-arm64 linux-386 linux-riscv64 linux-ppc64le linux-loong64) ## Disable linux-s390x builds
@@ -212,7 +248,8 @@ BuildDockerMultiplatform() {
212248
export GOARCH=$arch
213249
export CC=${cgo_cc}
214250
echo "building for $os_arch"
215-
go build -o build/$os/$arch/"$appName" -ldflags="$docker_lflags" -tags="$build_tags" .
251+
CGO_LDFLAGS="-static" go build -o build/$os/$arch/"$appName" -ldflags="$docker_lflags" -tags="$build_tags" .
252+
AssertStaticBinary "build/$os/$arch/$appName"
216253
done
217254

218255
DOCKER_ARM_ARCHES=(linux-arm/v6 linux-arm/v7)
@@ -226,7 +263,8 @@ BuildDockerMultiplatform() {
226263
export GOARM=${GO_ARM[$i]}
227264
export CC=${cgo_cc}
228265
echo "building for $docker_arch"
229-
go build -o build/${docker_arch%%-*}/${docker_arch##*-}/"$appName" -ldflags="$docker_lflags" -tags=jsoniter .
266+
CGO_LDFLAGS="-static" go build -o build/${docker_arch%%-*}/${docker_arch##*-}/"$appName" -ldflags="$docker_lflags" -tags=jsoniter .
267+
AssertStaticBinary "build/${docker_arch%%-*}/${docker_arch##*-}/$appName"
230268
done
231269
}
232270

@@ -406,7 +444,7 @@ BuildLoongGLIBC() {
406444
BuildReleaseLinuxMusl() {
407445
rm -rf .git/
408446
mkdir -p "build"
409-
muslflags="--extldflags '-static -fpic' $ldflags"
447+
muslflags="$(GetMuslStaticLdflags)"
410448
BASE="https://github.com/OpenListTeam/musl-compilers/releases/latest/download/"
411449
# Keep mips-family targets enabled; sqlite driver selection is handled by Go build tags.
412450
FILES=(x86_64-linux-musl-cross aarch64-linux-musl-cross mips-linux-musl-cross mips64-linux-musl-cross mips64el-linux-musl-cross mipsel-linux-musl-cross powerpc64le-linux-musl-cross s390x-linux-musl-cross loongarch64-linux-musl-cross)
@@ -427,14 +465,15 @@ BuildReleaseLinuxMusl() {
427465
export GOARCH=${os_arch##*-}
428466
export CC=${cgo_cc}
429467
export CGO_ENABLED=1
430-
go build -o ./build/$appName-$os_arch -ldflags="$muslflags" -tags="$build_tags" .
468+
CGO_LDFLAGS="-static" go build -o ./build/$appName-$os_arch -ldflags="$muslflags" -tags="$build_tags" .
469+
AssertStaticBinary "./build/$appName-$os_arch"
431470
done
432471
}
433472

434473
BuildReleaseLinuxMuslArm() {
435474
rm -rf .git/
436475
mkdir -p "build"
437-
muslflags="--extldflags '-static -fpic' $ldflags"
476+
muslflags="$(GetMuslStaticLdflags)"
438477
BASE="https://github.com/OpenListTeam/musl-compilers/releases/latest/download/"
439478
FILES=(arm-linux-musleabi-cross arm-linux-musleabihf-cross armel-linux-musleabi-cross armel-linux-musleabihf-cross armv5l-linux-musleabi-cross armv5l-linux-musleabihf-cross armv6-linux-musleabi-cross armv6-linux-musleabihf-cross armv7l-linux-musleabihf-cross armv7m-linux-musleabi-cross armv7r-linux-musleabihf-cross)
440479
for i in "${FILES[@]}"; do
@@ -456,7 +495,8 @@ BuildReleaseLinuxMuslArm() {
456495
export CC=${cgo_cc}
457496
export CGO_ENABLED=1
458497
export GOARM=${arm}
459-
go build -o ./build/$appName-$os_arch -ldflags="$muslflags" -tags=jsoniter .
498+
CGO_LDFLAGS="-static" go build -o ./build/$appName-$os_arch -ldflags="$muslflags" -tags=jsoniter .
499+
AssertStaticBinary "./build/$appName-$os_arch"
460500
done
461501
}
462502

0 commit comments

Comments
 (0)