Fix native library path separator on Windows (#383) On Windows, java.library.path is split by ";" instead of ":". Regression test added. Note for Googlers: this fix is in service of b/149162146#comment19 Closes #383 COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_java/pull/383 from gharrma:fix-java-native-lib-handling-on-windows b0e4c3efbe33f23d05145001ca9df54ba4c6e7ed PiperOrigin-RevId: 986888472 Change-Id: I492266c118fba328e651accf005c0ba7945ed0a3
diff --git a/java/common/rules/impl/java_binary_impl.bzl b/java/common/rules/impl/java_binary_impl.bzl index 379c213..691d66d 100644 --- a/java/common/rules/impl/java_binary_impl.bzl +++ b/java/common/rules/impl/java_binary_impl.bzl
@@ -169,8 +169,9 @@ native_libs_dirs = collect_native_deps_dirs(depset(transitive = native_libs_depsets)) if native_libs_dirs: prefix = "${JAVA_RUNFILES}/" + ctx.workspace_name + "/" + separator = ";" if helper.is_target_platform_windows(ctx) else ":" jvm_flags.append("-Djava.library.path=%s" % ( - ":".join([prefix + d for d in native_libs_dirs]) + separator.join([prefix + d for d in native_libs_dirs]) )) jvm_flags.extend(ctx.fragments.java.default_jvm_opts)
diff --git a/test/java/common/rules/common_launcher_java_binary_tests.bzl b/test/java/common/rules/common_launcher_java_binary_tests.bzl index c1e0128..ec403a0 100644 --- a/test/java/common/rules/common_launcher_java_binary_tests.bzl +++ b/test/java/common/rules/common_launcher_java_binary_tests.bzl
@@ -276,6 +276,47 @@ "${{JAVA_RUNFILES}}/{workspace}/_solib_{cpu}/_//{package}:{test_name}/jni.so___{package}", ]) +# Regression test: the native library path separator on Windows is ";" instead of ":". +def _test_java_binary_native_library_path_separator(name): + util.helper_target( + java_binary, + name = name + "/app", + srcs = ["DoesNotMatter.java"], + deps = [ + name + "/lib1", + name + "/lib2", + ], + ) + + # Define two native libs (in different directories so java.library.path has multiple entries). + util.helper_target( + cc_binary, + name = name + "/lib1", + srcs = ["lib1.so"], + ) + util.helper_target( + cc_binary, + name = name + "/lib2", + srcs = ["subdir/lib2.so"], + ) + + analysis_test( + name = name, + # The Starlark rules are only used with Bazel 8 onwards. + attr_values = {"tags": ["min_bazel_8"]}, + attrs = { + "_windows_constraints": attr.label_list(default = ["@platforms//os:windows"]), + "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + }, + impl = _test_java_binary_native_library_path_separator_impl, + target = name + "/app", + ) + +def _test_java_binary_native_library_path_separator_impl(env, target): + # We should find two libraries on java.library.path (if the correct path separator was used). + native_library_paths = expect_that_executable.of_target(env, target).native_library_paths() + native_library_paths.has_size(2) + # Regression test for bug 2774317: Problems with inner classes as main class. def _test_java_binary_inner_class(name): util.helper_target( @@ -596,6 +637,7 @@ _test_java_test_main_class_with_dot, _test_java_test_has_assertions_enabled, _test_java_binary_native_library_path_includes_transitive_deps, + _test_java_binary_native_library_path_separator, _test_java_binary_inner_class, _test_java_test_inner_class, _test_java_binary_strict_java_deps_flag,
diff --git a/test/java/testutil/binary_executable_subject.bzl b/test/java/testutil/binary_executable_subject.bzl index df5c477..29df32d 100644 --- a/test/java/testutil/binary_executable_subject.bzl +++ b/test/java/testutil/binary_executable_subject.bzl
@@ -3,6 +3,7 @@ load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_testing//lib:truth.bzl", "subjects") load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") def _of_target(env, target): executable = target[DefaultInfo].files_to_run.executable.short_path @@ -11,7 +12,7 @@ java_start_class = lambda: _java_start_class_subject(action_subject), test_suite = lambda: _test_suite_subject(action_subject), jvm_flags = lambda: _jvm_flags_subject(action_subject), - native_library_paths = lambda: _native_library_paths_subject(action_subject), + native_library_paths = lambda: _native_library_paths_subject(env, action_subject), ) return public @@ -44,7 +45,8 @@ desc = "jvm_flags", ).offset(0, factory = subjects.str).split("\t") -def _native_library_paths_subject(action): +def _native_library_paths_subject(env, action): + separator = ";" if helper.is_target_platform_windows(env.ctx) else ":" return _jvm_flags_subject(action).transform( filter = lambda e: e.startswith("-Djava.library.path="), map_each = lambda e: e.split("=", 1)[1], @@ -54,7 +56,7 @@ factory = lambda actual, meta: subjects.str(actual, meta.derive( format_str_kwargs = {"cpu": meta.ctx.attr._cc_toolchain[cc_common.CcToolchainInfo].cpu}, )), - ).split(":").transform( + ).split(separator).transform( map_each = lambda e: e.replace("_U", "_").replace("_S", "/").replace("_C", ":"), desc = "pretty", format = True,