Skip to content

Add native build to CI and MUSL build #2490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions .github/workflows/build-native-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Build native image
defaults:
run:
shell: bash -euo pipefail -O nullglob {0}
on:
workflow_dispatch:
inputs:
ref:
type: string
description: "Git ref from which to release"
required: true
default: "master"
workflow_call:
inputs:
ref:
type: string
description: "Git ref from which to release"
required: true
default: "master"
env:
INPUT_REF: ${{ github.event.inputs.ref }}

jobs:
build_native_images:
name: Build native test server
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
os_family: linux
arch: amd64
musl: true
- runner: ubuntu-latest
os_family: linux
arch: amd64
musl: false
- runner: macos-13
os_family: macOS
arch: amd64
- runner: macos-latest
os_family: macOS
arch: arm64
- runner: ubuntu-24.04-arm
os_family: linux
arch: arm64
- runner: windows-latest
os_family: windows
arch: amd64
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
ref: ${{ env.INPUT_REF }}

- name: Set up Java
if: matrix.os_family != 'Linux'
uses: actions/setup-java@v4
with:
java-version: |
21
23
distribution: "graalvm"

- name: Set up Gradle
if: matrix.os_family != 'Linux'
uses: gradle/actions/setup-gradle@v4

- name: Build native test server (non-Docker)
if: matrix.os_family != 'Linux'
run: |
./gradlew -PnativeBuild :temporal-test-server:nativeCompile

- name: Build native test server (Docker non-musl)
if: matrix.os_family == 'Linux' && matrix.musl == false
run: |
docker run \
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
$(docker build -q ./docker/native-image) \
sh -c "./gradlew -PnativeBuild :temporal-test-server:nativeCompile"

- name: Build native test server (Docker musl)
if: matrix.os_family == 'Linux' && matrix.musl == true
run: |
docker run \
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
$(docker build -q ./docker/native-image-musl) \
sh -c "./gradlew -PnativeBuild -PnativeBuildMusl :temporal-test-server:nativeCompile"
# path ends in a wildcard because on windows the file ends in '.exe'
- name: Upload executable to workflow
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.musl && format('{0}_{1}_musl', matrix.os_family, matrix.arch) || format('{0}_{1}', matrix.os_family, matrix.arch)}}
path: |
temporal-test-server/build/native/nativeCompile/temporal-test-server*
if-no-files-found: error
retention-days: 1

10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: "21"
java-version: "23"
distribution: "temurin"

- name: Set up Gradle
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: |
21
23
11
distribution: "temurin"

Expand Down Expand Up @@ -188,3 +188,9 @@ jobs:

- name: Run copyright and code format checks
run: ./gradlew --no-daemon checkLicenseMain checkLicenses spotlessCheck

build_native_images:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it by intention that we are building native images for every CI run now or is this leftover from testing? If it is by intention, I would usually be concerned with unnecessarily using storage for all of these images, though I see we only retain for one day, but I wonder if it's even worth that vs just a workflow call option to not upload the artifacts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I do want to build as part of CI so we don't discover issue when trying to cut a release. I would be OK only doing the builds post merge or not including artifacts for CI

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me, especially if it's concurrent and doesn't take longer than the existing jobs (doesn't seem to though that poor macos-arm one in last CI run took a really long time). I do think we should skip uploading the artifact though, but not a big deal.

name: Build native test server
uses: ./.github/workflows/build-native-image.yml
with:
ref: ${{ github.event.pull_request.head.sha }}
67 changes: 3 additions & 64 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,70 +124,9 @@ jobs:
name: Build native test server
needs: create_draft_release
if: github.event.inputs.do_build_native_images == 'true'
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
os_family: linux
arch: amd64
- runner: macos-13
os_family: macOS
arch: amd64
- runner: macos-latest
os_family: macOS
arch: arm64
- runner: ubuntu-24.04-arm
os_family: linux
arch: arm64
- runner: windows-2019
os_family: windows
arch: amd64
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{ env.INPUT_REF }}

# See comment on temporary tag above. tldr: this is a local tag; never
# gets pushed
- name: Temporary tag
run: git tag "$INPUT_TAG"

- name: Set up Java
if: matrix.os_family != 'Linux'
uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "graalvm"

- name: Set up Gradle
if: matrix.os_family != 'Linux'
uses: gradle/actions/setup-gradle@v4

- name: Build native test server (non-Docker)
if: matrix.os_family != 'Linux'
run: |
./gradlew -PnativeBuild :temporal-test-server:nativeBuild

- name: Build native test server (Docker)
if: matrix.os_family == 'Linux'
run: |
docker run \
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
$(docker build -q ./docker/native-image) \
sh -c "./gradlew -PnativeBuild :temporal-test-server:nativeBuild"
# path ends in a wildcard because on windows the file ends in '.exe'
- name: Upload executable to workflow
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os_family }}_${{ matrix.arch }}
path: |
temporal-test-server/build/native/nativeCompile/temporal-test-server*
if-no-files-found: error
retention-days: 1
uses: ./.github/workflows/build-native-image.yml
with:
ref: ${{ github.event.inputs.ref }}

