Repository: vercel/next.js
Pull request: fix(CI): On musl/alpine builds, pin llvm to llvm20, add llvm bin directory to path

Alpine Edge recently removed `llvm-config` from the PATH:

- 3.22: https://pkgs.alpinelinux.org/contents?file=llvm-config&path=&name=&branch=v3.22&repo=&arch=x86_64
- Edge: https://pkgs.alpinelinux.org/contents?file=llvm-config&path=&name=&branch=edge&repo=&arch=x86_64

CI job: https://github.com/vercel/next.js/actions/runs/16208743604

Also, fix a bunch of escaping problems with how we invoke bash inside of docker...

Closes PACK-5058

Changed files:
filename: .github/workflows/build_and_deploy.yml
patch: @@ -224,16 +224,16 @@ jobs:
             # - zig linker with portable glibc is avoided as it has known issues with static tls + node.js + multi threaded
             #   environment.
             docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-x64
-            build: >-
-              set -ex &&
-              apt update &&
-              apt install -y pkg-config xz-utils dav1d libdav1d-dev &&
-              rustup show &&
-              rustup target add x86_64-unknown-linux-gnu &&
-              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" &&
-              unset CC_x86_64_unknown_linux_gnu && unset CC &&
-              cd packages/next-swc && npm run build-native-release -- --target x86_64-unknown-linux-gnu &&
-              strip native/next-swc.*.node &&
+            build: |
+              apt update
+              apt install -y pkg-config xz-utils dav1d libdav1d-dev
+              rustup show
+              rustup target add x86_64-unknown-linux-gnu
+              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}"
+              unset CC_x86_64_unknown_linux_gnu && unset CC
+              cd packages/next-swc
+              npm run build-native-release -- --target x86_64-unknown-linux-gnu
+              strip native/next-swc.*.node
               objdump -T native/next-swc.*.node | grep GLIBC_
 
           - host:
@@ -244,16 +244,17 @@ jobs:
 
             target: 'x86_64-unknown-linux-musl'
             docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine
-            build: >-
-              set -ex &&
-              apk update &&
-              apk del llvm &&
-              apk add --no-cache libc6-compat pkgconfig dav1d libdav1d dav1d-dev clang-static llvm llvm-dev &&
-              rustup show &&
-              rustup target add x86_64-unknown-linux-musl &&
-              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" &&
-              export RUSTFLAGS='--cfg tokio_unstable -Zshare-generics=y -Zthreads=8 -Csymbol-mangling-version=v0 -Ctarget-feature=-crt-static' &&
-              cd packages/next-swc && npm run build-native-release -- --target x86_64-unknown-linux-musl &&
+            build: |
+              apk update
+              apk del llvm
+              apk add --no-cache libc6-compat pkgconfig dav1d libdav1d dav1d-dev clang20-static llvm20 llvm20-dev
+              export PATH="/usr/lib/llvm20/bin:$PATH"
+              rustup show
+              rustup target add x86_64-unknown-linux-musl
+              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}"
+              export RUSTFLAGS='--cfg tokio_unstable -Zshare-generics=y -Zthreads=8 -Csymbol-mangling-version=v0 -Ctarget-feature=-crt-static'
+              cd packages/next-swc
+              npm run build-native-release -- --target x86_64-unknown-linux-musl
               strip native/next-swc.*.node
 
           - host:
@@ -264,18 +265,18 @@ jobs:
 
             target: 'aarch64-unknown-linux-gnu'
             docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-aarch64
