Build Node.js from Source #33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Node.js from Source | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| linux-x64: | |
| description: 'Build Linux x64' | |
| type: boolean | |
| default: true | |
| linux-arm64: | |
| description: 'Build Linux ARM64' | |
| type: boolean | |
| default: true | |
| macos-x64: | |
| description: 'Build macOS x64' | |
| type: boolean | |
| default: true | |
| macos-arm64: | |
| description: 'Build macOS ARM64' | |
| type: boolean | |
| default: true | |
| windows-x64: | |
| description: 'Build Windows x64' | |
| type: boolean | |
| default: true | |
| windows-arm64: | |
| description: 'Build Windows ARM64' | |
| type: boolean | |
| default: true | |
| env: | |
| ARTIFACT_RETENTION_DAYS: 1 | |
| NODE_TAG: v24.15.0 | |
| GIT_AUTHOR_NAME: github-actions[bot] | |
| GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com | |
| GIT_COMMITTER_NAME: github-actions[bot] | |
| GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com | |
| jobs: | |
| # ───────────────────────────────────────────── | |
| # Linux x64 | |
| # ───────────────────────────────────────────── | |
| build-linux-x64: | |
| if: inputs.linux-x64 | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - name: Set artifact name | |
| run: | | |
| ARTIFACT_NAME="node-$NODE_TAG-linux-x64" | |
| echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV | |
| echo "ARCHIVE_NAME=$ARTIFACT_NAME.tar.gz" >> $GITHUB_ENV | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y -q \ | |
| python3 g++ make ninja-build git \ | |
| libssl-dev pkg-config \ | |
| xz-utils curl ca-certificates | |
| - name: Clone Node.js ${{ env.NODE_TAG }} | |
| run: | | |
| git clone --depth 1 --branch "$NODE_TAG" \ | |
| https://github.com/nodejs/node.git node-src | |
| - name: Checkout repository (for patches) | |
| uses: actions/checkout@v6 | |
| with: | |
| path: repo | |
| - name: Apply patches | |
| working-directory: node-src | |
| run: ../repo/script/git-import-patches ../repo/patches | |
| - name: Configure | |
| working-directory: node-src | |
| run: | | |
| # --prefix: install root inside the staging directory | |
| # --tag: cleared so the version string is clean (e.g. v24.14.1, not v24.14.1-custom) | |
| # --ninja: use Ninja instead of Make for faster incremental builds | |
| # --experimental-enable-pointer-compression: compress V8 heap pointers from 8 to 4 bytes, reducing heap size | |
| # --experimental-pointer-compression-shared-cage: share the pointer compression cage across Isolates in the same process | |
| # --without-siphash: disable SipHash for V8 hash seeds, using a simpler alternative | |
| ./configure \ | |
| --prefix=/usr/local/$ARTIFACT_NAME \ | |
| --tag="" \ | |
| --ninja \ | |
| --experimental-enable-pointer-compression \ | |
| --experimental-pointer-compression-shared-cage \ | |
| --without-siphash | |
| - name: Build (this takes 20–40 min) | |
| working-directory: node-src | |
| run: make -j4 | |
| - name: Smoke test | |
| working-directory: node-src | |
| run: ./out/Release/node --version | |
| - name: Install into staging directory | |
| working-directory: node-src | |
| run: make install DESTDIR=$PWD/../stage | |
| - name: Smoke test npm | |
| run: ../stage/usr/local/$ARTIFACT_NAME/bin/npm --version | |
| working-directory: node-src | |
| - name: Package tarball (full install tree) | |
| run: | | |
| tar czf "$ARCHIVE_NAME" -C stage/usr/local $ARTIFACT_NAME | |
| echo "Archive size: $(du -sh $ARCHIVE_NAME | cut -f1)" | |
| echo "Top-level entries:" | |
| tar tzf "$ARCHIVE_NAME" | cut -d/ -f1-2 | sort -u | head -20 | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.ARCHIVE_NAME }} | |
| retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} | |
| # ───────────────────────────────────────────── | |
| # Linux ARM64 (GitHub-hosted) | |
| # ───────────────────────────────────────────── | |
| build-linux-arm64: | |
| if: inputs.linux-arm64 | |
| runs-on: ubuntu-22.04-arm | |
| steps: | |
| - name: Set artifact name | |
| run: | | |
| ARTIFACT_NAME="node-$NODE_TAG-linux-arm64" | |
| echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV | |
| echo "ARCHIVE_NAME=$ARTIFACT_NAME.tar.gz" >> $GITHUB_ENV | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y -q \ | |
| python3 g++-12 make ninja-build git \ | |
| libssl-dev pkg-config \ | |
| xz-utils curl ca-certificates | |
| - name: Clone Node.js ${{ env.NODE_TAG }} | |
| run: | | |
| git clone --depth 1 --branch "$NODE_TAG" \ | |
| https://github.com/nodejs/node.git node-src | |
| - name: Checkout repository (for patches) | |
| uses: actions/checkout@v6 | |
| with: | |
| path: repo | |
| - name: Apply patches | |
| working-directory: node-src | |
| run: ../repo/script/git-import-patches ../repo/patches | |
| - name: Configure | |
| working-directory: node-src | |
| env: | |
| CC: gcc-12 | |
| CXX: g++-12 | |
| run: | | |
| # --prefix: install root inside the staging directory | |
| # --ninja: use Ninja instead of Make for faster incremental builds | |
| # --experimental-enable-pointer-compression: compress V8 heap pointers from 8 to 4 bytes, reducing heap size | |
| # --experimental-pointer-compression-shared-cage: share the pointer compression cage across Isolates in the same process | |
| # --without-siphash: disable SipHash for V8 hash seeds, using a simpler alternative | |
| ./configure \ | |
| --prefix=/usr/local/$ARTIFACT_NAME \ | |
| --ninja \ | |
| --experimental-enable-pointer-compression \ | |
| --experimental-pointer-compression-shared-cage \ | |
| --without-siphash | |
| - name: Build | |
| working-directory: node-src | |
| env: | |
| CC: gcc-12 | |
| CXX: g++-12 | |
| run: make -j4 | |
| - name: Smoke test | |
| working-directory: node-src | |
| run: ./out/Release/node --version | |
| - name: Install into staging directory | |
| working-directory: node-src | |
| run: make install DESTDIR=$PWD/../stage | |
| - name: Smoke test npm | |
| working-directory: node-src | |
| run: ../stage/usr/local/$ARTIFACT_NAME/bin/npm --version | |
| - name: Package tarball (full install tree) | |
| run: | | |
| tar czf "$ARCHIVE_NAME" -C stage/usr/local $ARTIFACT_NAME | |
| echo "Archive size: $(du -sh $ARCHIVE_NAME | cut -f1)" | |
| echo "Top-level entries:" | |
| tar tzf "$ARCHIVE_NAME" | cut -d/ -f1-2 | sort -u | head -20 | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.ARCHIVE_NAME }} | |
| retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} | |
| # ───────────────────────────────────────────── | |
| # macOS x64 | |
| # ───────────────────────────────────────────── | |
| build-macos-x64: | |
| if: inputs.macos-x64 | |
| runs-on: macos-15-intel # last Intel runner | |
| steps: | |
| - name: Set artifact name | |
| run: | | |
| ARTIFACT_NAME="node-$NODE_TAG-darwin-x64" | |
| echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV | |
| echo "ARCHIVE_NAME=$ARTIFACT_NAME.tar.gz" >> $GITHUB_ENV | |
| - name: Install build dependencies | |
| run: brew install python3 openssl pkg-config ninja | |
| - name: Clone Node.js ${{ env.NODE_TAG }} | |
| run: | | |
| git clone --depth 1 --branch "$NODE_TAG" \ | |
| https://github.com/nodejs/node.git node-src | |
| - name: Checkout repository (for patches) | |
| uses: actions/checkout@v6 | |
| with: | |
| path: repo | |
| - name: Apply patches | |
| working-directory: node-src | |
| run: ../repo/script/git-import-patches ../repo/patches | |
| - name: Configure | |
| working-directory: node-src | |
| run: | | |
| # --prefix: install root inside the staging directory | |
| # --openssl-use-def-ca-store: use the macOS system Keychain for CA certificates instead of the bundled Mozilla store | |
| # --ninja: use Ninja instead of Make for faster incremental builds | |
| # --experimental-enable-pointer-compression: compress V8 heap pointers from 8 to 4 bytes, reducing heap size | |
| # --experimental-pointer-compression-shared-cage: share the pointer compression cage across Isolates in the same process | |
| # --without-siphash: disable SipHash for V8 hash seeds, using a simpler alternative | |
| ./configure \ | |
| --prefix=/usr/local/$ARTIFACT_NAME \ | |
| --openssl-use-def-ca-store \ | |
| --ninja \ | |
| --experimental-enable-pointer-compression \ | |
| --experimental-pointer-compression-shared-cage \ | |
| --without-siphash | |
| - name: Build | |
| working-directory: node-src | |
| run: make | |
| - name: Smoke test | |
| working-directory: node-src | |
| run: ./out/Release/node --version | |
| - name: Install into staging directory | |
| working-directory: node-src | |
| run: make install DESTDIR=$PWD/../stage | |
| - name: Smoke test npm | |
| working-directory: node-src | |
| run: ../stage/usr/local/$ARTIFACT_NAME/bin/npm --version | |
| - name: Package tarball (full install tree) | |
| run: | | |
| tar czf "$ARCHIVE_NAME" -C stage/usr/local $ARTIFACT_NAME | |
| echo "Archive size: $(du -sh $ARCHIVE_NAME | cut -f1)" | |
| echo "Top-level entries:" | |
| tar tzf "$ARCHIVE_NAME" | cut -d/ -f1-2 | sort -u | head -20 | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.ARCHIVE_NAME }} | |
| retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} | |
| # ───────────────────────────────────────────── | |
| # macOS ARM64 (Apple Silicon) | |
| # ───────────────────────────────────────────── | |
| build-macos-arm64: | |
| if: inputs.macos-arm64 | |
| runs-on: macos-15 # M1/M2 runner — ships with Xcode 16 (Clang 16+) | |
| steps: | |
| - name: Set artifact name | |
| run: | | |
| ARTIFACT_NAME="node-$NODE_TAG-darwin-arm64" | |
| echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV | |
| echo "ARCHIVE_NAME=$ARTIFACT_NAME.tar.gz" >> $GITHUB_ENV | |
| - name: Select Xcode 16 | |
| # Ensures Clang 16+ is active — required by V8's C++20 TypeIndex cast | |
| # in deps/v8/src/wasm/value-type.h (fails on Clang 15 / Xcode 15) | |
| run: | | |
| sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer | |
| echo "SDKROOT=$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV | |
| - name: Verify Clang version (must be 16+) | |
| run: clang++ --version | |
| - name: Install build dependencies | |
| run: brew install python3 openssl pkg-config ninja | |
| - name: Clone Node.js ${{ env.NODE_TAG }} | |
| run: | | |
| git clone --depth 1 --branch "$NODE_TAG" \ | |
| https://github.com/nodejs/node.git node-src | |
| - name: Checkout repository (for patches) | |
| uses: actions/checkout@v6 | |
| with: | |
| path: repo | |
| - name: Apply patches | |
| working-directory: node-src | |
| run: ../repo/script/git-import-patches ../repo/patches | |
| - name: Configure | |
| working-directory: node-src | |
| env: | |
| # Point the build system at the Xcode 16 toolchain explicitly | |
| CC: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang | |
| CXX: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ | |
| run: | | |
| # --prefix: install root inside the staging directory | |
| # --openssl-use-def-ca-store: use the macOS system Keychain for CA certificates instead of the bundled Mozilla store | |
| # --ninja: use Ninja instead of Make for faster incremental builds | |
| # --experimental-enable-pointer-compression: compress V8 heap pointers from 8 to 4 bytes, reducing heap size | |
| # --experimental-pointer-compression-shared-cage: share the pointer compression cage across Isolates in the same process | |
| # --without-siphash: disable SipHash for V8 hash seeds, using a simpler alternative | |
| ./configure \ | |
| --prefix=/usr/local/$ARTIFACT_NAME \ | |
| --openssl-use-def-ca-store \ | |
| --ninja \ | |
| --experimental-enable-pointer-compression \ | |
| --experimental-pointer-compression-shared-cage \ | |
| --without-siphash | |
| - name: Build | |
| working-directory: node-src | |
| env: | |
| CC: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang | |
| CXX: /Applications/Xcode_16.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ | |
| run: make | |
| - name: Smoke test | |
| working-directory: node-src | |
| run: ./out/Release/node --version | |
| - name: Install into staging directory | |
| working-directory: node-src | |
| run: make install DESTDIR=$PWD/../stage | |
| - name: Smoke test npm | |
| working-directory: node-src | |
| run: ../stage/usr/local/$ARTIFACT_NAME/bin/npm --version | |
| - name: Package tarball (full install tree) | |
| run: | | |
| tar czf "$ARCHIVE_NAME" -C stage/usr/local $ARTIFACT_NAME | |
| echo "Archive size: $(du -sh $ARCHIVE_NAME | cut -f1)" | |
| echo "Top-level entries:" | |
| tar tzf "$ARCHIVE_NAME" | cut -d/ -f1-2 | sort -u | head -20 | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.ARCHIVE_NAME }} | |
| retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} | |
| # ───────────────────────────────────────────── | |
| # Windows x64 | |
| # ───────────────────────────────────────────── | |
| build-windows-x64: | |
| if: inputs.windows-x64 | |
| runs-on: windows-2025 | |
| steps: | |
| - name: Install NASM (required by OpenSSL) | |
| run: choco install nasm -y | |
| - name: Clone Node.js ${{ env.NODE_TAG }} | |
| run: | | |
| git clone --depth 1 --branch "$env:NODE_TAG" ` | |
| https://github.com/nodejs/node.git node-src | |
| - name: Checkout repository (for patches) | |
| uses: actions/checkout@v6 | |
| with: | |
| path: repo | |
| - name: Apply patches | |
| working-directory: node-src | |
| shell: bash | |
| run: ../repo/script/git-import-patches ../repo/patches | |
| - name: Build (vcbuild.bat handles everything on Windows) | |
| working-directory: node-src | |
| shell: cmd | |
| run: vcbuild.bat release x64 no-cctest package | |
| - name: Smoke test | |
| working-directory: node-src | |
| shell: cmd | |
| run: .\Release\node.exe --version | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: node-${{ env.NODE_TAG }}-win-x64 | |
| path: node-src/Release/node-${{ env.NODE_TAG }}-win-x64.zip | |
| retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} | |
| # ───────────────────────────────────────────── | |
| # Windows ARM64 | |
| # ───────────────────────────────────────────── | |
| build-windows-arm64: | |
| if: inputs.windows-arm64 | |
| runs-on: windows-11-arm | |
| steps: | |
| - name: Install NASM (required by OpenSSL) | |
| run: choco install nasm -y | |
| - name: Clone Node.js ${{ env.NODE_TAG }} | |
| run: | | |
| git clone --depth 1 --branch "$env:NODE_TAG" ` | |
| https://github.com/nodejs/node.git node-src | |
| - name: Checkout repository (for patches) | |
| uses: actions/checkout@v6 | |
| with: | |
| path: repo | |
| - name: Apply patches | |
| working-directory: node-src | |
| shell: bash | |
| run: ../repo/script/git-import-patches ../repo/patches | |
| - name: Build | |
| working-directory: node-src | |
| shell: cmd | |
| run: vcbuild.bat release arm64 no-cctest package | |
| - name: Smoke test | |
| working-directory: node-src | |
| shell: cmd | |
| run: .\Release\node.exe --version | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: node-${{ env.NODE_TAG }}-win-arm64 | |
| path: node-src/Release/node-${{ env.NODE_TAG }}-win-arm64.zip | |
| retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} | |
| # ───────────────────────────────────────────── | |
| # Create GitHub Release and attach all binaries | |
| # ───────────────────────────────────────────── | |
| release: | |
| needs: | |
| - build-linux-x64 | |
| - build-linux-arm64 | |
| - build-macos-x64 | |
| - build-macos-arm64 | |
| - build-windows-x64 | |
| - build-windows-arm64 | |
| runs-on: ubuntu-latest | |
| # Run as long as at least one build job succeeded; resolve-version alone is not enough | |
| if: >- | |
| always() && ( | |
| needs.build-linux-x64.result == 'success' || | |
| needs.build-linux-arm64.result == 'success' || | |
| needs.build-macos-x64.result == 'success' || | |
| needs.build-macos-arm64.result == 'success' || | |
| needs.build-windows-x64.result == 'success' || | |
| needs.build-windows-arm64.result == 'success' | |
| ) | |
| permissions: | |
| contents: write # required to create releases and upload assets | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| steps: | |
| - name: Download all build artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: artifacts # each artifact lands in artifacts/<artifact-name>/ | |
| - name: Flatten artifacts into release-assets/ | |
| run: | | |
| mkdir release-assets | |
| find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" \) \ | |
| -exec mv {} release-assets/ \; | |
| ls -lh release-assets/ | |
| - name: Generate SHA256 checksums | |
| working-directory: release-assets | |
| if: >- | |
| needs.build-linux-x64.result == 'success' && | |
| needs.build-linux-arm64.result == 'success' && | |
| needs.build-macos-x64.result == 'success' && | |
| needs.build-macos-arm64.result == 'success' && | |
| needs.build-windows-x64.result == 'success' && | |
| needs.build-windows-arm64.result == 'success' | |
| run: | | |
| sha256sum * > SHASUMS256.txt | |
| cat SHASUMS256.txt | |
| - name: Create GitHub Release and upload assets | |
| run: | | |
| if gh release view "$NODE_TAG" --repo "$GITHUB_REPOSITORY" &>/dev/null; then | |
| echo "Release $NODE_TAG already exists — updating assets." | |
| # Delete any existing assets that share a name with what we're about to upload | |
| for file in release-assets/*; do | |
| asset_name=$(basename "$file") | |
| if gh release view "$NODE_TAG" --repo "$GITHUB_REPOSITORY" --json assets \ | |
| --jq ".assets[].name" | grep -qx "$asset_name"; then | |
| echo "Deleting existing asset: $asset_name" | |
| gh release delete-asset "$NODE_TAG" "$asset_name" \ | |
| --repo "$GITHUB_REPOSITORY" --yes | |
| fi | |
| done | |
| # Upload the fresh assets | |
| gh release upload "$NODE_TAG" release-assets/* \ | |
| --repo "$GITHUB_REPOSITORY" | |
| else | |
| echo "Creating new release $NODE_TAG." | |
| gh release create "$NODE_TAG" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "${NODE_TAG}" \ | |
| --notes "Custom build of Node.js ${NODE_TAG} from source that has pointer compression enabled. Verify downloads with \`SHASUMS256.txt\`." \ | |
| release-assets/* | |
| fi |