Skip to content

fix obi java agent build on macos#1247

Draft
esara wants to merge 1 commit intoopen-telemetry:mainfrom
esara:agent-build-darwin
Draft

fix obi java agent build on macos#1247
esara wants to merge 1 commit intoopen-telemetry:mainfrom
esara:agent-build-darwin

Conversation

@esara
Copy link
Copy Markdown
Contributor

@esara esara commented Feb 6, 2026

fixes #1246

@esara esara requested a review from a team as a code owner February 6, 2026 02:45
@esara esara force-pushed the agent-build-darwin branch from 213e04c to 1d38064 Compare February 6, 2026 02:49
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 43.37%. Comparing base (73c03a4) to head (ea6f69d).
⚠️ Report is 308 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1247      +/-   ##
==========================================
- Coverage   43.41%   43.37%   -0.05%     
==========================================
  Files         301      301              
  Lines       32409    32409              
==========================================
- Hits        14071    14056      -15     
- Misses      17432    17444      +12     
- Partials      906      909       +3     
Flag Coverage Δ
integration-test 20.94% <ø> (-0.39%) ⬇️
integration-test-arm 0.00% <ø> (ø)
k8s-integration-test 2.39% <ø> (ø)
oats-test 0.00% <ø> (ø)
unittests 44.32% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@esara esara force-pushed the agent-build-darwin branch 2 times, most recently from b71d098 to d399305 Compare February 6, 2026 04:22
@esara esara marked this pull request as draft February 6, 2026 04:26
Signed-off-by: Endre Sara <endresara@gmail.com>
@esara esara force-pushed the agent-build-darwin branch from d399305 to ea6f69d Compare February 6, 2026 04:51
@skl skl self-assigned this Apr 1, 2026
@skl skl requested a review from Copilot April 10, 2026 17:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses macOS build failures for the OBI Java agent’s JNI native library by shifting the native build to Linux/Docker and producing architecture-specific agent artifacts.

Changes:

  • Builds JNI native libraries via Docker and packages them into Linux x86_64 and arm64 agent JARs.
  • Adds loader tasks to assemble obi-java-agent-<arch>.jar artifacts that embed the corresponding agent payload.
  • Updates Java agent build documentation to describe architecture-specific outputs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pkg/internal/java/README.md Documents the new arch-specific agent JAR outputs.
pkg/internal/java/loader/build.gradle.kts Adds per-arch copy + ShadowJar tasks to create obi-java-agent-<arch>.jar.
pkg/internal/java/build.gradle.kts Copies per-arch assembled JARs into the root build/ output directory.
pkg/internal/java/agent/Makefile.jni Adds Docker-based build flow on macOS and arch-scoped output directories.
pkg/internal/java/agent/build.gradle.kts Reworks JNI build to produce amd64/arm64 Linux .so via Docker and creates per-arch agent ShadowJars.