attach_to_release:
name: Attach native executables to release
Expand Down
18 changes: 18 additions & 0 deletions docker/native-image-musl/dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Use an old version of Ubuntu to build the test server to maintain compatibility with
# older versions of glibc, specifically glib 2.17.
FROM ubuntu:24.04
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java23
COPY --from=ghcr.io/graalvm/native-image-community:23 $JAVA_HOME $JAVA_HOME
ENV PATH="${JAVA_HOME}/bin:${PATH}"
RUN apt-get update
RUN apt-get install -y git build-essential curl binutils
COPY install-musl.sh /opt/install-musl.sh
RUN chmod +x /opt/install-musl.sh
WORKDIR /opt
# We need to build musl and zlibc with musl to for a static build
# See https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
RUN ./install-musl.sh
ENV MUSL_HOME=/opt/musl-toolchain
ENV PATH="$MUSL_HOME/bin:$PATH"
# Avoid errors like: "fatal: detected dubious ownership in repository"
RUN git config --global --add safe.directory '*'
28 changes: 28 additions & 0 deletions docker/native-image-musl/install-musl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Specify an installation directory for musl:
export MUSL_HOME=$PWD/musl-toolchain

# Download musl and zlib sources:
curl -O https://musl.libc.org/releases/musl-1.2.5.tar.gz
curl -O https://zlib.net/fossils/zlib-1.2.13.tar.gz

# Build musl from source
tar -xzvf musl-1.2.5.tar.gz
cd musl-1.2.5
./configure --prefix=$MUSL_HOME --static
# The next operation may require privileged access to system resources, so use sudo
make && make install
cd ..

# Install a symlink for use by native-image
ln -s $MUSL_HOME/bin/musl-gcc $MUSL_HOME/bin/x86_64-linux-musl-gcc

# Extend the system path and confirm that musl is available by printing its version
export PATH="$MUSL_HOME/bin:$PATH"
x86_64-linux-musl-gcc --version

# Build zlib with musl from source and install into the MUSL_HOME directory
tar -xzvf zlib-1.2.13.tar.gz
cd zlib-1.2.13
CC=musl-gcc ./configure --prefix=$MUSL_HOME --static
make && make install
cd ..
10 changes: 7 additions & 3 deletions docker/native-image/dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Use an old version of Ubuntu to build the test server to maintain compatibility with
# older versions of glibc, specifically glib 2.17.
FROM ubuntu:18.04
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java21
COPY --from=ghcr.io/graalvm/jdk-community:21 $JAVA_HOME $JAVA_HOME
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java23
COPY --from=ghcr.io/graalvm/native-image-community:23 $JAVA_HOME $JAVA_HOME
ENV PATH="${JAVA_HOME}/bin:${PATH}"
RUN apt-get update && apt-get install -y software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test
RUN apt-get update
RUN apt-get install -y git build-essential zlib1g-dev
# We need to update gcc and g++ to 10 for Graal to work on ARM64
RUN apt-get install -y git build-essential zlib1g-dev gcc-10 g++-10
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10
# Avoid errors like: "fatal: detected dubious ownership in repository"
RUN git config --global --add safe.directory '*'
2 changes: 1 addition & 1 deletion temporal-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ dependencies {

tasks.named('compileJava21Java') {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(21)
languageVersion = JavaLanguageVersion.of(23)
}
options.release = 21
}
Expand Down
9 changes: 7 additions & 2 deletions temporal-test-server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,14 @@ if (project.hasProperty("nativeBuild")) {
// If we're on linux, static link everything but libc. Otherwise link
// everything dynamically (note the '-' rather than '+' in front of
// StaticExecutable)
buildArgs.add(isLinux() ? "-H:+StaticExecutableWithDynamicLibC": "-H:-StaticExecutable")
if (isLinux() && !project.hasProperty("nativeBuildMusl")) {
buildArgs.add("-H:+StaticExecutableWithDynamicLibC")
} else if (isLinux() && project.hasProperty("nativeBuildMusl")) {
buildArgs.add("--static")
buildArgs.add("--libc=musl")
}
buildArgs.add("-H:+UnlockExperimentalVMOptions")
buildArgs.add("-O4")
buildArgs.add("-Os")

runtimeArgs.add("7233")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ Args = -H:+UnlockExperimentalVMOptions \
-H:JNIConfigurationResources=${.}/jni-config.json \
-H:ReflectionConfigurationResources=${.}/reflect-config.json \
-H:ResourceConfigurationResources=${.}/resource-config.json \
-H:SerializationConfigurationResources=${.}/serialization-config.json
-H:SerializationConfigurationResources=${.}/serialization-config.json \
--initialize-at-build-time=org.slf4j.helpers.SubstituteLoggerFactory \
--initialize-at-build-time=org.slf4j.helpers.NOPLoggerFactory

Loading