-            build: >-
-              set -ex &&
-              apt update &&
-              apt install -y pkg-config xz-utils dav1d libdav1d-dev &&
-              export JEMALLOC_SYS_WITH_LG_PAGE=16 &&
-              rustup show &&
-              rustup target add aarch64-unknown-linux-gnu &&
-              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" &&
-              export CC_aarch64_unknown_linux_gnu=/usr/bin/clang &&
-              export CFLAGS_aarch64_unknown_linux_gnu=\"--target=aarch64-unknown-linux-gnu --sysroot=/usr/aarch64-unknown-linux-gnu\" &&
-              cd packages/next-swc && npm run build-native-release -- --target aarch64-unknown-linux-gnu &&
-              llvm-strip -x native/next-swc.*.node &&
+            build: |
+              apt update
+              apt install -y pkg-config xz-utils dav1d libdav1d-dev
+              export JEMALLOC_SYS_WITH_LG_PAGE=16
+              rustup show
+              rustup target add aarch64-unknown-linux-gnu
+              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}"
+              export CC_aarch64_unknown_linux_gnu=/usr/bin/clang
+              export CFLAGS_aarch64_unknown_linux_gnu="--target=aarch64-unknown-linux-gnu --sysroot=/usr/aarch64-unknown-linux-gnu"
+              cd packages/next-swc
+              npm run build-native-release -- --target aarch64-unknown-linux-gnu
+              llvm-strip -x native/next-swc.*.node
               objdump -T native/next-swc.*.node | grep GLIBC_
 
           - host:
@@ -286,17 +287,18 @@ jobs:
 
             target: 'aarch64-unknown-linux-musl'
             docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine
-            build: >-
-              set -ex &&
-              apk update &&
-              apk del llvm &&
-              apk add --no-cache libc6-compat pkgconfig dav1d libdav1d dav1d-dev clang-static llvm llvm-dev &&
-              export JEMALLOC_SYS_WITH_LG_PAGE=16 &&
-              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" &&
-              rustup show &&
-              rustup target add aarch64-unknown-linux-musl &&
-              export RUSTFLAGS='--cfg tokio_unstable -Zshare-generics=y -Zthreads=8 -Zunstable-options -Csymbol-mangling-version=v0 -Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker' &&
-              cd packages/next-swc && npm run build-native-release -- --target aarch64-unknown-linux-musl &&
+            build: |
+              apk update
+              apk del llvm
+              apk add --no-cache libc6-compat pkgconfig dav1d libdav1d dav1d-dev clang20-static llvm20 llvm20-dev
+              export PATH="/usr/lib/llvm20/bin:$PATH"
+              export JEMALLOC_SYS_WITH_LG_PAGE=16
+              npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}"
+              rustup show
+              rustup target add aarch64-unknown-linux-musl
+              export RUSTFLAGS='--cfg tokio_unstable -Zshare-generics=y -Zthreads=8 -Zunstable-options -Csymbol-mangling-version=v0 -Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker'
+              cd packages/next-swc
+              npm run build-native-release -- --target aarch64-unknown-linux-musl
               llvm-strip -x native/next-swc.*.node
 
     name: stable - ${{ matrix.settings.target }} - node@16
@@ -373,6 +375,9 @@ jobs:
 
       - name: Build in docker
         if: ${{ matrix.settings.docker && steps.build-exists.outputs.BUILD_EXISTS == 'no' }}
+        env:
+          # put the command in an environment variable to avoid escaping issues
+          DOCKER_CMD: ${{ matrix.settings.build }}
         run: |
           docker run -v "/var/run/docker.sock":"/var/run/docker.sock" \
             -e CI -e RUST_BACKTRACE -e NAPI_CLI_VERSION -e CARGO_TERM_COLOR -e CARGO_INCREMENTAL \
@@ -382,8 +387,9 @@ jobs:
             -v ${{ env.HOME }}/.cargo/registry:/root/.cargo/registry \
             -v ${{ github.workspace }}:/build \
             -w /build \
-            --entrypoint=bash ${{ matrix.settings.docker }} \
-            -c "${{ matrix.settings.build }}"
+            --entrypoint=bash \
+            ${{ matrix.settings.docker }} \
+            -xeo pipefail -c "$DOCKER_CMD" # these args are passed to the entrypoint (bash)
 
       - name: cache build
         if: ${{ matrix.settings.docker && steps.build-exists.outputs.BUILD_EXISTS == 'no' }}