Comment on lines +21 to +33
// Copy obi-java-agent JARs for each arch into root build/ (obi-java-agent-x86_64.jar, obi-java-agent-arm64.jar)
val copyObiJavaAgentJars by tasks.registering(Copy::class) {
dependsOn(":loader:obiJavaAgentX86_64", ":loader:obiJavaAgentArm64")
from(project(":loader").tasks.named("obiJavaAgentX86_64").get().outputs.files)
from(project(":loader").tasks.named("obiJavaAgentArm64").get().outputs.files)
into(layout.buildDirectory)
rename { name ->
when {
name.contains("x86_64") -> "obi-java-agent-x86_64.jar"
name.contains("arm64") -> "obi-java-agent-arm64.jar"
else -> name
}
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

copyObiJavaAgentJars no longer produces the previously expected build/obi-java-agent.jar (it only outputs obi-java-agent-x86_64.jar and obi-java-agent-arm64.jar). This is a breaking change: .github/workflows/java-agent.yml uploads pkg/internal/java/build/obi-java-agent.jar, and pkg/internal/java/java_inject.go hard-codes ObiJavaAgentFileName = "obi-java-agent.jar". Either keep generating obi-java-agent.jar for backward compatibility (e.g., as the default x86_64 build), or update all in-repo consumers to select the correct arch-specific JAR at runtime/build time.

Suggested change
// Copy obi-java-agent JARs for each arch into root build/ (obi-java-agent-x86_64.jar, obi-java-agent-arm64.jar)
val copyObiJavaAgentJars by tasks.registering(Copy::class) {
dependsOn(":loader:obiJavaAgentX86_64", ":loader:obiJavaAgentArm64")
from(project(":loader").tasks.named("obiJavaAgentX86_64").get().outputs.files)
from(project(":loader").tasks.named("obiJavaAgentArm64").get().outputs.files)
into(layout.buildDirectory)
rename { name ->
when {
name.contains("x86_64") -> "obi-java-agent-x86_64.jar"
name.contains("arm64") -> "obi-java-agent-arm64.jar"
else -> name
}
}
// Copy obi-java-agent JARs for each arch into root build/ and keep the legacy obi-java-agent.jar
val copyObiJavaAgentJars by tasks.registering(Copy::class) {
dependsOn(":loader:obiJavaAgentX86_64", ":loader:obiJavaAgentArm64")
into(layout.buildDirectory)
from(project(":loader").tasks.named("obiJavaAgentX86_64").get().outputs.files) {
rename { "obi-java-agent-x86_64.jar" }
}
from(project(":loader").tasks.named("obiJavaAgentArm64").get().outputs.files) {
rename { "obi-java-agent-arm64.jar" }
}
from(project(":loader").tasks.named("obiJavaAgentX86_64").get().outputs.files) {
rename { "obi-java-agent.jar" }
}

Copilot uses AI. Check for mistakes.
Comment on lines +163 to +168
**Architecture-specific JARs:** The native library is built for Linux only (x86_64 and arm64). `./gradlew build` produces both in `build/`:

```
build/obi-java-agent.jar
```
- `build/obi-java-agent-x86_64.jar` — for x86_64 Linux
- `build/obi-java-agent-arm64.jar` — for arm64 Linux

Use the JAR that matches your Linux host. Building requires Docker to cross-compile both architectures.
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This section introduces architecture-specific JAR names, but the usage examples below still reference obi-java-agent.jar. To avoid confusing users (and to match the new artifact names), update the usage snippets to use the selected arch-specific JAR (or explicitly document that obi-java-agent.jar is still produced as a compatibility alias).

Copilot uses AI. Check for mistakes.

// Build the native JNI library
tasks.register<Exec>("buildNativeLib") {
val isMac = System.getProperty("os.name").lowercase().contains("mac")
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

isMac is declared but never used. Either use it to choose between a native build vs Docker (as the Makefile suggests), or remove it to avoid dead code.

Suggested change
val isMac = System.getProperty("os.name").lowercase().contains("mac")

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +80
fun execDocker(arch: String, platform: String) =
listOf(
"docker", "run", "--rm",
"--platform", platform,
"-v", "$agentDir:/work", "-w", "/work",
dockerImage,
"bash", "-c",
"apt-get update -qq && apt-get install -y -qq make clang && make -f Makefile.jni native ARCH=$arch"
)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The Docker invocation mounts the project directory but runs as root in the container. On Linux hosts this commonly leaves build/ and target/ artifacts owned by root, breaking subsequent builds/cleans for the normal user. Consider running the container with the current UID/GID (or otherwise ensuring host-writable outputs), and/or writing artifacts to a container-only volume and copying them out with correct ownership.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +99
// Build Linux libobijni.so for x86_64 (always via Docker so it works on macOS and Linux)
tasks.register<Exec>("buildNativeLibAmd64") {
group = "build"
description = "Build the JNI native library (libobijni.so)"

description = "Build Linux libobijni.so for x86_64 (amd64)"
dependsOn("compileJava")

workingDir = projectDir
commandLine("make", "-f", "Makefile.jni")

doLast {
println("OBI JNI library built successfully")
}
commandLine(execDocker("amd64", "linux/amd64"))
doLast { println("OBI JNI library (amd64) built: target/classes/linux-amd64/libobijni.so") }
}

// Build Linux libobijni.so for arm64 (always via Docker)
tasks.register<Exec>("buildNativeLibArm64") {
group = "build"
description = "Build Linux libobijni.so for arm64"
dependsOn("compileJava")
workingDir = projectDir
commandLine(execDocker("arm64", "linux/arm64"))
doLast { println("OBI JNI library (arm64) built: target/classes/linux-arm64/libobijni.so") }
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

These tasks always build via Docker (including --platform linux/arm64), even on Linux where Makefile.jni supports a native build path. This makes ./gradlew build depend on Docker availability and (for arm64) binfmt/qemu support, which can break CI/dev setups that previously built natively. Consider using native make on Linux and Docker only on macOS (or gating the arm64 build behind an explicit opt-in task/flag).

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +13
# ARCH=amd64 or arm64; output goes to target/classes/linux-$(ARCH). Default only for direct 'make' use; Gradle always passes ARCH.
ARCH ?= amd64

SRC_DIR = src/main/c
BUILD_DIR = build
TARGET_DIR = target/classes
BUILD_DIR = build/linux-$(ARCH)
TARGET_DIR = target/classes/linux-$(ARCH)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

On macOS, docker run defaults to the host architecture (arm64 on Apple Silicon). With ARCH ?= amd64 as the default, invoking make without explicitly setting ARCH/DOCKER_PLATFORM can produce an arm64 .so but place it under target/classes/linux-amd64, effectively mislabeling the output. Consider defaulting ARCH based on uname -m on Darwin, or enforce that DOCKER_PLATFORM/ARCH are consistent when building via Docker.

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +42
linux-in-docker:
@command -v docker >/dev/null 2>&1 || (echo "Docker is required to build on macOS." && exit 1)
docker run --rm $(PLATFORM_OPT) -v "$(CURDIR):/work" -w /work $(DOCKER_IMAGE) bash -c 'apt-get update -qq && apt-get install -y -qq make clang && make -f Makefile.jni native ARCH=$(ARCH)'
@echo "Built Linux JNI library: $(TARGET)"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

linux-in-docker mounts the working directory but does not set a user for the container process. On Linux hosts this can leave generated outputs owned by root (e.g., under build/ and target/), which can break subsequent local builds/cleans. Consider running the container with the current UID/GID (or otherwise ensuring host-writable outputs).

Copilot uses AI. Check for mistakes.
@skl
Copy link
Copy Markdown
Member

skl commented Apr 10, 2026

Confirmed that I can reproduce the original issue on main, and that the changes in this branch do compile on macOS, though the filenames have changed as per the copilot review comments:

./gradlew build
...
BUILD SUCCESSFUL in 47s
24 actionable tasks: 15 executed, 9 up-to-date
Consider enabling configuration cache to speed up this build: https://docs.gradle.org/9.3.1/userguide/configuration_cache_enabling.html
...
ls -1 build/*.jar
build/obi-java-agent-arm64.jar
build/obi-java-agent-x86_64.jar

Regarding the CI failures:

  1. The ARM build may require ARM runners due to exec /__cacert_entrypoint.sh: exec format error
  2. Docker-in-Docker probably not required in CI as the environment is already Linux
  3. Other failures might be due to the file renaming

Suggest further iteration on this PR to address the above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

obi java agent build fails on macos

3 participants