rules_java is the official Bazel rule set for compiling, testing, and packaging Java software within Bazel workspaces.
rules_java defines the core primitives for Java builds (java_binary, java_library, java_test, java_toolchain, java_runtime, etc.). By default, rules_java downloads and uses pre-compiled platform-specific helper binaries (remote_java_tools_linux, remote_java_tools_darwin, etc.) for packaging and bytecode manipulation tasks such as singlejar and ijar.
When running Bazel builds on Nix Package Manager, builds using the default rules_java configuration will fail when packaging JARs or compiling source JARs because the pre-built singlejar_local or ijar C++ binaries are dynamically linked against standard FHS glibc paths (such as /lib64/ld-linux-x86-64.so.2).
ERROR: ... Building source jar ... failed: (Exit 127): singlejar_local failed: error executing JavaSourceJar command external/rules_java++toolchains+remote_java_tools_linux/java_tools/src/tools/singlejar/singlejar_local @...
Could not start dynamically linked executable: external/rules_java++toolchains+remote_java_tools_linux/java_tools/src/tools/singlejar/singlejar_local
NixOS cannot run dynamically linked executables intended for generic linux environments out of the box. For more information, see:
https://nix.dev/permalink/stub-ld
To resolve this hermetically on NixOS without requiring system-wide FHS workarounds (like nix-ld or buildFHSEnv), configure Bazel to:
PATH / JAVA_HOME.singlejar, ijar, etc.) from source using NONPREBUILT_TOOLCHAIN_CONFIGURATION.tools/java_toolchain/BUILD)load(
"@bazel_tools//tools/jdk:default_java_toolchain.bzl",
"NONPREBUILT_TOOLCHAIN_CONFIGURATION",
"default_java_toolchain",
)
default_java_toolchain(
name = "repository_default_java_toolchain",
configuration = NONPREBUILT_TOOLCHAIN_CONFIGURATION,
java_runtime = "@bazel_tools//tools/jdk:current_host_java_runtime",
source_version = "21",
target_version = "21",
)
MODULE.bazel)bazel_dep(name = "rules_java", version = "9.3.0")
register_toolchains("//tools/java_toolchain:repository_default_java_toolchain_definition")
.bazelrc)common --java_language_version=21
common --tool_java_language_version=21
common --java_runtime_version=local_jdk_21
common --tool_java_runtime_version=local_jdk_21
common --action_env=JAVA_HOME
java_single_jar in rules_jvm_external PinningWhile NONPREBUILT_TOOLCHAIN_CONFIGURATION configures standard java_binary and java_library targets to build singlejar from source, rules_jvm_external uses the java_single_jar rule (from @rules_java//java:java_single_jar.bzl) to package resolver plugins (e.g. plugin-single-jar) when generating dependencies with REPIN=1 bazel run @maven//:pin.
java_single_jar hardcodes _singlejar = Label("//toolchains:singlejar") rather than obtaining singlejar from the active java_toolchain. In @rules_java//toolchains/BUILD, :singlejar unconditionally selects the prebuilt binary @remote_java_tools_linux//:prebuilt_singlejar (singlejar_local) on Linux x86_64, which fails on NixOS with Exit 127: stub-ld.
Patch @rules_java using Bzlmod single_version_override to direct //toolchains:singlejar to @remote_java_tools//:singlejar_cc_bin:
single_version_override(
module_name = "rules_java",
patch_strip = 1,
patches = [
"//tools/patches:rules_java_singlejar.patch",
],
)
Where rules_java_singlejar.patch changes @rules_java//toolchains/BUILD:
--- a/toolchains/BUILD
+++ b/toolchains/BUILD
@@ -227,7 +227,7 @@
alias(
name = "singlejar",
- actual = ":singlejar_prebuilt_or_cc_binary",
+ actual = "@remote_java_tools//:singlejar_cc_bin",
)
See dev: Fix "REPIN=1 bazel run @maven//:pin" on NixOS (see https://wiki.… · enola-dev/enola@0ffbdcf · GitHub for how this was implemented in Enola.
PATHWhen executing java_test targets on Nix Package Manager with common --incompatible_strict_action_env enabled, Bazel isolates the action environment with a stripped down PATH that does not include Nixpkgs' bash.
ERROR: ...: Testing //java/dev/enola/common:tests failed: (Exit 127): generate-xml.sh failed: error executing TestRunner command (from target //java/dev/enola/common:tests) external/bazel_tools/tools/test/generate-xml.sh bazel-out/k8-fastbuild/testlogs/java/dev/enola/common/tests/test.log ...
Inspecting the test log (bazel-testlogs/.../tests/test.log) reveals:
env: 'bash': No such file or directory
The test runner script generated by rules_java starts with #!/usr/bin/env bash. Because strict action environments strip bash from PATH, /usr/bin/env cannot locate the interpreter.
To resolve this, pass the host/shell PATH into the test execution environment in .bazelrc:
# https://wiki.enola.dev/computer/programming/bazel/rules-java#test-execution-and-test-environment-path
test --test_env=PATH