Skip to content

Commit bdc94f7

Browse files
Add native build to CI and MUSL build (#2490)
Add native build to CI
1 parent 4f313bb commit bdc94f7

File tree

14 files changed

+507
-1445
lines changed

14 files changed

+507
-1445
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: Build native image
2+
permissions:
3+
contents: read
4+
defaults:
5+
run:
6+
shell: bash -euo pipefail -O nullglob {0}
7+
on:
8+
workflow_dispatch:
9+
inputs:
10+
ref:
11+
type: string
12+
description: "Git ref from which to release"
13+
required: true
14+
default: "master"
15+
upload_artifact:
16+
type: boolean
17+
description: "Upload the native test server executable as an artifact"
18+
required: false
19+
default: false
20+
workflow_call:
21+
inputs:
22+
ref:
23+
type: string
24+
description: "Git ref from which to release"
25+
required: true
26+
default: "master"
27+
upload_artifact:
28+
type: boolean
29+
description: "Upload the native test server executable as an artifact"
30+
required: false
31+
default: false
32+
env:
33+
INPUT_REF: ${{ github.event.inputs.ref }}
34+
35+
jobs:
36+
build_native_images:
37+
name: Build native test server
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
include:
42+
- runner: ubuntu-latest
43+
os_family: linux
44+
arch: amd64
45+
musl: true
46+
- runner: ubuntu-latest
47+
os_family: linux
48+
arch: amd64
49+
musl: false
50+
- runner: macos-13
51+
os_family: macOS
52+
arch: amd64
53+
- runner: macos-latest
54+
os_family: macOS
55+
arch: arm64
56+
- runner: ubuntu-24.04-arm
57+
os_family: linux
58+
arch: arm64
59+
- runner: windows-latest
60+
os_family: windows
61+
arch: amd64
62+
runs-on: ${{ matrix.runner }}
63+
steps:
64+
- name: Checkout repo
65+
uses: actions/checkout@v4
66+
with:
67+
fetch-depth: 0
68+
submodules: recursive
69+
ref: ${{ env.INPUT_REF }}
70+
71+
- name: Set up Java
72+
if: matrix.os_family != 'Linux'
73+
uses: actions/setup-java@v4
74+
with:
75+
java-version: 23
76+
distribution: "graalvm"
77+
78+
- name: Set up Gradle
79+
if: matrix.os_family != 'Linux'
80+
uses: gradle/actions/setup-gradle@v4
81+
82+
- name: Build native test server (non-Docker)
83+
if: matrix.os_family != 'Linux'
84+
run: |
85+
./gradlew -PnativeBuild :temporal-test-server:nativeCompile
86+
87+
- name: Build native test server (Docker non-musl)
88+
if: matrix.os_family == 'Linux' && matrix.musl == false
89+
run: |
90+
docker run \
91+
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
92+
$(docker build -q ./docker/native-image) \
93+
sh -c "./gradlew -PnativeBuild :temporal-test-server:nativeCompile"
94+
95+
- name: Build native test server (Docker musl)
96+
if: matrix.os_family == 'Linux' && matrix.musl == true
97+
run: |
98+
docker run \
99+
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
100+
$(docker build -q ./docker/native-image-musl) \
101+
sh -c "./gradlew -PnativeBuild -PnativeBuildMusl :temporal-test-server:nativeCompile"
102+
# path ends in a wildcard because on windows the file ends in '.exe'
103+
- name: Upload executable to workflow
104+
if: ${{ github.event.inputs.upload_artifact == 'true'}}
105+
uses: actions/upload-artifact@v4
106+
with:
107+
name: ${{ matrix.musl && format('{0}_{1}_musl', matrix.os_family, matrix.arch) || format('{0}_{1}', matrix.os_family, matrix.arch)}}
108+
path: |
109+
temporal-test-server/build/native/nativeCompile/temporal-test-server*
110+
if-no-files-found: error
111+
retention-days: 1
112+

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
name: Continuous Integration
2+
permissions:
3+
contents: read
24
on:
35
pull_request:
46
push:
@@ -191,3 +193,9 @@ jobs:
191193

192194
- name: Run copyright and code format checks
193195
run: ./gradlew --no-daemon spotlessCheck
196+
197+
build_native_images:
198+
name: Build native test server
199+
uses: ./.github/workflows/build-native-image.yml
200+
with:
201+
ref: ${{ github.event.pull_request.head.sha }}

.github/workflows/prepare-release.yml

Lines changed: 4 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -124,70 +124,10 @@ jobs:
124124
name: Build native test server
125125
needs: create_draft_release
126126
if: github.event.inputs.do_build_native_images == 'true'
127-
strategy:
128-
fail-fast: false
129-
matrix:
130-
include:
131-
- runner: ubuntu-latest
132-
os_family: linux
133-
arch: amd64
134-
- runner: macos-13
135-
os_family: macOS
136-
arch: amd64
137-
- runner: macos-latest
138-
os_family: macOS
139-
arch: arm64
140-
- runner: ubuntu-24.04-arm
141-
os_family: linux
142-
arch: arm64
143-
- runner: windows-2019
144-
os_family: windows
145-
arch: amd64
146-
runs-on: ${{ matrix.runner }}
147-
steps:
148-
- name: Checkout repo
149-
uses: actions/checkout@v4
150-
with:
151-
submodules: recursive
152-
ref: ${{ env.INPUT_REF }}
153-
154-
# See comment on temporary tag above. tldr: this is a local tag; never
155-
# gets pushed
156-
- name: Temporary tag
157-
run: git tag "$INPUT_TAG"
158-
159-
- name: Set up Java
160-
if: matrix.os_family != 'Linux'
161-
uses: actions/setup-java@v4
162-
with:
163-
java-version: "21"
164-
distribution: "graalvm"
165-
166-
- name: Set up Gradle
167-
if: matrix.os_family != 'Linux'
168-
uses: gradle/actions/setup-gradle@v4
169-
170-
- name: Build native test server (non-Docker)
171-
if: matrix.os_family != 'Linux'
172-
run: |
173-
./gradlew -PnativeBuild :temporal-test-server:nativeBuild
174-
175-
- name: Build native test server (Docker)
176-
if: matrix.os_family == 'Linux'
177-
run: |
178-
docker run \
179-
--rm -w /github/workspace -v "$(pwd):/github/workspace" \
180-
$(docker build -q ./docker/native-image) \
181-
sh -c "./gradlew -PnativeBuild :temporal-test-server:nativeBuild"
182-
# path ends in a wildcard because on windows the file ends in '.exe'
183-
- name: Upload executable to workflow
184-
uses: actions/upload-artifact@v4
185-
with:
186-
name: ${{ matrix.os_family }}_${{ matrix.arch }}
187-
path: |
188-
temporal-test-server/build/native/nativeCompile/temporal-test-server*
189-
if-no-files-found: error
190-
retention-days: 1
127+
uses: ./.github/workflows/build-native-image.yml
128+
with:
129+
upload_artifact: true
130+
ref: ${{ github.event.inputs.ref }}
191131

192132
attach_to_release:
193133
name: Attach native executables to release

docker/native-image-musl/dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This Dockerfile builds a GraalVM Native Image Test Server with musl support.
2+
FROM ubuntu:24.04
3+
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java23
4+
COPY --from=ghcr.io/graalvm/native-image-community:23 $JAVA_HOME $JAVA_HOME
5+
ENV PATH="${JAVA_HOME}/bin:${PATH}"
6+
RUN apt-get -y update --allow-releaseinfo-change && apt-get install -y -V git build-essential curl binutils
7+
COPY install-musl.sh /opt/install-musl.sh
8+
RUN chmod +x /opt/install-musl.sh
9+
WORKDIR /opt
10+
# We need to build musl and zlibc with musl to for a static build
11+
# See https://www.graalvm.org/21.3/reference-manual/native-image/StaticImages/index.html
12+
RUN ./install-musl.sh
13+
ENV MUSL_HOME=/opt/musl-toolchain
14+
ENV PATH="$MUSL_HOME/bin:$PATH"
15+
# Avoid errors like: "fatal: detected dubious ownership in repository"
16+
RUN git config --global --add safe.directory '*'
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Specify an installation directory for musl:
2+
export MUSL_HOME=$PWD/musl-toolchain
3+
4+
# Download musl and zlib sources:
5+
curl -O https://musl.libc.org/releases/musl-1.2.5.tar.gz
6+
curl -O https://zlib.net/fossils/zlib-1.2.13.tar.gz
7+
8+
# Build musl from source
9+
tar -xzvf musl-1.2.5.tar.gz
10+
cd musl-1.2.5
11+
./configure --prefix=$MUSL_HOME --static
12+
# The next operation may require privileged access to system resources, so use sudo
13+
make && make install
14+
cd ..
15+
16+
# Install a symlink for use by native-image
17+
ln -s $MUSL_HOME/bin/musl-gcc $MUSL_HOME/bin/x86_64-linux-musl-gcc
18+
19+
# Extend the system path and confirm that musl is available by printing its version
20+
export PATH="$MUSL_HOME/bin:$PATH"
21+
x86_64-linux-musl-gcc --version
22+
23+
# Build zlib with musl from source and install into the MUSL_HOME directory
24+
tar -xzvf zlib-1.2.13.tar.gz
25+
cd zlib-1.2.13
26+
CC=musl-gcc ./configure --prefix=$MUSL_HOME --static
27+
make && make install
28+
cd ..

docker/native-image/dockerfile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
# This Dockerfile builds a GraalVM Native Image Test Server with glibc support.
12
# Use an old version of Ubuntu to build the test server to maintain compatibility with
23
# older versions of glibc, specifically glib 2.17.
34
FROM ubuntu:18.04
4-
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java21
5-
COPY --from=ghcr.io/graalvm/jdk-community:21 $JAVA_HOME $JAVA_HOME
5+
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java23
6+
COPY --from=ghcr.io/graalvm/native-image-community:23 $JAVA_HOME $JAVA_HOME
67
ENV PATH="${JAVA_HOME}/bin:${PATH}"
8+
RUN apt-get -y update --allow-releaseinfo-change && apt-get install -V -y software-properties-common
9+
RUN add-apt-repository ppa:ubuntu-toolchain-r/test
710
RUN apt-get update
8-
RUN apt-get install -y git build-essential zlib1g-dev
11+
# We need to update gcc and g++ to 10 for Graal to work on ARM64
12+
RUN apt-get install -y git build-essential zlib1g-dev gcc-10 g++-10
13+
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10
914
# Avoid errors like: "fatal: detected dubious ownership in repository"
1015
RUN git config --global --add safe.directory '*'

temporal-sdk/build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,14 @@ dependencies {
5151
}
5252

5353
tasks.named('compileJava21Java') {
54-
javaCompiler = javaToolchains.compilerFor {
55-
languageVersion = JavaLanguageVersion.of(21)
54+
// Gradle toolchains are too strict and require the JDK to match the specified version exactly.
55+
// This is a workaround to use a JDK 21+ compiler.
56+
//
57+
// See also: https://github.com/gradle/gradle/issues/16256
58+
if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_21)) {
59+
javaCompiler = javaToolchains.compilerFor {
60+
languageVersion = JavaLanguageVersion.of(21)
61+
}
5662
}
5763
options.release = 21
5864
}

temporal-test-server/build.gradle

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,14 @@ if (project.hasProperty("nativeBuild")) {
120120
// If we're on linux, static link everything but libc. Otherwise link
121121
// everything dynamically (note the '-' rather than '+' in front of
122122
// StaticExecutable)
123-
buildArgs.add(isLinux() ? "-H:+StaticExecutableWithDynamicLibC": "-H:-StaticExecutable")
123+
if (isLinux() && !project.hasProperty("nativeBuildMusl")) {
124+
buildArgs.add("--static-nolibc")
125+
} else if (isLinux() && project.hasProperty("nativeBuildMusl")) {
126+
buildArgs.add("--static")
127+
buildArgs.add("--libc=musl")
128+
}
124129
buildArgs.add("-H:+UnlockExperimentalVMOptions")
125-
buildArgs.add("-O4")
130+
buildArgs.add("-Os")
126131

127132
runtimeArgs.add("7233")
128133
}

temporal-test-server/src/main/resources/META-INF/native-image/io.temporal/temporal-test-server/jni-config.json

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,29 @@
99
},
1010
{
1111
"name":"java.lang.String",
12-
"methods":[{"name":"lastIndexOf","parameterTypes":["int"] }, {"name":"substring","parameterTypes":["int"] }]
12+
"methods":[
13+
{"name":"lastIndexOf","parameterTypes":["int"] },
14+
{"name":"substring","parameterTypes":["int"] }
15+
]
1316
},
1417
{
1518
"name":"java.lang.System",
16-
"methods":[{"name":"getProperty","parameterTypes":["java.lang.String"] }, {"name":"setProperty","parameterTypes":["java.lang.String","java.lang.String"] }]
17-
},
18-
{
19-
"name":"sun.instrument.InstrumentationImpl",
20-
"methods":[{"name":"<init>","parameterTypes":["long","boolean","boolean","boolean"] }, {"name":"loadClassAndCallAgentmain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"loadClassAndCallPremain","parameterTypes":["java.lang.String","java.lang.String"] }, {"name":"transform","parameterTypes":["java.lang.Module","java.lang.ClassLoader","java.lang.String","java.lang.Class","java.security.ProtectionDomain","byte[]","boolean"] }]
19+
"methods":[
20+
{"name":"getProperty","parameterTypes":["java.lang.String"] },
21+
{"name":"setProperty","parameterTypes":["java.lang.String","java.lang.String"] }
22+
]
2123
},
2224
{
2325
"name":"sun.management.VMManagementImpl",
24-
"fields":[{"name":"compTimeMonitoringSupport"}, {"name":"currentThreadCpuTimeSupport"}, {"name":"objectMonitorUsageSupport"}, {"name":"otherThreadCpuTimeSupport"}, {"name":"remoteDiagnosticCommandsSupport"}, {"name":"synchronizerUsageSupport"}, {"name":"threadAllocatedMemorySupport"}, {"name":"threadContentionMonitoringSupport"}]
25-
},
26-
{
27-
"name":"worker.org.gradle.process.internal.worker.GradleWorkerMain",
28-
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
26+
"fields":[
27+
{"name":"compTimeMonitoringSupport"},
28+
{"name":"currentThreadCpuTimeSupport"},
29+
{"name":"objectMonitorUsageSupport"},
30+
{"name":"otherThreadCpuTimeSupport"},
31+
{"name":"remoteDiagnosticCommandsSupport"},
32+
{"name":"synchronizerUsageSupport"},
33+
{"name":"threadAllocatedMemorySupport"},
34+
{"name":"threadContentionMonitoringSupport"}
35+
]
2936
}
3037
]

temporal-test-server/src/main/resources/META-INF/native-image/io.temporal/temporal-test-server/native-image.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@ Args = -H:+UnlockExperimentalVMOptions \
2323
-H:JNIConfigurationResources=${.}/jni-config.json \
2424
-H:ReflectionConfigurationResources=${.}/reflect-config.json \
2525
-H:ResourceConfigurationResources=${.}/resource-config.json \
26-
-H:SerializationConfigurationResources=${.}/serialization-config.json
26+
-H:SerializationConfigurationResources=${.}/serialization-config.json \
27+
--initialize-at-build-time=org.slf4j.helpers.SubstituteLoggerFactory \
28+
--initialize-at-build-time=org.slf4j.helpers.NOPLoggerFactory
2729

0 commit comments

Comments
 (0)