From c4188b419a9e72a34b2f59fa982798ce77540091 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Mon, 1 Jan 2024 21:30:51 -0800 Subject: [PATCH 01/41] feat: shared headers, `rules_cc` support This changeset adds `out_headers` and `additional_outputs`, which, together, allow a developer to add additional outputs to a regular `native_image` build. Because a header is generated per C entrypoint class, the developer needs to be able to declare as many as they want. Additionally, a `CcInfo` provider needs to be returned from the `native_image` target to facilitate downsream support for `rules_cc` targets. - feat: add `out_headers` and `additional_outputs` attributes - feat: add `default_outputs` attribute to opt-out of new behavior - feat: resolve and add `CcInfo` to shared library targets Signed-off-by: Sam Gammon --- docs/api/defs.md | 5 ++- graalvm/nativeimage/rules.bzl | 18 +++++++-- internal/native_image/classic.bzl | 5 ++- internal/native_image/common.bzl | 33 +++++++++++++++-- internal/native_image/rules.bzl | 61 +++++++++++++++++++++++++------ 5 files changed, 102 insertions(+), 20 deletions(-) diff --git a/docs/api/defs.md b/docs/api/defs.md index 01490fec..19176249 100755 --- a/docs/api/defs.md +++ b/docs/api/defs.md @@ -11,7 +11,7 @@ native_image(name, jni_configuration, initialize_at_build_time, initialize_at_run_time, native_features, debug, optimization_mode, shared_library, static_zlib, c_compiler_option, data, extra_args, allow_fallback, check_toolchains, native_image_tool, native_image_settings, - profiles, kwargs) + profiles, out_headers, additional_outputs, default_outputs, kwargs) Generates and compiles a GraalVM native image from a Java library target. @@ -43,6 +43,9 @@ Generates and compiles a GraalVM native image from a Java library target. | native_image_tool | Specific `native-image` executable target to use. | `None` | | native_image_settings | Suite(s) of Native Image build settings to use. | `[Label("@rules_graalvm//internal/native_image:defaults")]` | | profiles | Profiles to use for profile-guided optimization (PGO) and obtained from a native image compiled with `--pgo-instrument`. | `[]` | +| out_headers | Shared library headers expected to be emitted by the rule (in addition to defaults). | `[]` | +| additional_outputs | Additional outputs to expect from the rule (for example, polyglot language resources). | `[]` | +| default_outputs | Whether to consider default output files; when `False`, the developer specifies all outputs on top of the binary itself. | `True` | | kwargs | Extra keyword arguments are passed to the underlying `native_image` rule. | none | diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index 45ba9a7a..de004920 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -4,9 +4,12 @@ load( "@bazel_skylib//lib:dicts.bzl", "dicts", ) +load( + "@bazel_tools//tools/cpp:toolchain_utils.bzl", + "use_cpp_toolchain", +) load( "//internal/native_image:rules.bzl", - _BAZEL_CPP_TOOLCHAIN_TYPE = "BAZEL_CPP_TOOLCHAIN_TYPE", _DEBUG = "DEBUG_CONDITION", _GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE", _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", @@ -53,8 +56,7 @@ _native_image = rule( "platform", "xcode", ], - toolchains = [ - _BAZEL_CPP_TOOLCHAIN_TYPE, + toolchains = use_cpp_toolchain() + [ _GVM_TOOLCHAIN_TYPE, ], ) @@ -83,6 +85,9 @@ def native_image( native_image_tool = None, # uses toolchains by default native_image_settings = [_DEFAULT_NATIVE_IMAGE_SETTINGS], profiles = [], + out_headers = [], + additional_outputs = [], + default_outputs = True, **kwargs): """Generates and compiles a GraalVM native image from a Java library target. @@ -111,10 +116,14 @@ def native_image( data: Data files to make available during the compilation. No default; optional. extra_args: Extra `native-image` args to pass. Last wins. No default; optional. allow_fallback: Whether to allow fall-back to a partial native image; defaults to `False`. + out_headers: Shared library headers expected to be emitted by the rule (in addition to defaults). + additional_outputs: Additional outputs to expect from the rule (for example, polyglot language resources). check_toolchains: Whether to perform toolchain checks in `native-image`; defaults to `True` on Windows, `False` otherwise. native_image_tool: Specific `native-image` executable target to use. native_image_settings: Suite(s) of Native Image build settings to use. profiles: Profiles to use for profile-guided optimization (PGO) and obtained from a native image compiled with `--pgo-instrument`. + default_outputs: Whether to consider default output files; when `False`, the developer specifies all outputs on top of the + binary itself. **kwargs: Extra keyword arguments are passed to the underlying `native_image` rule. """ @@ -141,5 +150,8 @@ def native_image( native_image_tool = native_image_tool, native_image_settings = native_image_settings, profiles = profiles, + out_headers = out_headers, + additional_outputs = additional_outputs, + default_outputs = default_outputs, **kwargs ) diff --git a/internal/native_image/classic.bzl b/internal/native_image/classic.bzl index f7a78756..82699f47 100644 --- a/internal/native_image/classic.bzl +++ b/internal/native_image/classic.bzl @@ -50,13 +50,14 @@ def _graal_binary_classic_implementation(ctx): ) args = ctx.actions.args() - binary = _prepare_native_image_rule_context( + outputs = _prepare_native_image_rule_context( ctx, args, classpath_depset, direct_inputs, native_toolchain.c_compiler_path, ) + binary = outputs[0] inputs = depset( direct_inputs, @@ -64,7 +65,7 @@ def _graal_binary_classic_implementation(ctx): ) ctx.actions.run( - outputs = [binary], + outputs = outputs, arguments = [args], executable = graal, inputs = inputs, diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index f13132ea..4dc0e84c 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -8,11 +8,12 @@ load( _RULES_REPO = "@rules_graalvm" _DEFAULT_GVM_REPO = "@graalvm" _GVM_TOOLCHAIN_TYPE = "%s//graalvm/toolchain" % _RULES_REPO -_BAZEL_CPP_TOOLCHAIN_TYPE = "@bazel_tools//tools/cpp:toolchain_type" _BAZEL_CURRENT_CPP_TOOLCHAIN = "@bazel_tools//tools/cpp:current_cc_toolchain" _LINUX_CONSTRAINT = "@platforms//os:linux" _MACOS_CONSTRAINT = "@platforms//os:macos" _WINDOWS_CONSTRAINT = "@platforms//os:windows" +_GRAALVM_ISOLATE_HEADER = "graal_isolate.h" +_GRAALVM_ISOLATE_DYNAMIC_HEADER = "graal_isolate_dynamic.h" # buildifier: disable=name-conventions _NativeImageOptimization = struct( @@ -113,6 +114,11 @@ _NATIVE_IMAGE_ATTRS = { allow_files = True, mandatory = False, ), + "out_headers": attr.output_list(), + "additional_outputs": attr.output_list(), + "default_outputs": attr.bool( + default = True, + ), "_cc_toolchain": attr.label( default = Label(_BAZEL_CURRENT_CPP_TOOLCHAIN), ), @@ -154,6 +160,9 @@ def _prepare_native_image_rule_context( out_bin_name = ctx.attr.executable_name.replace("%target%", ctx.attr.name) binary = ctx.actions.declare_file(_prepare_bin_name(out_bin_name, bin_postfix)) + additional_outputs = [] + outputs = [binary] + # TODO: This check really should be on the exec platform, not the target platform, but that # requires going through a separate rule. Since GraalVM doesn't support cross-compilation, the # distinction doesn't matter for now. @@ -162,6 +171,25 @@ def _prepare_native_image_rule_context( else: path_list_separator = ":" + # if we are building a shared library, headers will be emitted; by default, the `graal_isolate.h` + # and `graal_isolate_dynamic.h` files are included. additional headers can be added by the `out_headers` + # attribute. + if ctx.attr.shared_library and ctx.attr.default_outputs: + additional_outputs.append(_GRAALVM_ISOLATE_HEADER) + additional_outputs.append(_GRAALVM_ISOLATE_DYNAMIC_HEADER) + + # append all additional outputs + if len(additional_outputs) > 0: + outputs.extend([ctx.actions.declare_file(f) for f in additional_outputs]) + + # append all out headers + if len(ctx.attr.out_headers) > 0: + outputs.extend(ctx.outputs.out_headers) + + # append all attr additional outputs + if len(ctx.attr.additional_outputs) > 0: + outputs.extend(ctx.outputs.additional_outputs) + _assemble_native_build_options( ctx, args, @@ -173,7 +201,7 @@ def _prepare_native_image_rule_context( gvm_toolchain, bin_postfix, ) - return binary + return outputs ## Exports. @@ -186,7 +214,6 @@ DEBUG_CONDITION = _DEBUG_CONDITION COVERAGE_CONDITION = _COVERAGE_CONDITION OPTIMIZATION_MODE_CONDITION = _OPTIMIZATION_MODE_CONDITION GVM_TOOLCHAIN_TYPE = _GVM_TOOLCHAIN_TYPE -BAZEL_CPP_TOOLCHAIN_TYPE = _BAZEL_CPP_TOOLCHAIN_TYPE BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN MACOS_CONSTRAINT = _MACOS_CONSTRAINT WINDOWS_CONSTRAINT = _WINDOWS_CONSTRAINT diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 5841baff..b009c110 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -4,9 +4,12 @@ load( "@build_bazel_apple_support//lib:apple_support.bzl", "apple_support", ) +load( + "@bazel_tools//tools/cpp:toolchain_utils.bzl", + "find_cpp_toolchain", +) load( "//internal/native_image:common.bzl", - _BAZEL_CPP_TOOLCHAIN_TYPE = "BAZEL_CPP_TOOLCHAIN_TYPE", _BAZEL_CURRENT_CPP_TOOLCHAIN = "BAZEL_CURRENT_CPP_TOOLCHAIN", _DEBUG_CONDITION = "DEBUG_CONDITION", _DEFAULT_GVM_REPO = "DEFAULT_GVM_REPO", @@ -103,7 +106,7 @@ def _graal_binary_implementation(ctx): bin_postfix = _BIN_POSTFIX_SO args = ctx.actions.args().use_param_file("@%s", use_always=False) - binary = _prepare_native_image_rule_context( + all_outputs = _prepare_native_image_rule_context( ctx, args, classpath_depset, @@ -112,6 +115,7 @@ def _graal_binary_implementation(ctx): gvm_toolchain, bin_postfix = bin_postfix, ) + binary = all_outputs[0] # assemble final inputs inputs = depset( @@ -119,7 +123,7 @@ def _graal_binary_implementation(ctx): transitive = transitive_inputs, ) run_params = { - "outputs": [binary], + "outputs": all_outputs, "executable": graal, "inputs": inputs, "mnemonic": "NativeImage", @@ -159,14 +163,50 @@ def _graal_binary_implementation(ctx): **run_params ) - return [DefaultInfo( + # if we are building a shared library, prepare `CcSharedLibraryInfo` for it + cc_info = [] + runfiles = None + if ctx.attr.shared_library: + cc_toolchain = find_cpp_toolchain(ctx) + feature_configuration = cc_common.configure_features( + ctx = ctx, + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + libraries_to_link = [ + cc_common.create_library_to_link( + actions = ctx.actions, + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + dynamic_library = binary, + ), + ] + cc_info.extend([ + OutputGroupInfo( + main_shared_library_output = depset([binary]), + ), + CcSharedLibraryInfo( + linker_input = cc_common.create_linker_input( + owner = ctx.label, + libraries = depset(libraries_to_link), + ), + ), + ]) + + # prepare all runfiles + all_runfiles = ctx.runfiles( + collect_data = True, + collect_default = True, + files = [], + ) + if runfiles != None: + all_runfiles = all_runfiles.merge(runfiles) + + return cc_info + [DefaultInfo( executable = binary, - files = depset([binary]), - runfiles = ctx.runfiles( - collect_data = True, - collect_default = True, - files = [], - ), + files = depset(all_outputs), + runfiles = all_runfiles, )] def _wrap_actions_for_graal(actions): @@ -198,7 +238,6 @@ def _wrapped_run_for_graal(_original_actions, arguments = [], env = {}, **kwargs RULES_REPO = _RULES_REPO DEFAULT_GVM_REPO = _DEFAULT_GVM_REPO BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN -BAZEL_CPP_TOOLCHAIN_TYPE = _BAZEL_CPP_TOOLCHAIN_TYPE NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_ATTRS GVM_TOOLCHAIN_TYPE = _GVM_TOOLCHAIN_TYPE DEBUG_CONDITION = _DEBUG_CONDITION From b6c47efb93d53568aa6803b41b97f0534e049ea0 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Tue, 2 Jan 2024 15:15:37 -0800 Subject: [PATCH 02/41] fix: restore cpp toolchain symbol for classic rules Signed-off-by: Sam Gammon --- internal/native_image/common.bzl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index 4dc0e84c..7d685377 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -8,6 +8,7 @@ load( _RULES_REPO = "@rules_graalvm" _DEFAULT_GVM_REPO = "@graalvm" _GVM_TOOLCHAIN_TYPE = "%s//graalvm/toolchain" % _RULES_REPO +_BAZEL_CPP_TOOLCHAIN_TYPE = "@bazel_tools//tools/cpp:toolchain_type" _BAZEL_CURRENT_CPP_TOOLCHAIN = "@bazel_tools//tools/cpp:current_cc_toolchain" _LINUX_CONSTRAINT = "@platforms//os:linux" _MACOS_CONSTRAINT = "@platforms//os:macos" @@ -214,6 +215,7 @@ DEBUG_CONDITION = _DEBUG_CONDITION COVERAGE_CONDITION = _COVERAGE_CONDITION OPTIMIZATION_MODE_CONDITION = _OPTIMIZATION_MODE_CONDITION GVM_TOOLCHAIN_TYPE = _GVM_TOOLCHAIN_TYPE +BAZEL_CPP_TOOLCHAIN_TYPE = _BAZEL_CPP_TOOLCHAIN_TYPE BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN MACOS_CONSTRAINT = _MACOS_CONSTRAINT WINDOWS_CONSTRAINT = _WINDOWS_CONSTRAINT From 4e0f1bfe72d20a86fa381bd644c10597e8674479 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 4 Jan 2024 19:16:08 -0800 Subject: [PATCH 03/41] fix: inclusion of native jvm headers in `native-image` builds Signed-off-by: Sam Gammon --- internal/graalvm_bindist.bzl | 6 ++++++ internal/native_image/rules.bzl | 2 ++ internal/toolchain.bzl | 11 +++++++++++ 3 files changed, 19 insertions(+) diff --git a/internal/graalvm_bindist.bzl b/internal/graalvm_bindist.bzl index 47d55baf..09df6dbe 100644 --- a/internal/graalvm_bindist.bzl +++ b/internal/graalvm_bindist.bzl @@ -518,6 +518,7 @@ graalvm_sdk( name = "gvm", native_image_bin = ":native-image", gvm_files = ":files", + includes = ":includes", ) alias( name = "sdk", @@ -550,6 +551,11 @@ filegroup( srcs = glob(["**/*"]), ) +filegroup( + name = "includes", + srcs = glob(["include/**/*"]), +) + # Tool Targets {rendered_bin_targets} diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index b009c110..43787d1a 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -60,6 +60,7 @@ def _graal_binary_implementation(ctx): resolved_graal = graal_attr or info.native_image_bin gvm_toolchain = info extra_tool_deps.append(info.gvm_files) + extra_tool_deps.append(info.includes) graal_inputs, _ = ctx.resolve_tools(tools = [ resolved_graal, @@ -69,6 +70,7 @@ def _graal_binary_implementation(ctx): # add toolchain files to transitive inputs transitive_inputs.append(gvm_toolchain.gvm_files[DefaultInfo].files) + transitive_inputs.append(gvm_toolchain.includes[DefaultInfo].files) # if we're using an explicit tool, add it to the direct inputs if graal: diff --git a/internal/toolchain.bzl b/internal/toolchain.bzl index 338709c1..9da9716c 100644 --- a/internal/toolchain.bzl +++ b/internal/toolchain.bzl @@ -8,6 +8,7 @@ GraalVMToolchainInfo = provider( fields = [ "native_image_bin", "gvm_files", + "includes", ], ) @@ -24,6 +25,7 @@ def _gvm_toolchain_impl(ctx): graalvm = GraalVMToolchainInfo( native_image_bin = ctx.attr.native_image_bin, gvm_files = ctx.attr.gvm_files, + includes = ctx.attr.includes, ), ) return [toolchain_info] @@ -72,6 +74,15 @@ Filegroup which holds the full set of constituent files which are part of this G SDK installation. These files are transitive tool dependencies for any binary built with Native Image. +""", + ), + "includes": attr.label( + mandatory = True, + allow_files = True, + cfg = "exec", + doc = """ +Native headers from the GraalVM JDK which should be made available to `native-image` +compile jobs (for example, `jni.h`). """, ), }, From 55af61917bbb3c12f45fb7bbdc30dd11f2b425da Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 4 Jan 2024 19:16:32 -0800 Subject: [PATCH 04/41] chore: relock bazel mods Signed-off-by: Sam Gammon --- MODULE.bazel.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 90653967..ca056e85 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -2212,7 +2212,7 @@ "moduleExtensions": { "//:extensions.bzl%graalvm": { "general": { - "bzlTransitiveDigest": "PkyvavvK5e4FjXXNmFAYYcGB6FofYxEbQwP3Uuc8TR4=", + "bzlTransitiveDigest": "mRzSuTlbQlQ0snbnMM3X7itZ8Eh1p7TKee6l6JsBWUc=", "accumulatedFileDigests": {}, "envVariables": {}, "generatedRepoSpecs": { From 62d95e54c253c6e7956e2f407876a1a79493169c Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 4 Jan 2024 19:45:19 -0800 Subject: [PATCH 05/41] fix: provide `GRAALVM_HOME` to `native-image` builds Signed-off-by: Sam Gammon --- internal/native_image/rules.bzl | 2 ++ internal/native_image/toolchain.bzl | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 43787d1a..c1dce5ee 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -71,6 +71,7 @@ def _graal_binary_implementation(ctx): # add toolchain files to transitive inputs transitive_inputs.append(gvm_toolchain.gvm_files[DefaultInfo].files) transitive_inputs.append(gvm_toolchain.includes[DefaultInfo].files) + graalvm_home = graal.dirname # if we're using an explicit tool, add it to the direct inputs if graal: @@ -94,6 +95,7 @@ def _graal_binary_implementation(ctx): ctx, transitive_inputs, is_windows = is_windows, + graalvm_home = graalvm_home, ) # shared libraries on macos are produced with an extension of `dylib`. diff --git a/internal/native_image/toolchain.bzl b/internal/native_image/toolchain.bzl index f3e69b79..d1bc0979 100644 --- a/internal/native_image/toolchain.bzl +++ b/internal/native_image/toolchain.bzl @@ -20,7 +20,7 @@ load( "find_cpp_toolchain", ) -def resolve_cc_toolchain(ctx, transitive_inputs, *, is_windows): +def resolve_cc_toolchain(ctx, transitive_inputs, *, is_windows, graalvm_home): """Build a context struct for accessing the native C toolchain. Available struct properties: @@ -32,6 +32,7 @@ def resolve_cc_toolchain(ctx, transitive_inputs, *, is_windows): ctx: Context from the rule implementation. transitive_inputs: List of transitive inputs (mutated). is_windows: Whether the target (and hence execution) platform is Windows. + graalvm_home: Parent directory which should be used as `GRAALVM_HOME`. Returns: Resulting struct; see method documentation for parameters.""" @@ -118,9 +119,11 @@ def resolve_cc_toolchain(ctx, transitive_inputs, *, is_windows): # seal paths with hack above env["PATH"] = ctx.configuration.host_path_separator.join(paths) + env["GRAALVM_HOME"] = graalvm_home return struct( c_compiler_path = c_compiler_path, env = env, execution_requirements = execution_requirements, + graalvm_home = graalvm_home, ) From 7b53b5903881b59431bfa8b332c01e84d955e865 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 4 Jan 2024 19:48:25 -0800 Subject: [PATCH 06/41] fix: gvm home parameter in classic rules Signed-off-by: Sam Gammon --- internal/native_image/classic.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/native_image/classic.bzl b/internal/native_image/classic.bzl index 82699f47..df059414 100644 --- a/internal/native_image/classic.bzl +++ b/internal/native_image/classic.bzl @@ -42,11 +42,15 @@ def _graal_binary_classic_implementation(ctx): or install a GraalVM `native-image` toolchain. """) + # resolve graal_home + graalvm_home = graal.dirname + # resolve the native toolchain native_toolchain = _resolve_cc_toolchain( ctx, transitive_inputs, is_windows = ctx.configuration.host_path_separator == ";", + graalvm_home = graalvm_home, ) args = ctx.actions.args() From 9d6d95672bd4c901f0df8cb3692bbc990316d091 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 4 Jan 2024 19:54:59 -0800 Subject: [PATCH 07/41] fix: off-by-one in graalvm home path Signed-off-by: Sam Gammon --- internal/native_image/classic.bzl | 6 +++++- internal/native_image/rules.bzl | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/native_image/classic.bzl b/internal/native_image/classic.bzl index df059414..62172c67 100644 --- a/internal/native_image/classic.bzl +++ b/internal/native_image/classic.bzl @@ -16,6 +16,10 @@ load( "//internal/native_image:toolchain.bzl", _resolve_cc_toolchain = "resolve_cc_toolchain", ) +load( + "@bazel_skylib//lib:paths.bzl", + "paths", +) def _graal_binary_classic_implementation(ctx): graal_attr = ctx.attr.native_image_tool @@ -43,7 +47,7 @@ def _graal_binary_classic_implementation(ctx): """) # resolve graal_home - graalvm_home = graal.dirname + graalvm_home = paths.dirname(graal.dirname) # resolve the native toolchain native_toolchain = _resolve_cc_toolchain( diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index c1dce5ee..9359abac 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -8,6 +8,10 @@ load( "@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", ) +load( + "@bazel_skylib//lib:paths.bzl", + "paths", +) load( "//internal/native_image:common.bzl", _BAZEL_CURRENT_CPP_TOOLCHAIN = "BAZEL_CURRENT_CPP_TOOLCHAIN", @@ -71,7 +75,7 @@ def _graal_binary_implementation(ctx): # add toolchain files to transitive inputs transitive_inputs.append(gvm_toolchain.gvm_files[DefaultInfo].files) transitive_inputs.append(gvm_toolchain.includes[DefaultInfo].files) - graalvm_home = graal.dirname + graalvm_home = paths.dirname(graal.dirname) # if we're using an explicit tool, add it to the direct inputs if graal: From 223e0b8ed1585aa2b3f7f345a2915d549ddd3286 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 4 Jan 2024 20:57:31 -0800 Subject: [PATCH 08/41] fix: include `data` attribute in direct inputs Signed-off-by: Sam Gammon --- internal/native_image/rules.bzl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 9359abac..1b18f62e 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -75,6 +75,8 @@ def _graal_binary_implementation(ctx): # add toolchain files to transitive inputs transitive_inputs.append(gvm_toolchain.gvm_files[DefaultInfo].files) transitive_inputs.append(gvm_toolchain.includes[DefaultInfo].files) + direct_inputs.extend(ctx.files.data) + graalvm_home = paths.dirname(graal.dirname) # if we're using an explicit tool, add it to the direct inputs From ed40131e88208a4fd4ec5301ef63b09b42c983e0 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Fri, 12 Jan 2024 23:00:07 -0800 Subject: [PATCH 09/41] feat: makevar expansion for `extra_args` Adds Makefile variable expansion support to the `extra_args` flags passed to `native-image`. Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 2 +- internal/native_image/rules.bzl | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index fc2a2068..151f954b 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -231,4 +231,4 @@ def assemble_native_build_options( # append extra arguments last for arg in ctx.attr.extra_args: - args.add(arg) + args.add(ctx.expand_location(arg, ctx.attr.data)) diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 1b18f62e..5ca59aa8 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -43,6 +43,14 @@ def _build_action_message(ctx): } return (_mode_label[ctx.attr.optimization_mode or "default"]) +def _prepare_execution_env(ctx, base_env = {}): + effective = {} + effective.update(base_env) + effective.update({ + "GRAALVM_BAZEL": "true", + }) + return effective + def _graal_binary_implementation(ctx): graal_attr = ctx.attr.native_image_tool extra_tool_deps = [] @@ -115,7 +123,7 @@ def _graal_binary_implementation(ctx): elif (not is_windows and not is_macos) and ctx.attr.shared_library: bin_postfix = _BIN_POSTFIX_SO - args = ctx.actions.args().use_param_file("@%s", use_always=False) + args = ctx.actions.args().use_param_file("@%s", use_always=True) all_outputs = _prepare_native_image_rule_context( ctx, args, @@ -126,6 +134,10 @@ def _graal_binary_implementation(ctx): bin_postfix = bin_postfix, ) binary = all_outputs[0] + execution_env = _prepare_execution_env( + ctx, + native_toolchain.env, + ) # assemble final inputs inputs = depset( @@ -137,7 +149,7 @@ def _graal_binary_implementation(ctx): "executable": graal, "inputs": inputs, "mnemonic": "NativeImage", - "env": native_toolchain.env, + "env": execution_env, "execution_requirements": {k: "" for k in native_toolchain.execution_requirements}, "progress_message": "Native Image __target__ (__mode__) %{label}" .replace("__mode__", _build_action_message(ctx)) From fb6a8e2c6518665a25804d5d767f7d5d028a5c25 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 15:49:05 -0800 Subject: [PATCH 10/41] feat: makevar expansion pt2, managed build tmpdir - feat: full implementation this time of make variable and location expansion - feat: managed build temp directory for `native-image` Relates-To: sgammon/rules_graalvm#244 Relates-To: sgammon/rules_graalvm#245 Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 61 ++++++++++++++++++++++++++++--- internal/native_image/common.bzl | 6 ++- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 151f954b..2b02d7ea 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -1,5 +1,22 @@ "Logic to assemble `native-image` options." +_DEFAULT_NATIVE_IMAGE_ARGS = [ + "-H:+ReportExceptionStackTraces", +] + +def _expand_var(ctx, arg, context = None, vars = None): + return ctx.expand_make_variables( + "native_image", + ctx.expand_location(arg, context or ctx.attr.data), + vars or ctx.var, + ) + +def _expand_vars(ctx, args, context = None, vars = None): + return [_expand_var(ctx, arg, context, vars or ctx.var) for arg in args] + +def _arg_formatted(ctx, args, value, format = None, context = None, vars = None): + args.add(_expand_var(ctx, value, context, vars), format = format or "%s") + def _configure_static_zlib_compile(ctx, args, direct_inputs): """Configure a static image compile against hermetic/static zlib. @@ -157,6 +174,9 @@ def assemble_native_build_options( path_list_separator: Platform-specific path separator. gvm_toolchain: Resolved GraalVM toolchain, or `None` if a tool target is in use via legacy rules. bin_postfix: Binary postfix expected from the output file (for example, `.exe` or `.dylib`). + + Returns: + Tempdir path where the native build should occur. """ # main class is required unless we are building a shared library @@ -177,8 +197,26 @@ def assemble_native_build_options( args.add(ctx.attr.main_class, format = "-H:Class=%s") args.add(trimmed_basename, format = "-H:Name=%s") - args.add(binary.dirname, format = "-H:Path=%s") - args.add("-H:+ReportExceptionStackTraces") + + # binary path supports expansion + _arg_formatted( + ctx, + args, + binary.dirname, + format = "-H:Path=%s", + ) + + # default native image args + args.add_all(_DEFAULT_NATIVE_IMAGE_ARGS) + + # declare a temp path for graalvm to use + tempdir = ctx.actions.declare_directory("native_image_build", sibling = binary) + + # share temp path with graalvm sandbox, as genfiles root + args.add( + tempdir.path, + format = "-H:TempDirectory=%s", + ) if not ctx.attr.check_toolchains: args.add("-H:-CheckToolchain") @@ -204,7 +242,14 @@ def assemble_native_build_options( # configure resources if ctx.attr.include_resources != None: - args.add(ctx.attr.include_resources, format = "-H:IncludeResources=%s") + # resources config supports expansion + _arg_formatted( + ctx, + args, + ctx.attr.include_resources, + format = "-H:IncludeResources=%s", + context = ctx.attr.profiles, + ) # if a static build is being performed against hermetic zlib, configure it if ctx.attr.static_zlib != None: @@ -215,8 +260,9 @@ def assemble_native_build_options( ) if ctx.files.profiles: + # pgo profiles support expansion args.add_joined( - ctx.files.profiles, + _expand_vars(ctx, ctx.files.profiles, ctx.attr.profiles), join_with = ",", format_joined = "--pgo=%s", ) @@ -230,5 +276,8 @@ def assemble_native_build_options( ) # append extra arguments last - for arg in ctx.attr.extra_args: - args.add(ctx.expand_location(arg, ctx.attr.data)) + if len(ctx.attr.extra_args) > 0: + # extra args support location + makefile expansion + args.add_all(_expand_vars(ctx, ctx.attr.extra_args)) + + return tempdir diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index 7d685377..0d3331b3 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -191,7 +191,8 @@ def _prepare_native_image_rule_context( if len(ctx.attr.additional_outputs) > 0: outputs.extend(ctx.outputs.additional_outputs) - _assemble_native_build_options( + # generate options with tempdir for build + tempdir = _assemble_native_build_options( ctx, args, binary, @@ -202,6 +203,9 @@ def _prepare_native_image_rule_context( gvm_toolchain, bin_postfix, ) + + # add native image tempdir to outputs + outputs.append(tempdir) return outputs ## Exports. From 2a70e118a75f25e224c21d574021f31a3e31f337 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:17:07 -0800 Subject: [PATCH 11/41] feat: initial work on shared native image rule - create base attributes, split into main/shared target attrs - create new macro and rules Signed-off-by: Sam Gammon --- graalvm/nativeimage/rules.bzl | 139 +++++++++++++++++++++++++++---- internal/native_image/common.bzl | 25 ++++-- internal/native_image/rules.bzl | 11 ++- 3 files changed, 151 insertions(+), 24 deletions(-) diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index de004920..5645a4dc 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -13,8 +13,10 @@ load( _DEBUG = "DEBUG_CONDITION", _GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE", _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", + _NATIVE_IMAGE_SHARED_LIB_ATTRS = "NATIVE_IMAGE_SHARED_LIB_ATTRS", _OPTIMIZATION_MODE = "OPTIMIZATION_MODE_CONDITION", _graal_binary_implementation = "graal_binary_implementation", + _graal_shared_binary_implementation = "graal_shared_binary_implementation", ) load( "//internal/native_image:settings.bzl", @@ -33,21 +35,39 @@ _EXEUCTABLE_NAME_CONDITION = select({ "//conditions:default": "%target%-bin", }) +_modern_rule_attrs = { + "native_image_tool": attr.label( + cfg = "exec", + allow_files = True, + executable = True, + mandatory = False, + ), + "native_image_settings": attr.label_list( + providers = [[NativeImageInfo]], + mandatory = False, + default = [_DEFAULT_NATIVE_IMAGE_SETTINGS], + ), +} + _native_image = rule( implementation = _graal_binary_implementation, - attrs = dicts.add(_NATIVE_IMAGE_ATTRS, **{ - "native_image_tool": attr.label( - cfg = "exec", - allow_files = True, - executable = True, - mandatory = False, - ), - "native_image_settings": attr.label_list( - providers = [[NativeImageInfo]], - mandatory = False, - default = [_DEFAULT_NATIVE_IMAGE_SETTINGS], - ), - }), + attrs = dicts.add(_NATIVE_IMAGE_ATTRS, **_modern_rule_attrs), + executable = True, + fragments = [ + "apple", + "cpp", + "java", + "platform", + "xcode", + ], + toolchains = use_cpp_toolchain() + [ + _GVM_TOOLCHAIN_TYPE, + ], +) + +_native_image_shared_library = rule( + implementation = _graal_shared_binary_implementation, + attrs = dicts.add(_NATIVE_IMAGE_SHARED_LIB_ATTRS, **_modern_rule_attrs), executable = True, fragments = [ "apple", @@ -85,7 +105,6 @@ def native_image( native_image_tool = None, # uses toolchains by default native_image_settings = [_DEFAULT_NATIVE_IMAGE_SETTINGS], profiles = [], - out_headers = [], additional_outputs = [], default_outputs = True, **kwargs): @@ -116,7 +135,6 @@ def native_image( data: Data files to make available during the compilation. No default; optional. extra_args: Extra `native-image` args to pass. Last wins. No default; optional. allow_fallback: Whether to allow fall-back to a partial native image; defaults to `False`. - out_headers: Shared library headers expected to be emitted by the rule (in addition to defaults). additional_outputs: Additional outputs to expect from the rule (for example, polyglot language resources). check_toolchains: Whether to perform toolchain checks in `native-image`; defaults to `True` on Windows, `False` otherwise. native_image_tool: Specific `native-image` executable target to use. @@ -127,6 +145,9 @@ def native_image( **kwargs: Extra keyword arguments are passed to the underlying `native_image` rule. """ + if shared_library: + debug("GraalVM rules for Bazel at >0.11.x uses `native_image_shared_library`. Please migrate at your convenience.") + _native_image( name = name, deps = deps, @@ -150,6 +171,94 @@ def native_image( native_image_tool = native_image_tool, native_image_settings = native_image_settings, profiles = profiles, + additional_outputs = additional_outputs, + default_outputs = default_outputs, + **kwargs + ) + +def native_image_shared_library( + name, + deps, + executable_name = _EXEUCTABLE_NAME_CONDITION, + include_resources = None, + reflection_configuration = None, + jni_configuration = None, + initialize_at_build_time = [], + initialize_at_run_time = [], + native_features = [], + debug = _DEBUG, + optimization_mode = _OPTIMIZATION_MODE, + static_zlib = None, + c_compiler_option = [], + data = [], + extra_args = [], + allow_fallback = False, + check_toolchains = _DEFAULT_CHECK_TOOLCHAINS_CONDITION, + native_image_tool = None, # uses toolchains by default + native_image_settings = [_DEFAULT_NATIVE_IMAGE_SETTINGS], + profiles = [], + out_headers = [], + additional_outputs = [], + default_outputs = True, + **kwargs): + """Generates and compiles a GraalVM native image from a Java library target. + + Args: + name: Name of the target; required. + deps: Dependency `java_library` targets to assemble the classpath from. Mandatory. + executable_name: Set the name of the output binary; defaults to `%target%-bin`, or `%target%-bin.exe` on Windows. + The special string `%target%`, if present, is replaced with `name`. + include_resources: Glob to pass to `IncludeResources`. No default; optional. + reflection_configuration: Reflection configuration file. No default; optional. + jni_configuration: JNI configuration file. No default; optional. + initialize_at_build_time: Classes or patterns to pass to `--initialize-at-build-time`. No default; optional. + initialize_at_run_time: Classes or patterns to pass to `--initialize-at-run-time`. No default; optional. + native_features: GraalVM `Feature` classes to include and apply. No default; optional. + debug: Whether to include debug symbols; by default, this flag's state is managed by Bazel. Passing + `--compilation_mode=dbg` is sufficient to flip this to `True`, or it can be overridden via this parameter. + optimization_mode: Behaves the same as `debug`; normally, this flag's state is managed by Bazel. Passing + `--compilation_mode=fastbuild|opt|dbg` is sufficient to set this flag, or it can be overridden via this + parameter. + static_zlib: A cc_library or cc_import target that provides zlib as a static library. + On Linux, this is used when Graal statically links zlib into the binary, e.g. with + `-H:+StaticExecutableWithDynamicLibC`. + c_compiler_option: Extra C compiler options to pass through `native-image`. No default; optional. + data: Data files to make available during the compilation. No default; optional. + extra_args: Extra `native-image` args to pass. Last wins. No default; optional. + allow_fallback: Whether to allow fall-back to a partial native image; defaults to `False`. + out_headers: Shared library headers expected to be emitted by the rule (in addition to defaults). + additional_outputs: Additional outputs to expect from the rule (for example, polyglot language resources). + check_toolchains: Whether to perform toolchain checks in `native-image`; defaults to `True` on Windows, `False` otherwise. + native_image_tool: Specific `native-image` executable target to use. + native_image_settings: Suite(s) of Native Image build settings to use. + profiles: Profiles to use for profile-guided optimization (PGO) and obtained from a native image compiled with `--pgo-instrument`. + default_outputs: Whether to consider default output files; when `False`, the developer specifies all outputs on top of the + binary itself. + **kwargs: Extra keyword arguments are passed to the underlying `native_image` rule. + """ + + _native_image_shared_library( + name = name, + deps = deps, + include_resources = include_resources, + reflection_configuration = reflection_configuration, + jni_configuration = jni_configuration, + initialize_at_build_time = initialize_at_build_time, + initialize_at_run_time = initialize_at_run_time, + native_features = native_features, + debug = debug, + optimization_mode = optimization_mode, + shared_library = True, + data = data, + extra_args = extra_args, + check_toolchains = check_toolchains, + static_zlib = static_zlib, + c_compiler_option = c_compiler_option, + allow_fallback = allow_fallback, + executable_name = executable_name, + native_image_tool = native_image_tool, + native_image_settings = native_image_settings, + profiles = profiles, out_headers = out_headers, additional_outputs = additional_outputs, default_outputs = default_outputs, diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index 0d3331b3..c209c3a2 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -1,5 +1,9 @@ "Defines common properties shared by modern and legacy Native Image rules." +load( + "@bazel_skylib//lib:dicts.bzl", + "dicts", +) load( "//internal/native_image:builder.bzl", _assemble_native_build_options = "assemble_native_build_options", @@ -40,14 +44,11 @@ _OPTIMIZATION_MODE_CONDITION = select({ "//conditions:default": _NativeImageOptimization.DEFAULT, # becomes `-O2` via GraalVM defaults }) -_NATIVE_IMAGE_ATTRS = { +_NATIVE_IMAGE_BASE_ATTRS = { "deps": attr.label_list( providers = [[JavaInfo]], mandatory = True, ), - "main_class": attr.string( - mandatory = False, - ), "shared_library": attr.bool( mandatory = False, default = False, @@ -140,6 +141,19 @@ _NATIVE_IMAGE_ATTRS = { ), } +_NATIVE_IMAGE_BIN_ATTRS = dicts.add(_NATIVE_IMAGE_BASE_ATTRS, **{ + "main_class": attr.string( + mandatory = False, + ), + "main_module": attr.string( + mandatory = False, + ), +}) + +_NATIVE_IMAGE_SHAREDLIB_ATTRS = dicts.add(_NATIVE_IMAGE_BASE_ATTRS, **{ + # Nothing at this time. +}) + def _prepare_bin_name( name, bin_postfix = None): @@ -223,5 +237,6 @@ BAZEL_CPP_TOOLCHAIN_TYPE = _BAZEL_CPP_TOOLCHAIN_TYPE BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN MACOS_CONSTRAINT = _MACOS_CONSTRAINT WINDOWS_CONSTRAINT = _WINDOWS_CONSTRAINT -NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_ATTRS +NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_BIN_ATTRS +NATIVE_IMAGE_SHARED_LIB_ATTRS = _NATIVE_IMAGE_SHAREDLIB_ATTRS prepare_native_image_rule_context = _prepare_native_image_rule_context diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 5ca59aa8..c6ebe4e8 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -1,16 +1,16 @@ "Rules for building native binaries using the GraalVM `native-image` tool." load( - "@build_bazel_apple_support//lib:apple_support.bzl", - "apple_support", + "@bazel_skylib//lib:paths.bzl", + "paths", ) load( "@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", ) load( - "@bazel_skylib//lib:paths.bzl", - "paths", + "@build_bazel_apple_support//lib:apple_support.bzl", + "apple_support", ) load( "//internal/native_image:common.bzl", @@ -19,6 +19,7 @@ load( _DEFAULT_GVM_REPO = "DEFAULT_GVM_REPO", _GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE", _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", + _NATIVE_IMAGE_SHARED_LIB_ATTRS = "NATIVE_IMAGE_SHARED_LIB_ATTRS", _OPTIMIZATION_MODE_CONDITION = "OPTIMIZATION_MODE_CONDITION", _RULES_REPO = "RULES_REPO", _prepare_native_image_rule_context = "prepare_native_image_rule_context", @@ -261,7 +262,9 @@ RULES_REPO = _RULES_REPO DEFAULT_GVM_REPO = _DEFAULT_GVM_REPO BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_ATTRS +NATIVE_IMAGE_SHARED_LIB_ATTRS = _NATIVE_IMAGE_SHARED_LIB_ATTRS GVM_TOOLCHAIN_TYPE = _GVM_TOOLCHAIN_TYPE DEBUG_CONDITION = _DEBUG_CONDITION OPTIMIZATION_MODE_CONDITION = _OPTIMIZATION_MODE_CONDITION graal_binary_implementation = _graal_binary_implementation +graal_shared_binary_implementation = _graal_binary_implementation From 3383a37c58f73ffcaa5fc539482313fba8906d53 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:18:19 -0800 Subject: [PATCH 12/41] feat: modular native builds - support `main_module` attribute - format with `main_module` attr if present Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 2b02d7ea..bd857498 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -195,8 +195,15 @@ def assemble_native_build_options( if bin_postfix: trimmed_basename = trimmed_basename[0:-(len(bin_postfix))] - args.add(ctx.attr.main_class, format = "-H:Class=%s") args.add(trimmed_basename, format = "-H:Name=%s") + if ctx.attr.main_class != None and ctx.attr.main_class != "": + if ctx.attr.main_module != None and ctx.attr.main_module != "": + args.add( + "%s/%s" % (ctx.attr.main_module, ctx.attr.main_class), + format = "-H:Class=%s", + ) + else: + args.add(ctx.attr.main_class, format = "-H:Class=%s") # binary path supports expansion _arg_formatted( From e5ec85653954e6f79f070dacf969c010621ed43c Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:19:30 -0800 Subject: [PATCH 13/41] fix: override native image tmpdir for shared libs Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 21 ++++++++++++++------- internal/native_image/common.bzl | 5 +++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index bd857498..398ad2be 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -1,5 +1,7 @@ "Logic to assemble `native-image` options." +_NATIVE_IMAGE_SHARED_TMP_DIR_TPL = "native-shlib-%s" + _DEFAULT_NATIVE_IMAGE_ARGS = [ "-H:+ReportExceptionStackTraces", ] @@ -216,14 +218,19 @@ def assemble_native_build_options( # default native image args args.add_all(_DEFAULT_NATIVE_IMAGE_ARGS) - # declare a temp path for graalvm to use - tempdir = ctx.actions.declare_directory("native_image_build", sibling = binary) + tempdir = None + if ctx.attr.shared_library: + # declare a temp path for graalvm to use + tempdir = ctx.actions.declare_directory( + _NATIVE_IMAGE_SHARED_TMP_DIR_TPL % (ctx.label.name), + sibling = binary, + ) - # share temp path with graalvm sandbox, as genfiles root - args.add( - tempdir.path, - format = "-H:TempDirectory=%s", - ) + # share temp path with graalvm sandbox, as genfiles root + args.add( + tempdir.path, + format = "-H:TempDirectory=%s", + ) if not ctx.attr.check_toolchains: args.add("-H:-CheckToolchain") diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index c209c3a2..d26dca98 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -218,8 +218,9 @@ def _prepare_native_image_rule_context( bin_postfix, ) - # add native image tempdir to outputs - outputs.append(tempdir) + # add native image tempdir to outputs if one was allocated + if tempdir != None: + outputs.append(tempdir) return outputs ## Exports. From ebfc4216201ef154cece1e72382ca7ecfb62fddf Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:20:27 -0800 Subject: [PATCH 14/41] feat: implement `strict` attribute - provide `strict` attribute in all `native_image` rules - inject `strict` arguments according to latest gvm version Signed-off-by: Sam Gammon --- example/native/BUILD.bazel | 1 + internal/native_image/builder.bzl | 11 ++++++++++- internal/native_image/common.bzl | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/example/native/BUILD.bazel b/example/native/BUILD.bazel index ba44f5ec..957770f7 100644 --- a/example/native/BUILD.bazel +++ b/example/native/BUILD.bazel @@ -29,6 +29,7 @@ native_image( name = "main-native", main_class = "Main", deps = [":java"], + strict = True, ) alias( diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 398ad2be..905ca1be 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -3,7 +3,14 @@ _NATIVE_IMAGE_SHARED_TMP_DIR_TPL = "native-shlib-%s" _DEFAULT_NATIVE_IMAGE_ARGS = [ + "-H:+JNI", "-H:+ReportExceptionStackTraces", + "-H:+UnlockExperimentalVMOptions", +] + +_STRICT_NATIVE_IMAGE_ARGS = [ + "--link-at-build-time", + "--strict-image-heap", ] def _expand_var(ctx, arg, context = None, vars = None): @@ -215,8 +222,10 @@ def assemble_native_build_options( format = "-H:Path=%s", ) - # default native image args + # default native image args, and strict args if directed args.add_all(_DEFAULT_NATIVE_IMAGE_ARGS) + if ctx.attr.strict: + args.add_all(_STRICT_NATIVE_IMAGE_ARGS) tempdir = None if ctx.attr.shared_library: diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index d26dca98..2d8d96d8 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -72,6 +72,10 @@ _NATIVE_IMAGE_BASE_ATTRS = { mandatory = False, default = False, ), + "strict": attr.bool( + mandatory = False, + default = False, + ), "optimization_mode": attr.string( mandatory = False, values = [ From dd5f4a4a46f69b7eca5eb75a47f0d911e054c145 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:21:15 -0800 Subject: [PATCH 15/41] feat: multi-config attributes - add multi-label variants of config file attribuets for resources, jni, and so on - disallow use of singular and plural attributes together in one target definition Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 74 +++++++++++++++++++++++++++---- internal/native_image/common.bzl | 13 ++++++ 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 905ca1be..df6b6d59 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -93,6 +93,45 @@ def _configure_optimization_mode(ctx, args): format = "-O%s", ) +def _singular_or_multi_but_not_both(args, direct_inputs, singular_label, plural_label, singular, plural, format = "%s", separator = ","): + """Use either the singular form of a file attribute, or the multi-label form, but fail if both are provided. + + Resulting arguments are formatted (if necessary) and appended to the `direct_inputs` list and + suite of args. + + Args: + args: Arguments to add to. + direct_inputs: Direct inputs list to append to for matching files. + singular_label: Label for the singular attribute. Used in error messages. + plural_label: Label for the plural attribute. Used in error messages. + singular: Singular attribute value. + plural: Plural attribute value. + format: Format string for the attribute value. + separator: Separator for the attribute value. + """ + + values = [] + if singular != None: + values.append(singular) + elif plural and len(plural) > 0: + values.extend(plural) + elif (plural == None or len(plural) == 0) and (singular == None): + pass + else: + fail( + "GraalVM Rules: Please provide singular or plural attributes, but not both. Got both: %s and %s." % ( + singular_label, + plural_label + )) + + if len(values) > 0: + args.add_joined( + values, + join_with = separator, + format_joined = format, + ) + direct_inputs.extend(values) + def _configure_reflection(ctx, args, direct_inputs): """Configure reflection settings for a Native Image build. @@ -113,14 +152,33 @@ def _configure_reflection(ctx, args, direct_inputs): format_joined = "--initialize-at-run-time=%s", ) - if ctx.attr.reflection_configuration != None: - args.add(ctx.file.reflection_configuration, format = "-H:ReflectionConfigurationFiles=%s") - direct_inputs.append(ctx.file.reflection_configuration) - - if ctx.attr.jni_configuration != None: - args.add(ctx.file.jni_configuration, format = "-H:JNIConfigurationFiles=%s") - direct_inputs.append(ctx.file.jni_configuration) - args.add("-H:+JNI") + _singular_or_multi_but_not_both( + args, + direct_inputs, + "reflection_configuration", + "reflection_configurations", + ctx.file.reflection_configuration, + ctx.files.reflection_configurations, + format = "-H:ReflectionConfigurationFiles=%s", + ) + _singular_or_multi_but_not_both( + args, + direct_inputs, + "jni_configuration", + "jni_configurations", + ctx.file.jni_configuration, + ctx.files.jni_configurations, + format = "-H:JNIConfigurationFiles=%s", + ) + _singular_or_multi_but_not_both( + args, + direct_inputs, + "resource_configuration", + "resource_configurations", + ctx.file.resource_configuration, + ctx.files.resource_configurations, + format = "-H:ResourceConfigurationFiles=%s", + ) def _configure_native_compiler(ctx, args, c_compiler_path, gvm_toolchain): """Configure native compiler and linker flags for a Native Image build. diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index 2d8d96d8..40533070 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -64,10 +64,23 @@ _NATIVE_IMAGE_BASE_ATTRS = { mandatory = False, allow_single_file = True, ), + "reflection_configurations": attr.label_list( + mandatory = False, + ), "jni_configuration": attr.label( mandatory = False, allow_single_file = True, ), + "jni_configurations": attr.label_list( + mandatory = False, + ), + "resource_configuration": attr.label( + mandatory = False, + allow_single_file = True, + ), + "resource_configurations": attr.label_list( + mandatory = False, + ), "debug": attr.bool( mandatory = False, default = False, From 36befe6e10dac707ad6d034b38a352cb29985a61 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:22:02 -0800 Subject: [PATCH 16/41] fix: provide genfiles dir to native image env Signed-off-by: Sam Gammon --- internal/native_image/rules.bzl | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index c6ebe4e8..72018b85 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -49,6 +49,7 @@ def _prepare_execution_env(ctx, base_env = {}): effective.update(base_env) effective.update({ "GRAALVM_BAZEL": "true", + "GENFILES_DIR": ctx.genfiles_dir.path, }) return effective From 19e679d642bb4849ab2eec1b909d4a7b1eea4b76 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:38:10 -0800 Subject: [PATCH 17/41] feat: better `debug` build experience - don't delete local symbols for `debug` builds - enable source-level debugging by default for `debug` builds Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index df6b6d59..286988ce 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -13,6 +13,12 @@ _STRICT_NATIVE_IMAGE_ARGS = [ "--strict-image-heap", ] +_DEBUG_NATIVE_IMAGE_ARGS = [ + "-g", + "-H:+SourceLevelDebug", + "-H:-DeleteLocalSymbols", +] + def _expand_var(ctx, arg, context = None, vars = None): return ctx.expand_make_variables( "native_image", @@ -77,7 +83,7 @@ def _configure_debug(ctx, args): """ if ctx.attr.debug: - args.add("-g") + args.add_all(_DEBUG_NATIVE_IMAGE_ARGS) def _configure_optimization_mode(ctx, args): """Configure the Native Image optimization mode to match Bazel's build setting. From bb3ae0aadc01866f5c04e90ad19c59ffc1e94702 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 18:47:30 -0800 Subject: [PATCH 18/41] feat: implement support for output groups - add common enum for output group names - add named output group for shared library headers - use default output group for binary or shared library Signed-off-by: Sam Gammon --- graalvm/artifacts/maven.bzl | 3 +++ graalvm/nativeimage/rules.bzl | 15 +++++++++++++ internal/native_image/common.bzl | 10 +++++++++ internal/native_image/rules.bzl | 38 +++++++++++++++++++++++--------- 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/graalvm/artifacts/maven.bzl b/graalvm/artifacts/maven.bzl index d66c987e..6ad05531 100644 --- a/graalvm/artifacts/maven.bzl +++ b/graalvm/artifacts/maven.bzl @@ -119,6 +119,9 @@ _MavenTools = struct( artifact = _graalvm_maven_artifact, ) +# buildifier: disable=name-conventions +MavenTools = _MavenTools + # Exports. # buildifier: disable=name-conventions diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index 5645a4dc..0e30c5a6 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -8,12 +8,18 @@ load( "@bazel_tools//tools/cpp:toolchain_utils.bzl", "use_cpp_toolchain", ) +load( + "//graalvm/artifacts:maven.bzl", + _MavenArtifacts = "MavenArtifacts", + _graalvm_maven_artifact = "graalvm_maven_artifact", +) load( "//internal/native_image:rules.bzl", _DEBUG = "DEBUG_CONDITION", _GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE", _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", _NATIVE_IMAGE_SHARED_LIB_ATTRS = "NATIVE_IMAGE_SHARED_LIB_ATTRS", + _OUTPUT_GROUPS = "OUTPUT_GROUPS", _OPTIMIZATION_MODE = "OPTIMIZATION_MODE_CONDITION", _graal_binary_implementation = "graal_binary_implementation", _graal_shared_binary_implementation = "graal_shared_binary_implementation", @@ -81,6 +87,12 @@ _native_image_shared_library = rule( ], ) +_NATIVE_IMAGE_UTILS = struct( + output_groups = _OUTPUT_GROUPS, + catalog = _MavenArtifacts, + artifact = _graalvm_maven_artifact, +) + # Exports. def native_image( name, @@ -264,3 +276,6 @@ def native_image_shared_library( default_outputs = default_outputs, **kwargs ) + +# Struct alias. +graalvm = _NATIVE_IMAGE_UTILS diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index 40533070..35474ab9 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -44,6 +44,15 @@ _OPTIMIZATION_MODE_CONDITION = select({ "//conditions:default": _NativeImageOptimization.DEFAULT, # becomes `-O2` via GraalVM defaults }) +_OUTPUT_GROUPS = struct( + DEFAULT = "default", + SYMBOLS = "symbols", + HEADERS = "headers", + OBJECTS = "objects", + PROFILES = "profiles", + RESOURCES = "resources", +) + _NATIVE_IMAGE_BASE_ATTRS = { "deps": attr.label_list( providers = [[JavaInfo]], @@ -246,6 +255,7 @@ def _prepare_native_image_rule_context( NativeImageOptimization = _NativeImageOptimization RULES_REPO = _RULES_REPO +OUTPUT_GROUPS = _OUTPUT_GROUPS DEFAULT_GVM_REPO = _DEFAULT_GVM_REPO DEBUG_CONDITION = _DEBUG_CONDITION COVERAGE_CONDITION = _COVERAGE_CONDITION diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 72018b85..d532568d 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -21,6 +21,7 @@ load( _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", _NATIVE_IMAGE_SHARED_LIB_ATTRS = "NATIVE_IMAGE_SHARED_LIB_ATTRS", _OPTIMIZATION_MODE_CONDITION = "OPTIMIZATION_MODE_CONDITION", + _OUTPUT_GROUPS = "OUTPUT_GROUPS", _RULES_REPO = "RULES_REPO", _prepare_native_image_rule_context = "prepare_native_image_rule_context", ) @@ -54,6 +55,7 @@ def _prepare_execution_env(ctx, base_env = {}): return effective def _graal_binary_implementation(ctx): + output_groups = {} graal_attr = ctx.attr.native_image_tool extra_tool_deps = [] gvm_toolchain = None @@ -188,7 +190,7 @@ def _graal_binary_implementation(ctx): ) # if we are building a shared library, prepare `CcSharedLibraryInfo` for it - cc_info = [] + output_infos = [] runfiles = None if ctx.attr.shared_library: cc_toolchain = find_cpp_toolchain(ctx) @@ -206,10 +208,10 @@ def _graal_binary_implementation(ctx): dynamic_library = binary, ), ] - cc_info.extend([ - OutputGroupInfo( - main_shared_library_output = depset([binary]), - ), + + ## extend with additional cc info for shared library use + output_groups["main_shared_library_output"] = depset([binary]) + output_infos.extend([ CcSharedLibraryInfo( linker_input = cc_common.create_linker_input( owner = ctx.label, @@ -218,6 +220,16 @@ def _graal_binary_implementation(ctx): ), ]) + # add output group for shared headers + # output_groups[_OUTPUT_GROUPS.HEADERS] = depset([binary]) + + # in shared library mode, the shared library is the default output + output_groups[_OUTPUT_GROUPS.DEFAULT] = depset([binary]) + + else: + # if it's not a shared library, our default output is the binary produced + output_groups[_OUTPUT_GROUPS.DEFAULT] = depset([binary]) + # prepare all runfiles all_runfiles = ctx.runfiles( collect_data = True, @@ -227,11 +239,16 @@ def _graal_binary_implementation(ctx): if runfiles != None: all_runfiles = all_runfiles.merge(runfiles) - return cc_info + [DefaultInfo( - executable = binary, - files = depset(all_outputs), - runfiles = all_runfiles, - )] + return output_infos + [ + DefaultInfo( + executable = binary, + files = depset(all_outputs), + runfiles = all_runfiles, + ), + OutputGroupInfo( + **output_groups + ) + ] def _wrap_actions_for_graal(actions): """Wraps the given ctx.actions struct so that env variables are correctly passed to Graal.""" @@ -265,6 +282,7 @@ BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_ATTRS NATIVE_IMAGE_SHARED_LIB_ATTRS = _NATIVE_IMAGE_SHARED_LIB_ATTRS GVM_TOOLCHAIN_TYPE = _GVM_TOOLCHAIN_TYPE +OUTPUT_GROUPS = _OUTPUT_GROUPS DEBUG_CONDITION = _DEBUG_CONDITION OPTIMIZATION_MODE_CONDITION = _OPTIMIZATION_MODE_CONDITION graal_binary_implementation = _graal_binary_implementation From b61399ca555b758cc54b4a8aacff3cd51226ca2c Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 19:21:43 -0800 Subject: [PATCH 19/41] feat: support for `neverlink` - add transitive inputs for compile-time jars - mark applicable dependencies with `neverlink` Relates-To: sgammon/rules_graalvm#243 Signed-off-by: Sam Gammon --- MODULE.bazel | 36 +++++++++++++++++++++---------- graalvm/artifacts/maven.bzl | 9 ++++++++ internal/maven.bzl | 4 ++-- internal/native_image/classic.bzl | 6 +++++- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index fe9ffd18..c4aba1a6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -137,11 +137,31 @@ bazel_dep( # rules_jvm_external ################################################################################ -MAVEN_ARTIFACTS = [ - "org.graalvm.nativeimage:svm:%s" % GRAALVM_SDK_VERSION, - "org.graalvm.sdk:graal-sdk:%s" % GRAALVM_SDK_VERSION, - "org.graalvm.polyglot:polyglot:%s" % GRAALVM_SDK_VERSION, -] +maven = use_extension( + "@rules_jvm_external//:extensions.bzl", + "maven", + dev_dependency = True, +) +maven.artifact( + name = "maven_gvm", + group = "org.graalvm.nativeimage", + artifact= "svm", + version = GRAALVM_SDK_VERSION, + neverlink = True, +) +maven.artifact( + name = "maven_gvm", + group = "org.graalvm.sdk", + artifact= "graal_sdk", + version = GRAALVM_SDK_VERSION, + neverlink = True, +) +maven.artifact( + name = "maven_gvm", + group = "org.graalvm.polyglot", + artifact= "polyglot", + version = GRAALVM_SDK_VERSION, +) MAVEN_REPOSITORIES = [ "https://maven.pkg.st", @@ -149,14 +169,8 @@ MAVEN_REPOSITORIES = [ "https://repo1.maven.org/maven2", ] -maven = use_extension( - "@rules_jvm_external//:extensions.bzl", - "maven", - dev_dependency = True, -) maven.install( name = "maven_gvm", - artifacts = MAVEN_ARTIFACTS, lock_file = "//:maven_install.json", repositories = MAVEN_REPOSITORIES, ) diff --git a/graalvm/artifacts/maven.bzl b/graalvm/artifacts/maven.bzl index 6ad05531..9deb1a77 100644 --- a/graalvm/artifacts/maven.bzl +++ b/graalvm/artifacts/maven.bzl @@ -1,10 +1,18 @@ "Defines Maven helpers and coordinates for GraalVM artifacts." +load("@rules_jvm_external//:specs.bzl", "maven") + # buildifier: disable=name-conventions _MavenArtifacts = struct( + SVM = struct( + artifact = "svm", + group = "org.graalvm.nativeimage", + neverlink = True, + ), SDK = struct( artifact = "graal-sdk", group = "org.graalvm.sdk", + neverlink = True, ), POLYGLOT = struct( artifact = "polyglot", @@ -111,6 +119,7 @@ def _graalvm_maven_artifact(maven, artifact, version): artifact = artifact.artifact, group = artifact.group, version = version, + neverlink = artifact.get("neverlink", False), ) # buildifier: disable=name-conventions diff --git a/internal/maven.bzl b/internal/maven.bzl index 0b977b3e..375acdc7 100644 --- a/internal/maven.bzl +++ b/internal/maven.bzl @@ -2,7 +2,7 @@ load( "//internal:config.bzl", - "GRAALVM_VERSION", + _GRAALVM_VERSION = "GRAALVM_VERSION", ) def graalvm(artifact, repository = "@maven", version = None, group = None): @@ -25,7 +25,7 @@ def graalvm(artifact, repository = "@maven", version = None, group = None): group = (group or artifact.split(":")[0]).replace(".", "_") name = (group and artifact or artifact.split(":")[1]).replace(".", "_") - resolved_version = version or GRAALVM_VERSION + resolved_version = version or _GRAALVM_VERSION if resolved_version: formatted_version = resolved_version.replace(".", "_") diff --git a/internal/native_image/classic.bzl b/internal/native_image/classic.bzl index 62172c67..2e2f3793 100644 --- a/internal/native_image/classic.bzl +++ b/internal/native_image/classic.bzl @@ -27,9 +27,13 @@ def _graal_binary_classic_implementation(ctx): dep[JavaInfo].transitive_runtime_jars for dep in ctx.attr.deps ]) + classpath_neverlink_depset = depset(transitive = [ + dep[JavaInfo].transitive_compile_time_jars + for dep in ctx.attr.deps + ]) direct_inputs = [] - transitive_inputs = [classpath_depset] + transitive_inputs = [classpath_depset, classpath_neverlink_depset] if graal_attr != None: # otherwise, use the legacy code path. the `graal` value is used in the run From 85cfed700654596f4284dbed0dd354734df5c21f Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 19:22:57 -0800 Subject: [PATCH 20/41] chore: update blzmod lock Signed-off-by: Sam Gammon --- MODULE.bazel.lock | 78 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index ca056e85..013674d1 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,6 +1,6 @@ { "lockFileVersion": 3, - "moduleFileHash": "fa50be8381e0ebb2e2dd9fbb5eeff1495406335c7141ccc5d5d24800f8374789", + "moduleFileHash": "c95fac7b8759c10d5755dc4955d5d0cfe05aed0b945acf9097a5b6aadf10eaf2", "flags": { "cmdRegistries": [ "https://bcr.bazel.build/" @@ -34,7 +34,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 152, + "line": 140, "column": 22 }, "imports": { @@ -46,15 +46,57 @@ "unpinned_maven_gvm" ], "tags": [ + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.graalvm.nativeimage", + "artifact": "svm", + "version": "23.1.1", + "neverlink": true + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 145, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.graalvm.sdk", + "artifact": "graal_sdk", + "version": "23.1.1", + "neverlink": true + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 152, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.graalvm.polyglot", + "artifact": "polyglot", + "version": "23.1.1" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 159, + "column": 15 + } + }, { "tagName": "install", "attributeValues": { "name": "maven_gvm", - "artifacts": [ - "org.graalvm.nativeimage:svm:23.1.1", - "org.graalvm.sdk:graal-sdk:23.1.1", - "org.graalvm.polyglot:polyglot:23.1.1" - ], "lock_file": "//:maven_install.json", "repositories": [ "https://maven.pkg.st", @@ -65,7 +107,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 157, + "line": 172, "column": 14 } } @@ -79,7 +121,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 173, + "line": 187, "column": 20 }, "imports": { @@ -102,7 +144,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 178, + "line": 192, "column": 12 } } @@ -116,7 +158,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 212, + "line": 226, "column": 21 }, "imports": {}, @@ -130,7 +172,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 217, + "line": 231, "column": 15 } } @@ -144,7 +186,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 219, + "line": 233, "column": 20 }, "imports": { @@ -164,7 +206,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 224, + "line": 238, "column": 23 } } @@ -4644,8 +4686,8 @@ "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" ], "artifacts": [ - "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\" }", - "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal-sdk\", \"version\": \"23.1.1\" }", + "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\", \"neverlink\": true }", + "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal_sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }" ], "fail_on_missing_checksum": true, @@ -4747,8 +4789,8 @@ "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" ], "artifacts": [ - "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\" }", - "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal-sdk\", \"version\": \"23.1.1\" }", + "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\", \"neverlink\": true }", + "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal_sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }" ], "fetch_sources": true, From f3a80308174e12cccb55e07f0d04b67e6bd32ae1 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 19:50:10 -0800 Subject: [PATCH 21/41] fix: don't pull in jvm external from main rule entrypoint Signed-off-by: Sam Gammon --- graalvm/nativeimage/rules.bzl | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index 0e30c5a6..d2f50649 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -8,11 +8,6 @@ load( "@bazel_tools//tools/cpp:toolchain_utils.bzl", "use_cpp_toolchain", ) -load( - "//graalvm/artifacts:maven.bzl", - _MavenArtifacts = "MavenArtifacts", - _graalvm_maven_artifact = "graalvm_maven_artifact", -) load( "//internal/native_image:rules.bzl", _DEBUG = "DEBUG_CONDITION", @@ -89,8 +84,6 @@ _native_image_shared_library = rule( _NATIVE_IMAGE_UTILS = struct( output_groups = _OUTPUT_GROUPS, - catalog = _MavenArtifacts, - artifact = _graalvm_maven_artifact, ) # Exports. @@ -277,5 +270,5 @@ def native_image_shared_library( **kwargs ) -# Struct alias. -graalvm = _NATIVE_IMAGE_UTILS +# Aliases. +utils = _NATIVE_IMAGE_UTILS From e36ba064d8801fcf5ad5bd2bd1265b01bfdb470a Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 19:50:28 -0800 Subject: [PATCH 22/41] fix: don't provide UnlockExperimentalOptions yet Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 286988ce..40c1fa03 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -5,7 +5,6 @@ _NATIVE_IMAGE_SHARED_TMP_DIR_TPL = "native-shlib-%s" _DEFAULT_NATIVE_IMAGE_ARGS = [ "-H:+JNI", "-H:+ReportExceptionStackTraces", - "-H:+UnlockExperimentalVMOptions", ] _STRICT_NATIVE_IMAGE_ARGS = [ @@ -252,6 +251,9 @@ def assemble_native_build_options( Tempdir path where the native build should occur. """ + # @TODO(sgammon): only append with gvm version > 23.1.x + # "-H:+UnlockExperimentalVMOptions" + # main class is required unless we are building a shared library if ctx.attr.shared_library: args.add("--shared") From 167d4f636a0a951a90ddf12d5258aa3609a7cb6f Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 19:50:31 -0800 Subject: [PATCH 23/41] chore: update blzmod lock Signed-off-by: Sam Gammon --- MODULE.bazel.lock | 180 +++++++++--------- .../bzlmod/MODULE.bazel.lock | 125 +++++++++++- 2 files changed, 213 insertions(+), 92 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 013674d1..f70c7ff5 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -223,6 +223,7 @@ "build_bazel_apple_support": "apple_support@1.8.1", "rules_license": "rules_license@0.0.7", "rules_cc": "rules_cc@0.0.9", + "rules_jvm_external": "rules_jvm_external@5.3", "rules_python": "rules_python@0.25.0", "rules_testing": "rules_testing@0.4.0", "aspect_bazel_lib": "aspect_bazel_lib@1.34.1", @@ -231,7 +232,6 @@ "com_google_protobuf": "protobuf@21.7", "io_bazel_rules_go": "rules_go@0.41.0", "bazel_gazelle": "gazelle@0.32.0", - "rules_jvm_external": "rules_jvm_external@5.3", "io_bazel_stardoc": "stardoc@0.6.2", "bazel_skylib_gazelle_plugin": "bazel_skylib_gazelle_plugin@1.4.2", "contrib_rules_jvm": "contrib_rules_jvm@0.18.0", @@ -578,6 +578,95 @@ } } }, + "rules_jvm_external@5.3": { + "name": "rules_jvm_external", + "version": "5.3", + "key": "rules_jvm_external@5.3", + "repoName": "rules_jvm_external", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 9, + "column": 32 + }, + "imports": { + "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": ":extensions.bzl", + "extensionName": "maven", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 16, + "column": 22 + }, + "imports": { + "rules_jvm_external_deps": "rules_jvm_external_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "rules_jvm_external_deps", + "artifacts": [ + "com.google.auth:google-auth-library-credentials:1.17.0", + "com.google.auth:google-auth-library-oauth2-http:1.17.0", + "com.google.cloud:google-cloud-core:2.18.1", + "com.google.cloud:google-cloud-storage:2.22.3", + "com.google.code.gson:gson:2.10.1", + "com.google.googlejavaformat:google-java-format:1.17.0", + "com.google.guava:guava:32.0.0-jre", + "org.apache.maven:maven-artifact:3.9.2", + "software.amazon.awssdk:s3:2.20.78" + ], + "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 18, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "io_bazel_stardoc": "stardoc@0.6.2", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_jvm_external~5.3", + "urls": [ + "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" + ], + "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", + "strip_prefix": "rules_jvm_external-5.3", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, "rules_python@0.25.0": { "name": "rules_python", "version": "0.25.0", @@ -1278,95 +1367,6 @@ } } }, - "rules_jvm_external@5.3": { - "name": "rules_jvm_external", - "version": "5.3", - "key": "rules_jvm_external@5.3", - "repoName": "rules_jvm_external", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", - "extensionName": "non_module_deps", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 9, - "column": 32 - }, - "imports": { - "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": ":extensions.bzl", - "extensionName": "maven", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 16, - "column": 22 - }, - "imports": { - "rules_jvm_external_deps": "rules_jvm_external_deps" - }, - "devImports": [], - "tags": [ - { - "tagName": "install", - "attributeValues": { - "name": "rules_jvm_external_deps", - "artifacts": [ - "com.google.auth:google-auth-library-credentials:1.17.0", - "com.google.auth:google-auth-library-oauth2-http:1.17.0", - "com.google.cloud:google-cloud-core:2.18.1", - "com.google.cloud:google-cloud-storage:2.22.3", - "com.google.code.gson:gson:2.10.1", - "com.google.googlejavaformat:google-java-format:1.17.0", - "com.google.guava:guava:32.0.0-jre", - "org.apache.maven:maven-artifact:3.9.2", - "software.amazon.awssdk:s3:2.20.78" - ], - "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 18, - "column": 14 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "io_bazel_stardoc": "stardoc@0.6.2", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_jvm_external~5.3", - "urls": [ - "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" - ], - "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", - "strip_prefix": "rules_jvm_external-5.3", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, "stardoc@0.6.2": { "name": "stardoc", "version": "0.6.2", diff --git a/example/integration_tests/bzlmod/MODULE.bazel.lock b/example/integration_tests/bzlmod/MODULE.bazel.lock index f8c1a7cd..d92910d2 100644 --- a/example/integration_tests/bzlmod/MODULE.bazel.lock +++ b/example/integration_tests/bzlmod/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "fa50be8381e0ebb2e2dd9fbb5eeff1495406335c7141ccc5d5d24800f8374789" + "rules_graalvm": "170782bb5188a142bef3bfce5e814b429c4c6c50bc64562672986382dfa22855" }, "moduleDepGraph": { "": { @@ -182,6 +182,7 @@ "platforms": "platforms@0.0.7", "bazel_features": "bazel_features@1.0.0", "rules_java": "rules_java@7.1.0", + "rules_jvm_external": "rules_jvm_external@5.3", "bazel_skylib": "bazel_skylib@1.5.0", "build_bazel_apple_support": "apple_support@1.8.1", "bazel_tools": "bazel_tools@_", @@ -550,6 +551,95 @@ } } }, + "rules_jvm_external@5.3": { + "name": "rules_jvm_external", + "version": "5.3", + "key": "rules_jvm_external@5.3", + "repoName": "rules_jvm_external", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 9, + "column": 32 + }, + "imports": { + "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": ":extensions.bzl", + "extensionName": "maven", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 16, + "column": 22 + }, + "imports": { + "rules_jvm_external_deps": "rules_jvm_external_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "rules_jvm_external_deps", + "artifacts": [ + "com.google.auth:google-auth-library-credentials:1.17.0", + "com.google.auth:google-auth-library-oauth2-http:1.17.0", + "com.google.cloud:google-cloud-core:2.18.1", + "com.google.cloud:google-cloud-storage:2.22.3", + "com.google.code.gson:gson:2.10.1", + "com.google.googlejavaformat:google-java-format:1.17.0", + "com.google.guava:guava:32.0.0-jre", + "org.apache.maven:maven-artifact:3.9.2", + "software.amazon.awssdk:s3:2.20.78" + ], + "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 18, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "io_bazel_stardoc": "stardoc@0.5.3", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_jvm_external~5.3", + "urls": [ + "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" + ], + "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", + "strip_prefix": "rules_jvm_external-5.3", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, "apple_support@1.8.1": { "name": "apple_support", "version": "1.8.1", @@ -726,6 +816,37 @@ "remote_patch_strip": 0 } } + }, + "stardoc@0.5.3": { + "name": "stardoc", + "version": "0.5.3", + "key": "stardoc@0.5.3", + "repoName": "stardoc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "rules_java": "rules_java@7.1.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "stardoc~0.5.3", + "urls": [ + "https://github.com/bazelbuild/stardoc/releases/download/0.5.3/stardoc-0.5.3.tar.gz" + ], + "integrity": "sha256-P9j+xN3sPGcL2BCQTi4zFwvt/hL5Ct+UNQgYS+RYyLs=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/stardoc/0.5.3/patches/module_dot_bazel.patch": "sha256-Lgpy9OCr0zBWYuHoyM1rJJrgxn23X/bwgICEF7XiEug=" + }, + "remote_patch_strip": 0 + } + } } }, "moduleExtensions": { @@ -811,7 +932,7 @@ }, "@@rules_graalvm~override//:extensions.bzl%graalvm": { "general": { - "bzlTransitiveDigest": "PkyvavvK5e4FjXXNmFAYYcGB6FofYxEbQwP3Uuc8TR4=", + "bzlTransitiveDigest": "mRzSuTlbQlQ0snbnMM3X7itZ8Eh1p7TKee6l6JsBWUc=", "accumulatedFileDigests": {}, "envVariables": {}, "generatedRepoSpecs": { From 811d5fe519051dc75489494f7f5c388a46562fc2 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 19:56:45 -0800 Subject: [PATCH 24/41] fix: artifact options with structs Signed-off-by: Sam Gammon --- graalvm/artifacts/maven.bzl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/graalvm/artifacts/maven.bzl b/graalvm/artifacts/maven.bzl index 9deb1a77..9d65c2e0 100644 --- a/graalvm/artifacts/maven.bzl +++ b/graalvm/artifacts/maven.bzl @@ -7,23 +7,26 @@ _MavenArtifacts = struct( SVM = struct( artifact = "svm", group = "org.graalvm.nativeimage", - neverlink = True, + options = {"neverlink": True}, ), SDK = struct( artifact = "graal-sdk", group = "org.graalvm.sdk", - neverlink = True, + options = {"neverlink": True}, ), POLYGLOT = struct( artifact = "polyglot", group = "org.graalvm.polyglot", + options = {}, ), TRUFFLE = struct( artifact = "truffle-api", group = "org.graalvm.truffle", + options = {}, NFI = struct( artifact = "truffle-nfi", group = "org.graalvm.truffle", + options = {}, ), ), ) @@ -119,7 +122,7 @@ def _graalvm_maven_artifact(maven, artifact, version): artifact = artifact.artifact, group = artifact.group, version = version, - neverlink = artifact.get("neverlink", False), + **artifact.options, ) # buildifier: disable=name-conventions From ca030882352f5003b5d132526ef7fb0e359242a8 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:00:49 -0800 Subject: [PATCH 25/41] fix: proper `print` for debug message Signed-off-by: Sam Gammon --- graalvm/nativeimage/rules.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index d2f50649..dc757624 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -151,7 +151,7 @@ def native_image( """ if shared_library: - debug("GraalVM rules for Bazel at >0.11.x uses `native_image_shared_library`. Please migrate at your convenience.") + print("GraalVM rules for Bazel at >0.11.x uses `native_image_shared_library`. Please migrate at your convenience.") _native_image( name = name, From 2ed1f4f47d85867e93596efb6f17649a4e72ffcb Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:01:11 -0800 Subject: [PATCH 26/41] fix: `main_class` not available for shared libraries Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 40c1fa03..74a9a7ec 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -271,14 +271,15 @@ def assemble_native_build_options( trimmed_basename = trimmed_basename[0:-(len(bin_postfix))] args.add(trimmed_basename, format = "-H:Name=%s") - if ctx.attr.main_class != None and ctx.attr.main_class != "": - if ctx.attr.main_module != None and ctx.attr.main_module != "": - args.add( - "%s/%s" % (ctx.attr.main_module, ctx.attr.main_class), - format = "-H:Class=%s", - ) - else: - args.add(ctx.attr.main_class, format = "-H:Class=%s") + if not ctx.attr.shared_library: + if ctx.attr.main_class != None and ctx.attr.main_class != "": + if ctx.attr.main_module != None and ctx.attr.main_module != "": + args.add( + "%s/%s" % (ctx.attr.main_module, ctx.attr.main_class), + format = "-H:Class=%s", + ) + else: + args.add(ctx.attr.main_class, format = "-H:Class=%s") # binary path supports expansion _arg_formatted( From 1e9c24b86eed7219b74d2b053b116bb9fb64cc45 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:01:34 -0800 Subject: [PATCH 27/41] test: move to new `native_image_shared_library` rule Signed-off-by: Sam Gammon --- example/integration_tests/shared-lib/MODULE.bazel.lock | 4 ++-- example/integration_tests/shared-lib/sample/BUILD.bazel | 5 ++--- graalvm/defs.bzl | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/example/integration_tests/shared-lib/MODULE.bazel.lock b/example/integration_tests/shared-lib/MODULE.bazel.lock index f8c1a7cd..213e2ed5 100644 --- a/example/integration_tests/shared-lib/MODULE.bazel.lock +++ b/example/integration_tests/shared-lib/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "fa50be8381e0ebb2e2dd9fbb5eeff1495406335c7141ccc5d5d24800f8374789" + "rules_graalvm": "c95fac7b8759c10d5755dc4955d5d0cfe05aed0b945acf9097a5b6aadf10eaf2" }, "moduleDepGraph": { "": { @@ -811,7 +811,7 @@ }, "@@rules_graalvm~override//:extensions.bzl%graalvm": { "general": { - "bzlTransitiveDigest": "PkyvavvK5e4FjXXNmFAYYcGB6FofYxEbQwP3Uuc8TR4=", + "bzlTransitiveDigest": "mRzSuTlbQlQ0snbnMM3X7itZ8Eh1p7TKee6l6JsBWUc=", "accumulatedFileDigests": {}, "envVariables": {}, "generatedRepoSpecs": { diff --git a/example/integration_tests/shared-lib/sample/BUILD.bazel b/example/integration_tests/shared-lib/sample/BUILD.bazel index 38a62864..4acc1785 100644 --- a/example/integration_tests/shared-lib/sample/BUILD.bazel +++ b/example/integration_tests/shared-lib/sample/BUILD.bazel @@ -1,6 +1,6 @@ load( "@rules_graalvm//graalvm:defs.bzl", - "native_image", + "native_image_shared_library", ) java_library( @@ -8,10 +8,9 @@ java_library( srcs = ["Main.java"], ) -native_image( +native_image_shared_library( name = "lib-native", deps = [":java"], - shared_library = True, ) alias( diff --git a/graalvm/defs.bzl b/graalvm/defs.bzl index 0cb4121a..f74fd591 100644 --- a/graalvm/defs.bzl +++ b/graalvm/defs.bzl @@ -3,7 +3,9 @@ load( "//graalvm/nativeimage:rules.bzl", _native_image = "native_image", + _native_image_shared_library = "native_image_shared_library", ) ## Exports native_image = _native_image +native_image_shared_library = _native_image_shared_library From 5c674d1f2196db33158fbafa7c7f5b48bc00e825 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:51:25 -0800 Subject: [PATCH 28/41] feat: ability to move specific deps to `modulepath` - add new `module_deps` attribute - add example of modular java use - wire in `main_module` attribute - process into separate module path (direct only) - append to `native-image` invocation as `--module-path` Signed-off-by: Sam Gammon --- example/modular/BUILD.bazel | 58 +++++++++++++++++++++++++++++++ example/modular/Main.java | 5 +++ example/modular/module-info.java | 4 +++ example/modular/reflection.json | 30 ++++++++++++++++ graalvm/nativeimage/rules.bzl | 1 + internal/native_image/builder.bzl | 9 +++-- internal/native_image/common.bzl | 8 ++++- internal/native_image/rules.bzl | 20 +++++++++-- 8 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 example/modular/BUILD.bazel create mode 100644 example/modular/Main.java create mode 100644 example/modular/module-info.java create mode 100644 example/modular/reflection.json diff --git a/example/modular/BUILD.bazel b/example/modular/BUILD.bazel new file mode 100644 index 00000000..2a674da8 --- /dev/null +++ b/example/modular/BUILD.bazel @@ -0,0 +1,58 @@ +load( + "@rules_graalvm//graalvm:defs.bzl", + "native_image", +) +load( + "@rules_graalvm//graalvm/artifacts:maven.bzl", + graalvm = "alias", +) +load( + "@rules_java//java:defs.bzl", + "java_binary", + "java_library", +) + +package(default_visibility = [ + "//tests:__subpackages__", +]) + + +filegroup( + name = "reflection-config", + srcs = ["reflection.json"], +) + +java_library( + name = "java", + srcs = [ + "Main.java", + "module-info.java", + ], + deps = [ + graalvm.artifact(graalvm.catalog.SDK, repo = "@maven_gvm"), + ], +) + +java_binary( + name = "main", + main_class = "app/Main", + runtime_deps = [ + ":java", + ], +) + +native_image( + name = "main-modular", + main_class = "Main", + deps = [":java"], + strict = True, + reflection_configuration = ":reflection-config", + module_deps = [ + graalvm.artifact(graalvm.catalog.SDK, repo = "@maven_gvm"), + ], +) + +alias( + name = "modular", + actual = "main-modular", +) diff --git a/example/modular/Main.java b/example/modular/Main.java new file mode 100644 index 00000000..c9824efb --- /dev/null +++ b/example/modular/Main.java @@ -0,0 +1,5 @@ +public class Main { + public static void main(String args[]) { + System.out.println("Hello, GraalVM!"); + } +} \ No newline at end of file diff --git a/example/modular/module-info.java b/example/modular/module-info.java new file mode 100644 index 00000000..0c8674cd --- /dev/null +++ b/example/modular/module-info.java @@ -0,0 +1,4 @@ +module app { + requires java.base; + requires org.graalvm.sdk; +} diff --git a/example/modular/reflection.json b/example/modular/reflection.json new file mode 100644 index 00000000..2ef1801f --- /dev/null +++ b/example/modular/reflection.json @@ -0,0 +1,30 @@ +[ + { + "name" : "java.lang.Class", + "allDeclaredConstructors" : true, + "allPublicConstructors" : true, + "allDeclaredMethods" : true, + "allPublicMethods" : true, + "allDeclaredClasses" : true, + "allPublicClasses" : true + }, + { + "name" : "java.lang.String", + "fields" : [ + { "name" : "value", "allowWrite" : true }, + { "name" : "hash" } + ], + "methods" : [ + { "name" : "", "parameterTypes" : [] }, + { "name" : "", "parameterTypes" : ["char[]"] }, + { "name" : "charAt" }, + { "name" : "format", "parameterTypes" : ["java.lang.String", "java.lang.Object[]"] } + ] + }, + { + "name" : "java.lang.String$CaseInsensitiveComparator", + "methods" : [ + { "name" : "compare" } + ] + } +] diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index dc757624..64f1387e 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -151,6 +151,7 @@ def native_image( """ if shared_library: + # buildifier: disable=print print("GraalVM rules for Bazel at >0.11.x uses `native_image_shared_library`. Please migrate at your convenience.") _native_image( diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 74a9a7ec..3f9ee45c 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -226,6 +226,7 @@ def assemble_native_build_options( args, binary, classpath_depset, + modulepath_depset, direct_inputs, c_compiler_path, path_list_separator, @@ -241,6 +242,7 @@ def assemble_native_build_options( args: Args builder for the Native Image build. binary: Target output binary which will be built with Native Image. classpath_depset: Classpath dependency set. + modulepath_depset: Modular dependency set. direct_inputs: Direct inputs into the native image build (mutable). c_compiler_path: Path to the C compiler; resolved via toolchains. path_list_separator: Platform-specific path separator. @@ -318,10 +320,11 @@ def assemble_native_build_options( join_with = path_list_separator, ) + # assemble module path args.add_joined( - ctx.attr.native_features, - join_with = ",", - format_joined = "-H:Features=%s", + "--module-path", + modulepath_depset, + join_with = path_list_separator, ) # configure the build optimization mode diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index 35474ab9..c640b52f 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -58,6 +58,10 @@ _NATIVE_IMAGE_BASE_ATTRS = { providers = [[JavaInfo]], mandatory = True, ), + "module_deps": attr.label_list( + providers = [[JavaInfo]], + mandatory = False, + ), "shared_library": attr.bool( mandatory = False, default = False, @@ -195,7 +199,8 @@ def _prepare_native_image_rule_context( direct_inputs, c_compiler_path, gvm_toolchain = None, - bin_postfix = None): + bin_postfix = None, + modulepath_depset = None): """Prepare a `native-image` build context.""" out_bin_name = ctx.attr.executable_name.replace("%target%", ctx.attr.name) @@ -237,6 +242,7 @@ def _prepare_native_image_rule_context( args, binary, classpath_depset, + modulepath_depset or depset([]), direct_inputs, c_compiler_path, path_list_separator, diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index d532568d..6479d2b9 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -59,9 +59,24 @@ def _graal_binary_implementation(ctx): graal_attr = ctx.attr.native_image_tool extra_tool_deps = [] gvm_toolchain = None + + # build a suite of modular-capable dependencies + modulepath_depset = depset([]) + modular_jars = [] + if ctx.attr.module_deps and len(ctx.attr.module_deps) > 0: + modulepath_depset = depset(transitive = [ + depset(dep[JavaInfo].java_outputs) + for dep in ctx.attr.module_deps + ]) + modular_jars = modulepath_depset.to_list() + classpath_depset = depset(transitive = [ - dep[JavaInfo].transitive_runtime_jars - for dep in ctx.attr.deps + f for f in + [ + dep[JavaInfo].transitive_runtime_jars + for dep in ctx.attr.deps + ] + if f not in modular_jars ]) graal = None @@ -136,6 +151,7 @@ def _graal_binary_implementation(ctx): native_toolchain.c_compiler_path, gvm_toolchain, bin_postfix = bin_postfix, + modulepath_depset = modulepath_depset, ) binary = all_outputs[0] execution_env = _prepare_execution_env( From 442935d605ef19f95ecad3502cb3ff87dfa42514 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:52:32 -0800 Subject: [PATCH 29/41] chore: build locally with strict java deps Signed-off-by: Sam Gammon --- tools/bazel/labs.bazelrc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/bazel/labs.bazelrc b/tools/bazel/labs.bazelrc index 98498faa..051b936c 100644 --- a/tools/bazel/labs.bazelrc +++ b/tools/bazel/labs.bazelrc @@ -8,7 +8,5 @@ build:labs --incompatible_strict_action_env build:labs --dynamic_local_strategy=worker,sandboxed,standalone build:labs --spawn_strategy=worker,sandboxed,local -build:labs-sandbox --experimental_use_sandboxfs=auto - -build:labs-broken --experimental_strict_java_deps=error +build:labs --experimental_strict_java_deps=error build:labs-broken --experimental_worker_strict_flagfiles From db9f53046a8b1bf6142574f7405a352b11a9c934 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:52:52 -0800 Subject: [PATCH 30/41] chore: add local example for `shared` library use Signed-off-by: Sam Gammon --- example/shared/BUILD.bazel | 45 ++++++++++++++++++++++++++++++++++ example/shared/Main.java | 5 ++++ example/shared/reflection.json | 30 +++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 example/shared/BUILD.bazel create mode 100644 example/shared/Main.java create mode 100644 example/shared/reflection.json diff --git a/example/shared/BUILD.bazel b/example/shared/BUILD.bazel new file mode 100644 index 00000000..44729274 --- /dev/null +++ b/example/shared/BUILD.bazel @@ -0,0 +1,45 @@ +load( + "@rules_graalvm//graalvm:defs.bzl", + "native_image_shared_library", +) +load( + "@rules_java//java:defs.bzl", + "java_binary", + "java_library", +) + +package(default_visibility = [ + "//tests:__subpackages__", +]) + + +filegroup( + name = "reflection-config", + srcs = ["reflection.json"], +) + +java_library( + name = "java", + srcs = ["Main.java"], +) + +java_binary( + name = "main", + main_class = "Main", + runtime_deps = [ + ":java", + ], +) + +native_image_shared_library( + name = "mylib", + deps = [":java"], + strict = True, + executable_name = "mylib", + reflection_configuration = ":reflection-config", +) + +alias( + name = "shared", + actual = "mylib", +) diff --git a/example/shared/Main.java b/example/shared/Main.java new file mode 100644 index 00000000..c9824efb --- /dev/null +++ b/example/shared/Main.java @@ -0,0 +1,5 @@ +public class Main { + public static void main(String args[]) { + System.out.println("Hello, GraalVM!"); + } +} \ No newline at end of file diff --git a/example/shared/reflection.json b/example/shared/reflection.json new file mode 100644 index 00000000..2ef1801f --- /dev/null +++ b/example/shared/reflection.json @@ -0,0 +1,30 @@ +[ + { + "name" : "java.lang.Class", + "allDeclaredConstructors" : true, + "allPublicConstructors" : true, + "allDeclaredMethods" : true, + "allPublicMethods" : true, + "allDeclaredClasses" : true, + "allPublicClasses" : true + }, + { + "name" : "java.lang.String", + "fields" : [ + { "name" : "value", "allowWrite" : true }, + { "name" : "hash" } + ], + "methods" : [ + { "name" : "", "parameterTypes" : [] }, + { "name" : "", "parameterTypes" : ["char[]"] }, + { "name" : "charAt" }, + { "name" : "format", "parameterTypes" : ["java.lang.String", "java.lang.Object[]"] } + ] + }, + { + "name" : "java.lang.String$CaseInsensitiveComparator", + "methods" : [ + { "name" : "compare" } + ] + } +] From b9ce2c0b95e489ef6f669cc3fd6f6f1e9a3a1dfd Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:53:07 -0800 Subject: [PATCH 31/41] fix: `native` example reflection config Signed-off-by: Sam Gammon --- example/native/BUILD.bazel | 7 +++++++ example/native/{reflection.cfg => reflection.json} | 0 2 files changed, 7 insertions(+) rename example/native/{reflection.cfg => reflection.json} (100%) diff --git a/example/native/BUILD.bazel b/example/native/BUILD.bazel index 957770f7..966c46d9 100644 --- a/example/native/BUILD.bazel +++ b/example/native/BUILD.bazel @@ -12,6 +12,12 @@ package(default_visibility = [ "//tests:__subpackages__", ]) + +filegroup( + name = "reflection-config", + srcs = ["reflection.json"], +) + java_library( name = "java", srcs = ["Main.java"], @@ -30,6 +36,7 @@ native_image( main_class = "Main", deps = [":java"], strict = True, + reflection_configuration = ":reflection-config", ) alias( diff --git a/example/native/reflection.cfg b/example/native/reflection.json similarity index 100% rename from example/native/reflection.cfg rename to example/native/reflection.json From 1e79b60e6e8df38c318aa64da2033e4d798e8c3a Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 20:53:20 -0800 Subject: [PATCH 32/41] fix: don't append `-bin` suffix to shared libs Signed-off-by: Sam Gammon --- graalvm/nativeimage/rules.bzl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index 64f1387e..56329eb2 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -36,6 +36,10 @@ _EXEUCTABLE_NAME_CONDITION = select({ "//conditions:default": "%target%-bin", }) +_SHARED_LIB_NAME_CONDITION = select({ + "//conditions:default": "%target%", +}) + _modern_rule_attrs = { "native_image_tool": attr.label( cfg = "exec", @@ -185,7 +189,7 @@ def native_image( def native_image_shared_library( name, deps, - executable_name = _EXEUCTABLE_NAME_CONDITION, + executable_name = _SHARED_LIB_NAME_CONDITION, include_resources = None, reflection_configuration = None, jni_configuration = None, From a186a27059c336026eb442c6919c4d8d84471180 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 21:26:09 -0800 Subject: [PATCH 33/41] chore: add `third_party` target for `jacoco` Relates-To: sgammon/rules_graalvm#220 Relates-To: bazelbuild/bazel#12714 Signed-off-by: Sam Gammon --- maven_install.json | 2 +- third_party/BUILD.bazel | 0 third_party/jacoco/BUILD.bazel | 13 +++++++++++++ third_party/jacoco/org.jacoco.core-0.8.9.jar | Bin 0 -> 204367 bytes 4 files changed, 14 insertions(+), 1 deletion(-) mode change 100644 => 100755 maven_install.json create mode 100644 third_party/BUILD.bazel create mode 100644 third_party/jacoco/BUILD.bazel create mode 100644 third_party/jacoco/org.jacoco.core-0.8.9.jar diff --git a/maven_install.json b/maven_install.json old mode 100644 new mode 100755 index b83ffb4c..e18f863f --- a/maven_install.json +++ b/maven_install.json @@ -1,6 +1,6 @@ { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": -1579394223, + "__INPUT_ARTIFACTS_HASH": 1409611957, "__RESOLVED_ARTIFACTS_HASH": -1141381396, "artifacts": { "org.graalvm.compiler:compiler": { diff --git a/third_party/BUILD.bazel b/third_party/BUILD.bazel new file mode 100644 index 00000000..e69de29b diff --git a/third_party/jacoco/BUILD.bazel b/third_party/jacoco/BUILD.bazel new file mode 100644 index 00000000..32e644ab --- /dev/null +++ b/third_party/jacoco/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_java//java:defs.bzl", "java_import") + +java_import( + name = "jacoco", + jars = [ + "org.jacoco.core-0.8.9.jar", + "org.jacoco.agent-0.8.9.jar", + "org.jacoco.agent-0.8.9-runtime.jar", + ], + visibility = [ + "@//:__subpackages__", + ], +) diff --git a/third_party/jacoco/org.jacoco.core-0.8.9.jar b/third_party/jacoco/org.jacoco.core-0.8.9.jar new file mode 100644 index 0000000000000000000000000000000000000000..f223bd08d66cf655d9ffc8be288847b190fe77c5 GIT binary patch literal 204367 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 SNkCD7;av}_=jAZ$VEzxlRjq~q literal 0 HcmV?d00001 From 53686ca4fbffe8293fc1060b47c0a0710434a052 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 21:27:12 -0800 Subject: [PATCH 34/41] fix: sdk artifact coordinate Signed-off-by: Sam Gammon --- MODULE.bazel | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index c4aba1a6..4a8d9076 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -142,6 +142,7 @@ maven = use_extension( "maven", dev_dependency = True, ) + maven.artifact( name = "maven_gvm", group = "org.graalvm.nativeimage", @@ -152,17 +153,21 @@ maven.artifact( maven.artifact( name = "maven_gvm", group = "org.graalvm.sdk", - artifact= "graal_sdk", + artifact= "graal-sdk", version = GRAALVM_SDK_VERSION, neverlink = True, ) maven.artifact( name = "maven_gvm", group = "org.graalvm.polyglot", - artifact= "polyglot", + artifact = "polyglot", version = GRAALVM_SDK_VERSION, ) +STD_ARTIFACTS = [ + # Nothing additional at this time. +] + MAVEN_REPOSITORIES = [ "https://maven.pkg.st", "https://maven.google.com", @@ -171,8 +176,9 @@ MAVEN_REPOSITORIES = [ maven.install( name = "maven_gvm", - lock_file = "//:maven_install.json", repositories = MAVEN_REPOSITORIES, + lock_file = "//:maven_install.json", + artifacts = STD_ARTIFACTS, ) use_repo( maven, From 1aefe819ce93d1376e6113b952dacb98db6023d2 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sat, 13 Jan 2024 21:40:10 -0800 Subject: [PATCH 35/41] chore: update bzlmod locks Signed-off-by: Sam Gammon --- MODULE.bazel.lock | 215 +++++++++--------- .../bzlmod/MODULE.bazel.lock | 123 +--------- .../components-ce/MODULE.bazel.lock | 4 +- .../components-oracle/MODULE.bazel.lock | 4 +- .../integration_tests/inert/MODULE.bazel.lock | 2 +- .../shared-lib/MODULE.bazel.lock | 2 +- 6 files changed, 115 insertions(+), 235 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index f70c7ff5..57f7f4a2 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,6 +1,6 @@ { "lockFileVersion": 3, - "moduleFileHash": "c95fac7b8759c10d5755dc4955d5d0cfe05aed0b945acf9097a5b6aadf10eaf2", + "moduleFileHash": "ef90136b5dd3e9ad687f8d5b073ac70e5c69eeac70bb7aff5db62b9b5d47114e", "flags": { "cmdRegistries": [ "https://bcr.bazel.build/" @@ -34,7 +34,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 140, + "line": 142, "column": 22 }, "imports": { @@ -58,7 +58,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 145, + "line": 148, "column": 15 } }, @@ -67,14 +67,14 @@ "attributeValues": { "name": "maven_gvm", "group": "org.graalvm.sdk", - "artifact": "graal_sdk", + "artifact": "graal-sdk", "version": "23.1.1", "neverlink": true }, "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 152, + "line": 155, "column": 15 } }, @@ -89,7 +89,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 159, + "line": 162, "column": 15 } }, @@ -97,17 +97,18 @@ "tagName": "install", "attributeValues": { "name": "maven_gvm", - "lock_file": "//:maven_install.json", "repositories": [ "https://maven.pkg.st", "https://maven.google.com", "https://repo1.maven.org/maven2" - ] + ], + "lock_file": "//:maven_install.json", + "artifacts": [] }, "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 172, + "line": 179, "column": 14 } } @@ -121,7 +122,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 187, + "line": 195, "column": 20 }, "imports": { @@ -144,7 +145,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 192, + "line": 200, "column": 12 } } @@ -158,7 +159,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 226, + "line": 234, "column": 21 }, "imports": {}, @@ -172,7 +173,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 231, + "line": 239, "column": 15 } } @@ -186,7 +187,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 233, + "line": 241, "column": 20 }, "imports": { @@ -206,7 +207,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 238, + "line": 246, "column": 23 } } @@ -223,7 +224,6 @@ "build_bazel_apple_support": "apple_support@1.8.1", "rules_license": "rules_license@0.0.7", "rules_cc": "rules_cc@0.0.9", - "rules_jvm_external": "rules_jvm_external@5.3", "rules_python": "rules_python@0.25.0", "rules_testing": "rules_testing@0.4.0", "aspect_bazel_lib": "aspect_bazel_lib@1.34.1", @@ -232,6 +232,7 @@ "com_google_protobuf": "protobuf@21.7", "io_bazel_rules_go": "rules_go@0.41.0", "bazel_gazelle": "gazelle@0.32.0", + "rules_jvm_external": "rules_jvm_external@5.3", "io_bazel_stardoc": "stardoc@0.6.2", "bazel_skylib_gazelle_plugin": "bazel_skylib_gazelle_plugin@1.4.2", "contrib_rules_jvm": "contrib_rules_jvm@0.18.0", @@ -578,95 +579,6 @@ } } }, - "rules_jvm_external@5.3": { - "name": "rules_jvm_external", - "version": "5.3", - "key": "rules_jvm_external@5.3", - "repoName": "rules_jvm_external", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", - "extensionName": "non_module_deps", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 9, - "column": 32 - }, - "imports": { - "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": ":extensions.bzl", - "extensionName": "maven", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 16, - "column": 22 - }, - "imports": { - "rules_jvm_external_deps": "rules_jvm_external_deps" - }, - "devImports": [], - "tags": [ - { - "tagName": "install", - "attributeValues": { - "name": "rules_jvm_external_deps", - "artifacts": [ - "com.google.auth:google-auth-library-credentials:1.17.0", - "com.google.auth:google-auth-library-oauth2-http:1.17.0", - "com.google.cloud:google-cloud-core:2.18.1", - "com.google.cloud:google-cloud-storage:2.22.3", - "com.google.code.gson:gson:2.10.1", - "com.google.googlejavaformat:google-java-format:1.17.0", - "com.google.guava:guava:32.0.0-jre", - "org.apache.maven:maven-artifact:3.9.2", - "software.amazon.awssdk:s3:2.20.78" - ], - "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 18, - "column": 14 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "io_bazel_stardoc": "stardoc@0.6.2", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_jvm_external~5.3", - "urls": [ - "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" - ], - "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", - "strip_prefix": "rules_jvm_external-5.3", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, "rules_python@0.25.0": { "name": "rules_python", "version": "0.25.0", @@ -1367,6 +1279,95 @@ } } }, + "rules_jvm_external@5.3": { + "name": "rules_jvm_external", + "version": "5.3", + "key": "rules_jvm_external@5.3", + "repoName": "rules_jvm_external", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 9, + "column": 32 + }, + "imports": { + "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": ":extensions.bzl", + "extensionName": "maven", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 16, + "column": 22 + }, + "imports": { + "rules_jvm_external_deps": "rules_jvm_external_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "rules_jvm_external_deps", + "artifacts": [ + "com.google.auth:google-auth-library-credentials:1.17.0", + "com.google.auth:google-auth-library-oauth2-http:1.17.0", + "com.google.cloud:google-cloud-core:2.18.1", + "com.google.cloud:google-cloud-storage:2.22.3", + "com.google.code.gson:gson:2.10.1", + "com.google.googlejavaformat:google-java-format:1.17.0", + "com.google.guava:guava:32.0.0-jre", + "org.apache.maven:maven-artifact:3.9.2", + "software.amazon.awssdk:s3:2.20.78" + ], + "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 18, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "io_bazel_stardoc": "stardoc@0.6.2", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_jvm_external~5.3", + "urls": [ + "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" + ], + "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", + "strip_prefix": "rules_jvm_external-5.3", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, "stardoc@0.6.2": { "name": "stardoc", "version": "0.6.2", @@ -4687,7 +4688,7 @@ ], "artifacts": [ "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\", \"neverlink\": true }", - "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal_sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", + "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal-sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }" ], "fail_on_missing_checksum": true, @@ -4790,7 +4791,7 @@ ], "artifacts": [ "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\", \"neverlink\": true }", - "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal_sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", + "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal-sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }" ], "fetch_sources": true, diff --git a/example/integration_tests/bzlmod/MODULE.bazel.lock b/example/integration_tests/bzlmod/MODULE.bazel.lock index d92910d2..a256ae6f 100644 --- a/example/integration_tests/bzlmod/MODULE.bazel.lock +++ b/example/integration_tests/bzlmod/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "170782bb5188a142bef3bfce5e814b429c4c6c50bc64562672986382dfa22855" + "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" }, "moduleDepGraph": { "": { @@ -182,7 +182,6 @@ "platforms": "platforms@0.0.7", "bazel_features": "bazel_features@1.0.0", "rules_java": "rules_java@7.1.0", - "rules_jvm_external": "rules_jvm_external@5.3", "bazel_skylib": "bazel_skylib@1.5.0", "build_bazel_apple_support": "apple_support@1.8.1", "bazel_tools": "bazel_tools@_", @@ -551,95 +550,6 @@ } } }, - "rules_jvm_external@5.3": { - "name": "rules_jvm_external", - "version": "5.3", - "key": "rules_jvm_external@5.3", - "repoName": "rules_jvm_external", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", - "extensionName": "non_module_deps", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 9, - "column": 32 - }, - "imports": { - "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": ":extensions.bzl", - "extensionName": "maven", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 16, - "column": 22 - }, - "imports": { - "rules_jvm_external_deps": "rules_jvm_external_deps" - }, - "devImports": [], - "tags": [ - { - "tagName": "install", - "attributeValues": { - "name": "rules_jvm_external_deps", - "artifacts": [ - "com.google.auth:google-auth-library-credentials:1.17.0", - "com.google.auth:google-auth-library-oauth2-http:1.17.0", - "com.google.cloud:google-cloud-core:2.18.1", - "com.google.cloud:google-cloud-storage:2.22.3", - "com.google.code.gson:gson:2.10.1", - "com.google.googlejavaformat:google-java-format:1.17.0", - "com.google.guava:guava:32.0.0-jre", - "org.apache.maven:maven-artifact:3.9.2", - "software.amazon.awssdk:s3:2.20.78" - ], - "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 18, - "column": 14 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "io_bazel_stardoc": "stardoc@0.5.3", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_jvm_external~5.3", - "urls": [ - "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" - ], - "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", - "strip_prefix": "rules_jvm_external-5.3", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, "apple_support@1.8.1": { "name": "apple_support", "version": "1.8.1", @@ -816,37 +726,6 @@ "remote_patch_strip": 0 } } - }, - "stardoc@0.5.3": { - "name": "stardoc", - "version": "0.5.3", - "key": "stardoc@0.5.3", - "repoName": "stardoc", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "rules_java": "rules_java@7.1.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "stardoc~0.5.3", - "urls": [ - "https://github.com/bazelbuild/stardoc/releases/download/0.5.3/stardoc-0.5.3.tar.gz" - ], - "integrity": "sha256-P9j+xN3sPGcL2BCQTi4zFwvt/hL5Ct+UNQgYS+RYyLs=", - "strip_prefix": "", - "remote_patches": { - "https://bcr.bazel.build/modules/stardoc/0.5.3/patches/module_dot_bazel.patch": "sha256-Lgpy9OCr0zBWYuHoyM1rJJrgxn23X/bwgICEF7XiEug=" - }, - "remote_patch_strip": 0 - } - } } }, "moduleExtensions": { diff --git a/example/integration_tests/components-ce/MODULE.bazel.lock b/example/integration_tests/components-ce/MODULE.bazel.lock index bff4727d..a2e48a65 100644 --- a/example/integration_tests/components-ce/MODULE.bazel.lock +++ b/example/integration_tests/components-ce/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "fa50be8381e0ebb2e2dd9fbb5eeff1495406335c7141ccc5d5d24800f8374789" + "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" }, "moduleDepGraph": { "": { @@ -814,7 +814,7 @@ }, "@@rules_graalvm~override//:extensions.bzl%graalvm": { "general": { - "bzlTransitiveDigest": "PkyvavvK5e4FjXXNmFAYYcGB6FofYxEbQwP3Uuc8TR4=", + "bzlTransitiveDigest": "mRzSuTlbQlQ0snbnMM3X7itZ8Eh1p7TKee6l6JsBWUc=", "accumulatedFileDigests": {}, "envVariables": {}, "generatedRepoSpecs": { diff --git a/example/integration_tests/components-oracle/MODULE.bazel.lock b/example/integration_tests/components-oracle/MODULE.bazel.lock index afbfee18..89e09d41 100644 --- a/example/integration_tests/components-oracle/MODULE.bazel.lock +++ b/example/integration_tests/components-oracle/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "fa50be8381e0ebb2e2dd9fbb5eeff1495406335c7141ccc5d5d24800f8374789" + "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" }, "moduleDepGraph": { "": { @@ -815,7 +815,7 @@ }, "@@rules_graalvm~override//:extensions.bzl%graalvm": { "general": { - "bzlTransitiveDigest": "PkyvavvK5e4FjXXNmFAYYcGB6FofYxEbQwP3Uuc8TR4=", + "bzlTransitiveDigest": "mRzSuTlbQlQ0snbnMM3X7itZ8Eh1p7TKee6l6JsBWUc=", "accumulatedFileDigests": {}, "envVariables": {}, "generatedRepoSpecs": { diff --git a/example/integration_tests/inert/MODULE.bazel.lock b/example/integration_tests/inert/MODULE.bazel.lock index a1910c83..678d4de6 100644 --- a/example/integration_tests/inert/MODULE.bazel.lock +++ b/example/integration_tests/inert/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "fa50be8381e0ebb2e2dd9fbb5eeff1495406335c7141ccc5d5d24800f8374789" + "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" }, "moduleDepGraph": { "": { diff --git a/example/integration_tests/shared-lib/MODULE.bazel.lock b/example/integration_tests/shared-lib/MODULE.bazel.lock index 213e2ed5..a256ae6f 100644 --- a/example/integration_tests/shared-lib/MODULE.bazel.lock +++ b/example/integration_tests/shared-lib/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "c95fac7b8759c10d5755dc4955d5d0cfe05aed0b945acf9097a5b6aadf10eaf2" + "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" }, "moduleDepGraph": { "": { From 1662194721db26aa5d04aa6e58ee018f206d0ce7 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sun, 14 Jan 2024 14:02:49 -0800 Subject: [PATCH 36/41] chore: drop old disabled tests Signed-off-by: Sam Gammon --- example/disabled_tests/bazel1/.bazelrc | 1 - example/disabled_tests/bazel1/.bazelversion | 1 - example/disabled_tests/bazel1/.gitignore | 1 - example/disabled_tests/bazel1/WORKSPACE.bazel | 29 ------------------- .../disabled_tests/bazel1/sample/BUILD.bazel | 28 ------------------ .../disabled_tests/bazel1/sample/Main.java | 5 ---- example/disabled_tests/bazel2/.bazelrc | 1 - example/disabled_tests/bazel2/.bazelversion | 1 - example/disabled_tests/bazel2/.gitignore | 1 - example/disabled_tests/bazel2/WORKSPACE.bazel | 29 ------------------- .../disabled_tests/bazel2/sample/BUILD.bazel | 28 ------------------ .../disabled_tests/bazel2/sample/Main.java | 5 ---- example/disabled_tests/bazel3/.bazelrc | 1 - example/disabled_tests/bazel3/.bazelversion | 1 - example/disabled_tests/bazel3/.gitignore | 1 - example/disabled_tests/bazel3/WORKSPACE.bazel | 29 ------------------- .../disabled_tests/bazel3/sample/BUILD.bazel | 28 ------------------ .../disabled_tests/bazel3/sample/Main.java | 5 ---- 18 files changed, 195 deletions(-) delete mode 100644 example/disabled_tests/bazel1/.bazelrc delete mode 100644 example/disabled_tests/bazel1/.bazelversion delete mode 100644 example/disabled_tests/bazel1/.gitignore delete mode 100644 example/disabled_tests/bazel1/WORKSPACE.bazel delete mode 100644 example/disabled_tests/bazel1/sample/BUILD.bazel delete mode 100644 example/disabled_tests/bazel1/sample/Main.java delete mode 100644 example/disabled_tests/bazel2/.bazelrc delete mode 100644 example/disabled_tests/bazel2/.bazelversion delete mode 100644 example/disabled_tests/bazel2/.gitignore delete mode 100644 example/disabled_tests/bazel2/WORKSPACE.bazel delete mode 100644 example/disabled_tests/bazel2/sample/BUILD.bazel delete mode 100644 example/disabled_tests/bazel2/sample/Main.java delete mode 100644 example/disabled_tests/bazel3/.bazelrc delete mode 100644 example/disabled_tests/bazel3/.bazelversion delete mode 100644 example/disabled_tests/bazel3/.gitignore delete mode 100644 example/disabled_tests/bazel3/WORKSPACE.bazel delete mode 100644 example/disabled_tests/bazel3/sample/BUILD.bazel delete mode 100644 example/disabled_tests/bazel3/sample/Main.java diff --git a/example/disabled_tests/bazel1/.bazelrc b/example/disabled_tests/bazel1/.bazelrc deleted file mode 100644 index 9e69f75e..00000000 --- a/example/disabled_tests/bazel1/.bazelrc +++ /dev/null @@ -1 +0,0 @@ -# Nothing at this time. \ No newline at end of file diff --git a/example/disabled_tests/bazel1/.bazelversion b/example/disabled_tests/bazel1/.bazelversion deleted file mode 100644 index 6085e946..00000000 --- a/example/disabled_tests/bazel1/.bazelversion +++ /dev/null @@ -1 +0,0 @@ -1.2.1 diff --git a/example/disabled_tests/bazel1/.gitignore b/example/disabled_tests/bazel1/.gitignore deleted file mode 100644 index ac51a054..00000000 --- a/example/disabled_tests/bazel1/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bazel-* diff --git a/example/disabled_tests/bazel1/WORKSPACE.bazel b/example/disabled_tests/bazel1/WORKSPACE.bazel deleted file mode 100644 index 48695d76..00000000 --- a/example/disabled_tests/bazel1/WORKSPACE.bazel +++ /dev/null @@ -1,29 +0,0 @@ -workspace(name = "rules_graalvm_sample") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -local_repository( - name = "rules_graalvm", - path = "../../..", -) - -http_archive( - name = "rules_java", - sha256 = "34b41ec683e67253043ab1a3d1e8b7c61e4e8edefbcad485381328c934d072fe", - url = "https://github.com/bazelbuild/rules_java/releases/download/4.0.0/rules_java-4.0.0.tar.gz", -) - -load("@rules_graalvm//graalvm:workspace.bzl", "register_graalvm_toolchains", "rules_graalvm_repositories") - -rules_graalvm_repositories(omit_rules_java = True) - -register_graalvm_toolchains() - -load("@rules_graalvm//graalvm:repositories.bzl", "graalvm_repository") - -graalvm_repository( - name = "graalvm", - distribution = "ce", - java_version = "20", - version = "20.0.2", -) diff --git a/example/disabled_tests/bazel1/sample/BUILD.bazel b/example/disabled_tests/bazel1/sample/BUILD.bazel deleted file mode 100644 index fbb24b47..00000000 --- a/example/disabled_tests/bazel1/sample/BUILD.bazel +++ /dev/null @@ -1,28 +0,0 @@ -load( - "@rules_graalvm//graal:graal.bzl", - "native_image", -) - -java_library( - name = "java", - srcs = ["Main.java"], -) - -java_binary( - name = "main", - main_class = "Main", - runtime_deps = [ - ":java", - ], -) - -native_image( - name = "main-native", - main_class = "Main", - deps = [":java"], -) - -alias( - name = "sample", - actual = "main-native", -) diff --git a/example/disabled_tests/bazel1/sample/Main.java b/example/disabled_tests/bazel1/sample/Main.java deleted file mode 100644 index c9824efb..00000000 --- a/example/disabled_tests/bazel1/sample/Main.java +++ /dev/null @@ -1,5 +0,0 @@ -public class Main { - public static void main(String args[]) { - System.out.println("Hello, GraalVM!"); - } -} \ No newline at end of file diff --git a/example/disabled_tests/bazel2/.bazelrc b/example/disabled_tests/bazel2/.bazelrc deleted file mode 100644 index 9e69f75e..00000000 --- a/example/disabled_tests/bazel2/.bazelrc +++ /dev/null @@ -1 +0,0 @@ -# Nothing at this time. \ No newline at end of file diff --git a/example/disabled_tests/bazel2/.bazelversion b/example/disabled_tests/bazel2/.bazelversion deleted file mode 100644 index ccbccc3d..00000000 --- a/example/disabled_tests/bazel2/.bazelversion +++ /dev/null @@ -1 +0,0 @@ -2.2.0 diff --git a/example/disabled_tests/bazel2/.gitignore b/example/disabled_tests/bazel2/.gitignore deleted file mode 100644 index ac51a054..00000000 --- a/example/disabled_tests/bazel2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bazel-* diff --git a/example/disabled_tests/bazel2/WORKSPACE.bazel b/example/disabled_tests/bazel2/WORKSPACE.bazel deleted file mode 100644 index 48695d76..00000000 --- a/example/disabled_tests/bazel2/WORKSPACE.bazel +++ /dev/null @@ -1,29 +0,0 @@ -workspace(name = "rules_graalvm_sample") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -local_repository( - name = "rules_graalvm", - path = "../../..", -) - -http_archive( - name = "rules_java", - sha256 = "34b41ec683e67253043ab1a3d1e8b7c61e4e8edefbcad485381328c934d072fe", - url = "https://github.com/bazelbuild/rules_java/releases/download/4.0.0/rules_java-4.0.0.tar.gz", -) - -load("@rules_graalvm//graalvm:workspace.bzl", "register_graalvm_toolchains", "rules_graalvm_repositories") - -rules_graalvm_repositories(omit_rules_java = True) - -register_graalvm_toolchains() - -load("@rules_graalvm//graalvm:repositories.bzl", "graalvm_repository") - -graalvm_repository( - name = "graalvm", - distribution = "ce", - java_version = "20", - version = "20.0.2", -) diff --git a/example/disabled_tests/bazel2/sample/BUILD.bazel b/example/disabled_tests/bazel2/sample/BUILD.bazel deleted file mode 100644 index fbb24b47..00000000 --- a/example/disabled_tests/bazel2/sample/BUILD.bazel +++ /dev/null @@ -1,28 +0,0 @@ -load( - "@rules_graalvm//graal:graal.bzl", - "native_image", -) - -java_library( - name = "java", - srcs = ["Main.java"], -) - -java_binary( - name = "main", - main_class = "Main", - runtime_deps = [ - ":java", - ], -) - -native_image( - name = "main-native", - main_class = "Main", - deps = [":java"], -) - -alias( - name = "sample", - actual = "main-native", -) diff --git a/example/disabled_tests/bazel2/sample/Main.java b/example/disabled_tests/bazel2/sample/Main.java deleted file mode 100644 index c9824efb..00000000 --- a/example/disabled_tests/bazel2/sample/Main.java +++ /dev/null @@ -1,5 +0,0 @@ -public class Main { - public static void main(String args[]) { - System.out.println("Hello, GraalVM!"); - } -} \ No newline at end of file diff --git a/example/disabled_tests/bazel3/.bazelrc b/example/disabled_tests/bazel3/.bazelrc deleted file mode 100644 index 9e69f75e..00000000 --- a/example/disabled_tests/bazel3/.bazelrc +++ /dev/null @@ -1 +0,0 @@ -# Nothing at this time. \ No newline at end of file diff --git a/example/disabled_tests/bazel3/.bazelversion b/example/disabled_tests/bazel3/.bazelversion deleted file mode 100644 index 47b6be3f..00000000 --- a/example/disabled_tests/bazel3/.bazelversion +++ /dev/null @@ -1 +0,0 @@ -3.7.2 \ No newline at end of file diff --git a/example/disabled_tests/bazel3/.gitignore b/example/disabled_tests/bazel3/.gitignore deleted file mode 100644 index ac51a054..00000000 --- a/example/disabled_tests/bazel3/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bazel-* diff --git a/example/disabled_tests/bazel3/WORKSPACE.bazel b/example/disabled_tests/bazel3/WORKSPACE.bazel deleted file mode 100644 index 48695d76..00000000 --- a/example/disabled_tests/bazel3/WORKSPACE.bazel +++ /dev/null @@ -1,29 +0,0 @@ -workspace(name = "rules_graalvm_sample") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -local_repository( - name = "rules_graalvm", - path = "../../..", -) - -http_archive( - name = "rules_java", - sha256 = "34b41ec683e67253043ab1a3d1e8b7c61e4e8edefbcad485381328c934d072fe", - url = "https://github.com/bazelbuild/rules_java/releases/download/4.0.0/rules_java-4.0.0.tar.gz", -) - -load("@rules_graalvm//graalvm:workspace.bzl", "register_graalvm_toolchains", "rules_graalvm_repositories") - -rules_graalvm_repositories(omit_rules_java = True) - -register_graalvm_toolchains() - -load("@rules_graalvm//graalvm:repositories.bzl", "graalvm_repository") - -graalvm_repository( - name = "graalvm", - distribution = "ce", - java_version = "20", - version = "20.0.2", -) diff --git a/example/disabled_tests/bazel3/sample/BUILD.bazel b/example/disabled_tests/bazel3/sample/BUILD.bazel deleted file mode 100644 index fbb24b47..00000000 --- a/example/disabled_tests/bazel3/sample/BUILD.bazel +++ /dev/null @@ -1,28 +0,0 @@ -load( - "@rules_graalvm//graal:graal.bzl", - "native_image", -) - -java_library( - name = "java", - srcs = ["Main.java"], -) - -java_binary( - name = "main", - main_class = "Main", - runtime_deps = [ - ":java", - ], -) - -native_image( - name = "main-native", - main_class = "Main", - deps = [":java"], -) - -alias( - name = "sample", - actual = "main-native", -) diff --git a/example/disabled_tests/bazel3/sample/Main.java b/example/disabled_tests/bazel3/sample/Main.java deleted file mode 100644 index c9824efb..00000000 --- a/example/disabled_tests/bazel3/sample/Main.java +++ /dev/null @@ -1,5 +0,0 @@ -public class Main { - public static void main(String args[]) { - System.out.println("Hello, GraalVM!"); - } -} \ No newline at end of file From 2dcad3f53c93b0117e288c647b44c1aa3b8af464 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sun, 14 Jan 2024 14:03:41 -0800 Subject: [PATCH 37/41] chore: add `nativeimage` artifact Signed-off-by: Sam Gammon --- graalvm/artifacts/maven.bzl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/graalvm/artifacts/maven.bzl b/graalvm/artifacts/maven.bzl index 9d65c2e0..def1ae67 100644 --- a/graalvm/artifacts/maven.bzl +++ b/graalvm/artifacts/maven.bzl @@ -13,6 +13,11 @@ _MavenArtifacts = struct( artifact = "graal-sdk", group = "org.graalvm.sdk", options = {"neverlink": True}, + NATIVEIMAGE = struct( + artifact = "nativeimage", + group = "org.graalvm.sdk", + options = {"neverlink": True}, + ) ), POLYGLOT = struct( artifact = "polyglot", From 81881604d33a4039f7829e638c9190c6b29a7b63 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sun, 14 Jan 2024 14:05:15 -0800 Subject: [PATCH 38/41] chore: adopt new attr structure in macro entrypoints Signed-off-by: Sam Gammon --- graalvm/nativeimage/rules.bzl | 46 +++++++++++++++-- internal/native_image/builder.bzl | 32 +++++++----- internal/native_image/common.bzl | 84 ++++++++++++++++++++++++++----- internal/native_image/rules.bzl | 2 +- 4 files changed, 135 insertions(+), 29 deletions(-) diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index 56329eb2..1fb580a8 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -98,7 +98,15 @@ def native_image( executable_name = _EXEUCTABLE_NAME_CONDITION, include_resources = None, reflection_configuration = None, + reflection_configurations = [], jni_configuration = None, + jni_configurations = [], + resource_configuration = None, + resource_configurations = [], + proxy_configuration = None, + proxy_configurations = [], + serialization_configuration = None, + serialization_configurations = [], initialize_at_build_time = [], initialize_at_run_time = [], native_features = [], @@ -127,7 +135,15 @@ def native_image( The special string `%target%`, if present, is replaced with `name`. include_resources: Glob to pass to `IncludeResources`. No default; optional. reflection_configuration: Reflection configuration file. No default; optional. + reflection_configurations: Reflection configuration file. No default; optional. jni_configuration: JNI configuration file. No default; optional. + jni_configurations: Multiple JNI configuration files. No default; optional. + resource_configuration: Configuration file for embedded resources. No default; optional. + resource_configurations: Configuration files for embedded resources. No default; optional. + proxy_configuration: Configuration file for Java class proxies. No default; optional. + proxy_configurations: Configuration files for Java class proxies. No default; optional. + serialization_configuration: Configuration file for Java class proxies. No default; optional. + serialization_configurations: Configuration files for Java class proxies. No default; optional. initialize_at_build_time: Classes or patterns to pass to `--initialize-at-build-time`. No default; optional. initialize_at_run_time: Classes or patterns to pass to `--initialize-at-run-time`. No default; optional. native_features: GraalVM `Feature` classes to include and apply. No default; optional. @@ -189,10 +205,18 @@ def native_image( def native_image_shared_library( name, deps, - executable_name = _SHARED_LIB_NAME_CONDITION, + lib_name = _SHARED_LIB_NAME_CONDITION, include_resources = None, reflection_configuration = None, + reflection_configurations = [], jni_configuration = None, + jni_configurations = [], + resource_configuration = None, + resource_configurations = [], + proxy_configuration = None, + proxy_configurations = [], + serialization_configuration = None, + serialization_configurations = [], initialize_at_build_time = [], initialize_at_run_time = [], native_features = [], @@ -216,11 +240,19 @@ def native_image_shared_library( Args: name: Name of the target; required. deps: Dependency `java_library` targets to assemble the classpath from. Mandatory. - executable_name: Set the name of the output binary; defaults to `%target%-bin`, or `%target%-bin.exe` on Windows. + lib_name: Set the name of the output library binary; defaults to `%target%`. The special string `%target%`, if present, is replaced with `name`. include_resources: Glob to pass to `IncludeResources`. No default; optional. reflection_configuration: Reflection configuration file. No default; optional. + reflection_configurations: Reflection configuration file. No default; optional. jni_configuration: JNI configuration file. No default; optional. + jni_configurations: Multiple JNI configuration files. No default; optional. + resource_configuration: Configuration file for embedded resources. No default; optional. + resource_configurations: Configuration files for embedded resources. No default; optional. + proxy_configuration: Configuration file for Java class proxies. No default; optional. + proxy_configurations: Configuration files for Java class proxies. No default; optional. + serialization_configuration: Configuration file for Java class proxies. No default; optional. + serialization_configurations: Configuration files for Java class proxies. No default; optional. initialize_at_build_time: Classes or patterns to pass to `--initialize-at-build-time`. No default; optional. initialize_at_run_time: Classes or patterns to pass to `--initialize-at-run-time`. No default; optional. native_features: GraalVM `Feature` classes to include and apply. No default; optional. @@ -252,7 +284,15 @@ def native_image_shared_library( deps = deps, include_resources = include_resources, reflection_configuration = reflection_configuration, + reflection_configurations = reflection_configurations, jni_configuration = jni_configuration, + jni_configurations = jni_configurations, + resource_configuration = resource_configuration, + resource_configurations = resource_configurations, + proxy_configuration = proxy_configuration, + proxy_configurations = proxy_configurations, + serialization_configuration = serialization_configuration, + serialization_configurations = serialization_configurations, initialize_at_build_time = initialize_at_build_time, initialize_at_run_time = initialize_at_run_time, native_features = native_features, @@ -265,7 +305,7 @@ def native_image_shared_library( static_zlib = static_zlib, c_compiler_option = c_compiler_option, allow_fallback = allow_fallback, - executable_name = executable_name, + lib_name = lib_name, native_image_tool = native_image_tool, native_image_settings = native_image_settings, profiles = profiles, diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 3f9ee45c..72324ff4 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -210,16 +210,19 @@ def _configure_native_compiler(ctx, args, c_compiler_path, gvm_toolchain): format_each = "-H:CCompilerOption=%s", ) -def _configure_native_test_flags(ctx, args): - """Configure native testing flags; only applies if we are building a test-only target. +def _configure_gvm_features(args, features = []): + """Format and add arguments for GraalVM feature classes. Args: - ctx: Context of the Native Image rule implementation. - args: Args builder for the Native Image build. + args: Args we're adding to. + features: Additional features to inject. """ - if ctx.attr.coverage: - args.add("--tool:coverage") + args.add_joined( + features, + join_with = ",", + format_joined = "--features=%s", + ) def assemble_native_build_options( ctx, @@ -231,7 +234,9 @@ def assemble_native_build_options( c_compiler_path, path_list_separator, gvm_toolchain = None, - bin_postfix = None): + bin_postfix = None, + injected_features = [], + injected_args = []): """Assemble the effective arguments to `native-image`. This function is responsible for converting the current rule invocation context into a set of arguments @@ -248,6 +253,8 @@ def assemble_native_build_options( path_list_separator: Platform-specific path separator. gvm_toolchain: Resolved GraalVM toolchain, or `None` if a tool target is in use via legacy rules. bin_postfix: Binary postfix expected from the output file (for example, `.exe` or `.dylib`). + injected_features: Additional feature classes to add to the compile invocation. + injected_args: Additional arguments to inject into the compile invocation. Returns: Tempdir path where the native build should occur. @@ -361,12 +368,11 @@ def assemble_native_build_options( ) direct_inputs.extend(ctx.files.profiles) - # add test-related flags, if this is a `testonly` target - if ctx.attr.testonly: - _configure_native_test_flags( - ctx, - args, - ) + # configure feature classes + _configure_gvm_features(args, injected_features) + + # add injected args before user args, so that `extra_args` has a chance to override these. + args.add_all(injected_args) # append extra arguments last if len(ctx.attr.extra_args) > 0: diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index c640b52f..c51a65f0 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -56,7 +56,7 @@ _OUTPUT_GROUPS = struct( _NATIVE_IMAGE_BASE_ATTRS = { "deps": attr.label_list( providers = [[JavaInfo]], - mandatory = True, + mandatory = False, ), "module_deps": attr.label_list( providers = [[JavaInfo]], @@ -94,6 +94,20 @@ _NATIVE_IMAGE_BASE_ATTRS = { "resource_configurations": attr.label_list( mandatory = False, ), + "proxy_configuration": attr.label( + mandatory = False, + allow_single_file = True, + ), + "proxy_configurations": attr.label_list( + mandatory = False, + ), + "serialization_configuration": attr.label( + mandatory = False, + allow_single_file = True, + ), + "serialization_configurations": attr.label_list( + mandatory = False, + ), "debug": attr.bool( mandatory = False, default = False, @@ -121,6 +135,9 @@ _NATIVE_IMAGE_BASE_ATTRS = { "initialize_at_run_time": attr.string_list( mandatory = False, ), + "initialize_rerun_at_runtime": attr.string_list( + mandatory = False, + ), "native_features": attr.string_list( mandatory = False, ), @@ -139,14 +156,10 @@ _NATIVE_IMAGE_BASE_ATTRS = { "c_compiler_option": attr.string_list( mandatory = False, ), - "executable_name": attr.string( - mandatory = True, - ), "profiles": attr.label_list( allow_files = True, mandatory = False, ), - "out_headers": attr.output_list(), "additional_outputs": attr.output_list(), "default_outputs": attr.bool( default = True, @@ -172,16 +185,54 @@ _NATIVE_IMAGE_BASE_ATTRS = { } _NATIVE_IMAGE_BIN_ATTRS = dicts.add(_NATIVE_IMAGE_BASE_ATTRS, **{ + "deps": attr.label_list( + providers = [[JavaInfo]], + mandatory = True, + ), + "main_class": attr.string( + mandatory = True, + ), + "main_module": attr.string( + mandatory = False, + ), + "executable_name": attr.string( + mandatory = True, + ), +}) + +_NATIVE_IMAGE_TEST_ATTRS = dicts.add(_NATIVE_IMAGE_BASE_ATTRS, **{ + "tests": attr.label_list( + providers = [[JavaInfo]], + mandatory = True, + ), "main_class": attr.string( mandatory = False, ), "main_module": attr.string( mandatory = False, ), + "discovery": attr.bool( + default = True, + ), + "executable_name": attr.string( + mandatory = True, + ), + "_is_test": attr.bool( + default = True, + ), }) _NATIVE_IMAGE_SHAREDLIB_ATTRS = dicts.add(_NATIVE_IMAGE_BASE_ATTRS, **{ - # Nothing at this time. + "deps": attr.label_list( + providers = [[JavaInfo]], + mandatory = True, + ), + "out_headers": attr.output_list( + # Emitted headers. + ), + "lib_name": attr.string( + # Shared library name. + ), }) def _prepare_bin_name( @@ -200,10 +251,17 @@ def _prepare_native_image_rule_context( c_compiler_path, gvm_toolchain = None, bin_postfix = None, - modulepath_depset = None): + modulepath_depset = None, + injected_features = [], + injected_args = []): """Prepare a `native-image` build context.""" - out_bin_name = ctx.attr.executable_name.replace("%target%", ctx.attr.name) + out_bin_name = None + if ctx.attr.shared_library: + out_bin_name = ctx.attr.lib_name.replace("%target%", ctx.attr.name) + else: + out_bin_name = ctx.attr.executable_name.replace("%target%", ctx.attr.name) + binary = ctx.actions.declare_file(_prepare_bin_name(out_bin_name, bin_postfix)) additional_outputs = [] @@ -224,14 +282,14 @@ def _prepare_native_image_rule_context( additional_outputs.append(_GRAALVM_ISOLATE_HEADER) additional_outputs.append(_GRAALVM_ISOLATE_DYNAMIC_HEADER) + # append all out headers + if len(ctx.attr.out_headers) > 0: + outputs.extend(ctx.outputs.out_headers) + # append all additional outputs if len(additional_outputs) > 0: outputs.extend([ctx.actions.declare_file(f) for f in additional_outputs]) - # append all out headers - if len(ctx.attr.out_headers) > 0: - outputs.extend(ctx.outputs.out_headers) - # append all attr additional outputs if len(ctx.attr.additional_outputs) > 0: outputs.extend(ctx.outputs.additional_outputs) @@ -248,6 +306,8 @@ def _prepare_native_image_rule_context( path_list_separator, gvm_toolchain, bin_postfix, + injected_features, + injected_args, ) # add native image tempdir to outputs if one was allocated diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 6479d2b9..004c6c2b 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -65,7 +65,7 @@ def _graal_binary_implementation(ctx): modular_jars = [] if ctx.attr.module_deps and len(ctx.attr.module_deps) > 0: modulepath_depset = depset(transitive = [ - depset(dep[JavaInfo].java_outputs) + dep.files for dep in ctx.attr.module_deps ]) modular_jars = modulepath_depset.to_list() From a5b91ccaba687526527108bf6a9a171f9aac64eb Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sun, 14 Jan 2024 14:16:18 -0800 Subject: [PATCH 39/41] feat: native junit testing - add rule and macro definition/entrypoint for test targets - rollup test targets dependencies in native image build - inject native test feature, runner as entrypoint - provide dependencies for junit5 Signed-off-by: Sam Gammon --- MODULE.bazel | 76 +++- MODULE.bazel.lock | 581 +++++++++++++++++++++++- example/shared/BUILD.bazel | 2 +- example/testing/BUILD.bazel | 50 ++ example/testing/Something.java | 11 + example/testing/SomethingTest.java | 29 ++ graalvm/defs.bzl | 2 + graalvm/nativeimage/rules.bzl | 195 +++++++- graalvm/testing/BUILD.bazel | 23 + graalvm/testing/NativeTestFeature.java | 15 + graalvm/testing/NativeTestLauncher.java | 16 + graalvm/testing/NativeTestRunner.java | 16 + graalvm/testing/defs.bzl | 21 + internal/native_image/builder.bzl | 16 + internal/native_image/common.bzl | 4 + internal/native_image/rules.bzl | 141 +++++- internal/native_image/testing.bzl | 13 + internal/testing.bzl | 21 + maven_install.json | 375 ++++++++++++++- tools/bazel/cache.bazelrc | 4 +- tools/defs/BUILD.bazel | 0 tools/defs/junit5.bzl | 50 ++ 22 files changed, 1613 insertions(+), 48 deletions(-) create mode 100644 example/testing/BUILD.bazel create mode 100644 example/testing/Something.java create mode 100644 example/testing/SomethingTest.java create mode 100644 graalvm/testing/BUILD.bazel create mode 100644 graalvm/testing/NativeTestFeature.java create mode 100644 graalvm/testing/NativeTestLauncher.java create mode 100644 graalvm/testing/NativeTestRunner.java create mode 100644 graalvm/testing/defs.bzl create mode 100644 internal/native_image/testing.bzl create mode 100644 internal/testing.bzl create mode 100644 tools/defs/BUILD.bazel create mode 100644 tools/defs/junit5.bzl diff --git a/MODULE.bazel b/MODULE.bazel index 4a8d9076..e941c2f4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,6 +17,14 @@ GRAALVM_DIST = "ce" GRAALVM_SDK_VERSION = "23.1.1" +GRAALVM_JUNIT_VERSION = "0.9.28" + +JUNIT4_VERSION = "4.12" + +JUNIT5_VERSION = "5.10.0" + +JUNIT5_PLATFORM_VERSION = "1.10.0" + ## ## Dependencies: API @@ -143,6 +151,7 @@ maven = use_extension( dev_dependency = True, ) +# GraalVM. maven.artifact( name = "maven_gvm", group = "org.graalvm.nativeimage", @@ -157,15 +166,80 @@ maven.artifact( version = GRAALVM_SDK_VERSION, neverlink = True, ) +maven.artifact( + name = "maven_gvm", + group = "org.graalvm.sdk", + artifact= "nativeimage", + version = GRAALVM_SDK_VERSION, + neverlink = True, +) maven.artifact( name = "maven_gvm", group = "org.graalvm.polyglot", artifact = "polyglot", version = GRAALVM_SDK_VERSION, ) +maven.artifact( + name = "maven_gvm", + group = "org.graalvm.polyglot", + artifact = "polyglot", + version = GRAALVM_SDK_VERSION, +) +maven.artifact( + name = "maven_gvm", + group = "org.graalvm.buildtools", + artifact = "junit-platform-native", + version = GRAALVM_JUNIT_VERSION, +) + +# JUnit 4. +maven.artifact( + name = "maven_gvm", + group = "junit", + artifact = "junit", + version = JUNIT4_VERSION, +) + +# JUnit 5. +maven.artifact( + name = "maven_gvm", + group = "org.junit.jupiter", + artifact = "junit-jupiter-api", + version = JUNIT5_VERSION, +) +maven.artifact( + name = "maven_gvm", + group = "org.junit.jupiter", + artifact = "junit-jupiter-engine", + version = JUNIT5_VERSION, +) +maven.artifact( + name = "maven_gvm", + group = "org.junit.jupiter", + artifact = "junit-jupiter-params", + version = JUNIT5_VERSION, +) +maven.artifact( + name = "maven_gvm", + group = "org.junit.platform", + artifact = "junit-platform-console", + version = JUNIT5_PLATFORM_VERSION, +) +maven.artifact( + name = "maven_gvm", + group = "org.junit.platform", + artifact = "junit-platform-commons", + version = JUNIT5_PLATFORM_VERSION, +) +maven.artifact( + name = "maven_gvm", + group = "org.junit.platform", + artifact = "junit-platform-launcher", + version = JUNIT5_PLATFORM_VERSION, +) STD_ARTIFACTS = [ - # Nothing additional at this time. + # Nothing at this time. ] MAVEN_REPOSITORIES = [ diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 57f7f4a2..f28f272f 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,6 +1,6 @@ { "lockFileVersion": 3, - "moduleFileHash": "ef90136b5dd3e9ad687f8d5b073ac70e5c69eeac70bb7aff5db62b9b5d47114e", + "moduleFileHash": "661de9433891f4824dce2a9447e4532dd15f886e3bab30ad91a3a6ed8998bbcf", "flags": { "cmdRegistries": [ "https://bcr.bazel.build/" @@ -34,7 +34,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 142, + "line": 148, "column": 22 }, "imports": { @@ -58,7 +58,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 148, + "line": 155, "column": 15 } }, @@ -74,7 +74,23 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 155, + "line": 162, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.graalvm.sdk", + "artifact": "nativeimage", + "version": "23.1.1", + "neverlink": true + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 169, "column": 15 } }, @@ -89,7 +105,142 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 162, + "line": 176, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.graalvm.polyglot", + "artifact": "polyglot", + "version": "23.1.1" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 182, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.graalvm.buildtools", + "artifact": "junit-platform-native", + "version": "0.9.28" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 188, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "junit", + "artifact": "junit", + "version": "4.12" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 196, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.junit.jupiter", + "artifact": "junit-jupiter-api", + "version": "5.10.0" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 204, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.junit.jupiter", + "artifact": "junit-jupiter-engine", + "version": "5.10.0" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 210, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.junit.jupiter", + "artifact": "junit-jupiter-params", + "version": "5.10.0" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 216, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.junit.platform", + "artifact": "junit-platform-console", + "version": "1.10.0" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 222, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.junit.platform", + "artifact": "junit-platform-commons", + "version": "1.10.0" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 228, + "column": 15 + } + }, + { + "tagName": "artifact", + "attributeValues": { + "name": "maven_gvm", + "group": "org.junit.platform", + "artifact": "junit-platform-launcher", + "version": "1.10.0" + }, + "devDependency": true, + "location": { + "file": "@@//:MODULE.bazel", + "line": 234, "column": 15 } }, @@ -108,7 +259,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 179, + "line": 251, "column": 14 } } @@ -122,7 +273,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 195, + "line": 267, "column": 20 }, "imports": { @@ -145,7 +296,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 200, + "line": 272, "column": 12 } } @@ -159,7 +310,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 234, + "line": 306, "column": 21 }, "imports": {}, @@ -173,7 +324,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 239, + "line": 311, "column": 15 } } @@ -187,7 +338,7 @@ "usingModule": "", "location": { "file": "@@//:MODULE.bazel", - "line": 241, + "line": 313, "column": 20 }, "imports": { @@ -207,7 +358,7 @@ "devDependency": true, "location": { "file": "@@//:MODULE.bazel", - "line": 246, + "line": 318, "column": 23 } } @@ -4221,7 +4372,7 @@ "general": { "bzlTransitiveDigest": "9VQBVBpk1BYX8MlZX/v6yoWpeoWbbeIDc8bZ2kiueLI=", "accumulatedFileDigests": { - "@@//:maven_install.json": "2c7a0a5389ba129060f790938b9522f9621b0b47efc5e6ef3c5b8ffaf12597a9", + "@@//:maven_install.json": "dd42cccacae1851b362f59dddedc2cf01f2ccff73e87b708346b1a484905e5f6", "@@stardoc~0.6.2//:maven_install.json": "de0bfa778b4ed6aebb77509362dd87ab8d20fc7c7c18d2a7429cdfee03949a21", "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json": "741ab2ef3843a43eaacb45d1448835c9deb99c95162279f513096eface8acd44" }, @@ -4263,6 +4414,20 @@ "downloaded_file_path": "org/graalvm/sdk/graal-sdk/23.1.1/graal-sdk-23.1.1.jar" } }, + "org_junit_platform_junit_platform_engine_jar_sources_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_engine_jar_sources_1_10_0", + "sha256": "17ac74964fcd82c57130623afe72a99105ca107fc96cb53f169b3a8c9c444c83", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0-sources.jar", + "https://maven.google.com/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0-sources.jar" + } + }, "org_junit_jupiter_junit_jupiter_engine": { "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", "ruleClassName": "compat_repository", @@ -4509,6 +4674,20 @@ "target_name": "com_google_protobuf_protobuf_java" } }, + "org_junit_jupiter_junit_jupiter_api_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_api_5_10_0", + "sha256": "108088fd7ea46a8e65a0ce7f5d75ae3ff7865606770a078715f5a6e5709e17d8", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0.jar" + } + }, "io_netty_netty_transport_native_unix_common_4_1_86_Final": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -4522,6 +4701,20 @@ "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar" } }, + "org_opentest4j_opentest4j_jar_sources_1_3_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_opentest4j_opentest4j_jar_sources_1_3_0", + "sha256": "724a24e3a68267d5ebac9411389a15638a71e50c62448ffa58f59c34d5c1ebb2", + "urls": [ + "https://maven.pkg.st/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0-sources.jar", + "https://maven.google.com/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0-sources.jar", + "https://repo1.maven.org/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0-sources.jar" + ], + "downloaded_file_path": "org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0-sources.jar" + } + }, "io_netty_netty_codec": { "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", "ruleClassName": "compat_repository", @@ -4531,6 +4724,34 @@ "target_name": "io_netty_netty_codec" } }, + "org_junit_platform_junit_platform_commons_jar_sources_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_commons_jar_sources_1_10_0", + "sha256": "ebeb653947017ad2eadc5e9f38eab56400003886d9edf6f336890906e8c905b3", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0-sources.jar", + "https://maven.google.com/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0-sources.jar" + } + }, + "org_apiguardian_apiguardian_api_jar_sources_1_1_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apiguardian_apiguardian_api_jar_sources_1_1_2", + "sha256": "277a7a4315412817beb6655b324dc7276621e95ebff00b8bf65e17a27b685e2d", + "urls": [ + "https://maven.pkg.st/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-sources.jar", + "https://maven.google.com/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-sources.jar", + "https://repo1.maven.org/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-sources.jar" + ], + "downloaded_file_path": "org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2-sources.jar" + } + }, "io_grpc_grpc_api_1_55_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -4582,6 +4803,20 @@ "downloaded_file_path": "org/ow2/asm/asm/9.1/asm-9.1.jar" } }, + "org_junit_platform_junit_platform_console_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_console_1_10_0", + "sha256": "5c43a8dccbb24781a1880ce0287e81290eb8fd23fa6800a346cec219a46b21a8", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0.jar", + "https://maven.google.com/org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0.jar" + } + }, "org_codehaus_mojo_animal_sniffer_annotations": { "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", "ruleClassName": "compat_repository", @@ -4600,6 +4835,20 @@ "target_name": "org_slf4j_slf4j_api" } }, + "org_junit_jupiter_junit_jupiter_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_5_10_0", + "sha256": "8e4bde23ee28fc443975654a7b28c410a3b78d6be96b78c99ab73695ec344f7c", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0.jar" + } + }, "com_google_api_api_common_2_11_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -4689,7 +4938,17 @@ "artifacts": [ "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\", \"neverlink\": true }", "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal-sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", - "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }" + "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"nativeimage\", \"version\": \"23.1.1\", \"neverlink\": true }", + "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }", + "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }", + "{ \"group\": \"org.graalvm.buildtools\", \"artifact\": \"junit-platform-native\", \"version\": \"0.9.28\" }", + "{ \"group\": \"junit\", \"artifact\": \"junit\", \"version\": \"4.12\" }", + "{ \"group\": \"org.junit.jupiter\", \"artifact\": \"junit-jupiter-api\", \"version\": \"5.10.0\" }", + "{ \"group\": \"org.junit.jupiter\", \"artifact\": \"junit-jupiter-engine\", \"version\": \"5.10.0\" }", + "{ \"group\": \"org.junit.jupiter\", \"artifact\": \"junit-jupiter-params\", \"version\": \"5.10.0\" }", + "{ \"group\": \"org.junit.platform\", \"artifact\": \"junit-platform-console\", \"version\": \"1.10.0\" }", + "{ \"group\": \"org.junit.platform\", \"artifact\": \"junit-platform-commons\", \"version\": \"1.10.0\" }", + "{ \"group\": \"org.junit.platform\", \"artifact\": \"junit-platform-launcher\", \"version\": \"1.10.0\" }" ], "fail_on_missing_checksum": true, "fetch_sources": true, @@ -4792,7 +5051,17 @@ "artifacts": [ "{ \"group\": \"org.graalvm.nativeimage\", \"artifact\": \"svm\", \"version\": \"23.1.1\", \"neverlink\": true }", "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"graal-sdk\", \"version\": \"23.1.1\", \"neverlink\": true }", - "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }" + "{ \"group\": \"org.graalvm.sdk\", \"artifact\": \"nativeimage\", \"version\": \"23.1.1\", \"neverlink\": true }", + "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }", + "{ \"group\": \"org.graalvm.polyglot\", \"artifact\": \"polyglot\", \"version\": \"23.1.1\" }", + "{ \"group\": \"org.graalvm.buildtools\", \"artifact\": \"junit-platform-native\", \"version\": \"0.9.28\" }", + "{ \"group\": \"junit\", \"artifact\": \"junit\", \"version\": \"4.12\" }", + "{ \"group\": \"org.junit.jupiter\", \"artifact\": \"junit-jupiter-api\", \"version\": \"5.10.0\" }", + "{ \"group\": \"org.junit.jupiter\", \"artifact\": \"junit-jupiter-engine\", \"version\": \"5.10.0\" }", + "{ \"group\": \"org.junit.jupiter\", \"artifact\": \"junit-jupiter-params\", \"version\": \"5.10.0\" }", + "{ \"group\": \"org.junit.platform\", \"artifact\": \"junit-platform-console\", \"version\": \"1.10.0\" }", + "{ \"group\": \"org.junit.platform\", \"artifact\": \"junit-platform-commons\", \"version\": \"1.10.0\" }", + "{ \"group\": \"org.junit.platform\", \"artifact\": \"junit-platform-launcher\", \"version\": \"1.10.0\" }" ], "fetch_sources": true, "fetch_javadoc": false, @@ -4926,6 +5195,20 @@ "duplicate_version_warning": "warn" } }, + "org_junit_jupiter_junit_jupiter_api_jar_sources_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_api_jar_sources_5_10_0", + "sha256": "34fbf1f58dac2db51ab44f22f547fcee185b342d046c3ac119ec00dd2ba98e75", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0-sources.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter-api/5.10.0/junit-jupiter-api-5.10.0-sources.jar" + } + }, "org_graalvm_sdk_collections_23_1_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -4966,6 +5249,20 @@ "downloaded_file_path": "com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1.jar" } }, + "junit_junit_4_12": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~junit_junit_4_12", + "sha256": "59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a", + "urls": [ + "https://maven.pkg.st/junit/junit/4.12/junit-4.12.jar", + "https://maven.google.com/junit/junit/4.12/junit-4.12.jar", + "https://repo1.maven.org/maven2/junit/junit/4.12/junit-4.12.jar" + ], + "downloaded_file_path": "junit/junit/4.12/junit-4.12.jar" + } + }, "com_google_j2objc_j2objc_annotations_1_3": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5141,6 +5438,20 @@ "downloaded_file_path": "org/graalvm/truffle/truffle-compiler/23.1.1/truffle-compiler-23.1.1.jar" } }, + "org_hamcrest_hamcrest_core_jar_sources_1_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_hamcrest_hamcrest_core_jar_sources_1_3", + "sha256": "e223d2d8fbafd66057a8848cc94222d63c3cedd652cc48eddc0ab5c39c0f84df", + "urls": [ + "https://maven.pkg.st/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar", + "https://maven.google.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar", + "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar" + ], + "downloaded_file_path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar" + } + }, "junit_junit_4_13_2": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5166,6 +5477,20 @@ "downloaded_file_path": "software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar" } }, + "org_junit_platform_junit_platform_commons_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_commons_1_10_0", + "sha256": "6083db08ca11fca1e16099d0dcfede0193d80b3762b276349d80d3da536791b2", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar", + "https://maven.google.com/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-commons/1.10.0/junit-platform-commons-1.10.0.jar" + } + }, "org_checkerframework_checker_qual_3_33_0": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5186,6 +5511,8 @@ "name": "rules_jvm_external~5.3~maven~org_hamcrest_hamcrest_core_1_3", "sha256": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", "urls": [ + "https://maven.pkg.st/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar", + "https://maven.google.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar", "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" ], "downloaded_file_path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" @@ -5302,6 +5629,20 @@ "downloaded_file_path": "software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar" } }, + "org_junit_jupiter_junit_jupiter_params_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_params_5_10_0", + "sha256": "f259a7322cce375430c2236a2dcb24d4a49d22045b723ad85af88e11704391c2", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0.jar" + } + }, "commons_cli_commons_cli": { "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", "ruleClassName": "compat_repository", @@ -5311,6 +5652,20 @@ "target_name": "commons_cli_commons_cli" } }, + "org_junit_platform_junit_platform_reporting_jar_sources_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_reporting_jar_sources_1_10_0", + "sha256": "3da58799df48f4a280f4e4ea7a92d5e97d2e357ac1b98885afc04a4445457713", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0-sources.jar", + "https://maven.google.com/org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0-sources.jar" + } + }, "io_opencensus_opencensus_contrib_http_util_0_31_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5410,6 +5765,20 @@ "downloaded_file_path": "io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar" } }, + "org_junit_platform_junit_platform_console_jar_sources_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_console_jar_sources_1_10_0", + "sha256": "31abe626be8e567e99366667a1242e2d469e3e828d40efca65017662df4f61c6", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0-sources.jar", + "https://maven.google.com/org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-console/1.10.0/junit-platform-console-1.10.0-sources.jar" + } + }, "software_amazon_awssdk_utils_2_20_78": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5646,6 +6015,20 @@ "target_name": "io_netty_netty_transport_native_unix_common" } }, + "org_junit_platform_junit_platform_reporting_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_reporting_1_10_0", + "sha256": "a0cdce1cc588fb902bdd08c7f24624ef72b131873eea09f063e6ee6ff453f654", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0.jar", + "https://maven.google.com/org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-reporting/1.10.0/junit-platform-reporting-1.10.0.jar" + } + }, "com_google_api_gax_httpjson_0_113_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5801,6 +6184,20 @@ "target_name": "com_google_auto_value_auto_value_annotations" } }, + "org_junit_jupiter_junit_jupiter_params_jar_sources_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_params_jar_sources_5_10_0", + "sha256": "7d20740d1dded4cb1de5805c3da3293b6a5e2991ad3b64539aa575c9638719dc", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0-sources.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter-params/5.10.0/junit-jupiter-params-5.10.0-sources.jar" + } + }, "com_google_api_grpc_grpc_google_cloud_storage_v2_2_22_3_alpha": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5960,6 +6357,20 @@ "target_name": "io_grpc_grpc_netty" } }, + "org_junit_platform_junit_platform_launcher_jar_sources_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_launcher_jar_sources_1_10_0", + "sha256": "f98514c156fe6a257659e2c4e964193ffc1d68df1e003d0d0470b24b9055787e", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0-sources.jar", + "https://maven.google.com/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0-sources.jar" + } + }, "io_opencensus_opencensus_api": { "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", "ruleClassName": "compat_repository", @@ -5969,6 +6380,34 @@ "target_name": "io_opencensus_opencensus_api" } }, + "org_junit_jupiter_junit_jupiter_engine_jar_sources_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_engine_jar_sources_5_10_0", + "sha256": "050476b6fa4a57db3152f52403860019a5588d480d653bc7a1df5bcc84376211", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0-sources.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0-sources.jar" + } + }, + "junit_junit_jar_sources_4_12": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~junit_junit_jar_sources_4_12", + "sha256": "9f43fea92033ad82bcad2ae44cec5c82abc9d6ee4b095cab921d11ead98bf2ff", + "urls": [ + "https://maven.pkg.st/junit/junit/4.12/junit-4.12-sources.jar", + "https://maven.google.com/junit/junit/4.12/junit-4.12-sources.jar", + "https://repo1.maven.org/maven2/junit/junit/4.12/junit-4.12-sources.jar" + ], + "downloaded_file_path": "junit/junit/4.12/junit-4.12-sources.jar" + } + }, "com_google_apis_google_api_services_storage_v1_rev20230301_2_0_0": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -5982,6 +6421,20 @@ "downloaded_file_path": "com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar" } }, + "org_junit_jupiter_junit_jupiter_jar_sources_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_jar_sources_5_10_0", + "sha256": "bd628b06b83b0d8830b53747b7f466beebca12d4808f117660ac06e47af99d1c", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0-sources.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0-sources.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0-sources.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter/5.10.0/junit-jupiter-5.10.0-sources.jar" + } + }, "org_apache_httpcomponents_httpclient_4_5_14": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -6079,6 +6532,20 @@ "target_name": "org_junit_vintage_junit_vintage_engine" } }, + "org_graalvm_buildtools_junit_platform_native_0_9_28": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_graalvm_buildtools_junit_platform_native_0_9_28", + "sha256": "b3f1f35878fdf3d2040e75f0fd5a787f03bf33c567419f81f4ce935726ea38fe", + "urls": [ + "https://maven.pkg.st/org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28.jar", + "https://maven.google.com/org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28.jar", + "https://repo1.maven.org/maven2/org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28.jar" + ], + "downloaded_file_path": "org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28.jar" + } + }, "org_codehaus_plexus_plexus_utils_3_5_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -6366,6 +6833,20 @@ "downloaded_file_path": "com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar" } }, + "org_graalvm_buildtools_junit_platform_native_jar_sources_0_9_28": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_graalvm_buildtools_junit_platform_native_jar_sources_0_9_28", + "sha256": "117c6752e28c6335c506c2d5fd945d9b4f6d0aeb9a6a4c960f19e1cc61e8efad", + "urls": [ + "https://maven.pkg.st/org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28-sources.jar", + "https://maven.google.com/org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28-sources.jar", + "https://repo1.maven.org/maven2/org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28-sources.jar" + ], + "downloaded_file_path": "org/graalvm/buildtools/junit-platform-native/0.9.28/junit-platform-native-0.9.28-sources.jar" + } + }, "com_google_errorprone_error_prone_annotations": { "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", "ruleClassName": "compat_repository", @@ -6410,6 +6891,20 @@ "downloaded_file_path": "software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar" } }, + "org_apiguardian_apiguardian_api_1_1_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apiguardian_apiguardian_api_1_1_2", + "sha256": "b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38", + "urls": [ + "https://maven.pkg.st/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar", + "https://maven.google.com/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar", + "https://repo1.maven.org/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar" + ], + "downloaded_file_path": "org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar" + } + }, "maven": { "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", "ruleClassName": "coursier_fetch", @@ -6450,6 +6945,20 @@ "duplicate_version_warning": "warn" } }, + "org_junit_platform_junit_platform_launcher_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_launcher_1_10_0", + "sha256": "8c60b661ac170701a635dfc67565efbb8c85b5c5cdd5a4a9576e3a015c7111a4", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar", + "https://maven.google.com/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-launcher/1.10.0/junit-platform-launcher-1.10.0.jar" + } + }, "io_netty_netty_codec_http_4_1_86_Final": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -6463,6 +6972,20 @@ "downloaded_file_path": "io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar" } }, + "org_junit_platform_junit_platform_engine_1_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_platform_junit_platform_engine_1_10_0", + "sha256": "cd338efd02ee73966ea754e0c0c71e1a11f4af5db9c2003e4b6137e119155abe", + "urls": [ + "https://maven.pkg.st/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar", + "https://maven.google.com/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar" + ], + "downloaded_file_path": "org/junit/platform/junit-platform-engine/1.10.0/junit-platform-engine-1.10.0.jar" + } + }, "com_google_cloud_google_cloud_core_grpc_2_18_1": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -6511,6 +7034,20 @@ "target_name": "org_junit_platform_junit_platform_reporting" } }, + "org_junit_jupiter_junit_jupiter_engine_5_10_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_junit_jupiter_junit_jupiter_engine_5_10_0", + "sha256": "57ea48e6f795200791065bbc86b70b84cd05367c5c9f2ac8f9268e27154c88a8", + "urls": [ + "https://maven.pkg.st/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar", + "https://maven.google.com/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar", + "https://repo1.maven.org/maven2/org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar" + ], + "downloaded_file_path": "org/junit/jupiter/junit-jupiter-engine/5.10.0/junit-jupiter-engine-5.10.0.jar" + } + }, "com_google_errorprone_error_prone_annotations_2_11_0": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", @@ -6787,6 +7324,20 @@ "target_name": "com_google_guava_guava" } }, + "org_opentest4j_opentest4j_1_3_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_opentest4j_opentest4j_1_3_0", + "sha256": "48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b", + "urls": [ + "https://maven.pkg.st/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar", + "https://maven.google.com/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar", + "https://repo1.maven.org/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar" + ], + "downloaded_file_path": "org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar" + } + }, "org_checkerframework_checker_qual_3_13_0": { "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", "ruleClassName": "http_file", diff --git a/example/shared/BUILD.bazel b/example/shared/BUILD.bazel index 44729274..0c2f4a82 100644 --- a/example/shared/BUILD.bazel +++ b/example/shared/BUILD.bazel @@ -35,7 +35,7 @@ native_image_shared_library( name = "mylib", deps = [":java"], strict = True, - executable_name = "mylib", + lib_name = "libmylib", # becomes `libmylib.so`, `libmylib.dylib`, etc. reflection_configuration = ":reflection-config", ) diff --git a/example/testing/BUILD.bazel b/example/testing/BUILD.bazel new file mode 100644 index 00000000..4fbcea5e --- /dev/null +++ b/example/testing/BUILD.bazel @@ -0,0 +1,50 @@ +load( + "@rules_graalvm//graalvm:defs.bzl", + "native_image_test", +) +load( + "@rules_java//java:defs.bzl", + "java_library", +) +load( + "//tools/defs:junit5.bzl", + java_test = "java_junit5_test", +) + +package(default_visibility = [ + "//tests:__subpackages__", +]) + + +java_library( + name = "java", + srcs = ["Something.java"], +) + +java_test( + name = "java-test", + test_package = "example.testing", + srcs = ["SomethingTest.java"], + size = "small", + deps = [ + ":java", + ], +) + +native_image_test( + name = "native-test", + tests = [":java-test"], + size = "small", +) + +test_suite( + name = "tests", + tests = [ + ":native-test", + ], +) + +alias( + name = "testing", + actual = "tests", +) diff --git a/example/testing/Something.java b/example/testing/Something.java new file mode 100644 index 00000000..2e37cb9a --- /dev/null +++ b/example/testing/Something.java @@ -0,0 +1,11 @@ +package example.testing; + +public class Something { + public static void main(String args[]) { + System.out.println("Hello, GraalVM!"); + } + + public static int add(int a, int b) { + return a + b; + } +} diff --git a/example/testing/SomethingTest.java b/example/testing/SomethingTest.java new file mode 100644 index 00000000..1ab4c80c --- /dev/null +++ b/example/testing/SomethingTest.java @@ -0,0 +1,29 @@ +package example.testing; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import example.testing.Something; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; + +public class SomethingTest { + @Test + public void testMath() { + assertEquals(3, 1 + 2); + } + + @Test + @Disabled + public void testFails() { + assertEquals(4, 1 + 2); + } + + // @Test + // public void testSomething() { + // assertEquals(3, Something.add(1, 2)); + // } + + // @Test + // public void testSomethingThatFails() { + // assertEquals(9, Something.add(1, 2)); + // } +} diff --git a/graalvm/defs.bzl b/graalvm/defs.bzl index f74fd591..f672d855 100644 --- a/graalvm/defs.bzl +++ b/graalvm/defs.bzl @@ -4,8 +4,10 @@ load( "//graalvm/nativeimage:rules.bzl", _native_image = "native_image", _native_image_shared_library = "native_image_shared_library", + _native_image_test = "native_image_test", ) ## Exports native_image = _native_image native_image_shared_library = _native_image_shared_library +native_image_test = _native_image_test diff --git a/graalvm/nativeimage/rules.bzl b/graalvm/nativeimage/rules.bzl index 1fb580a8..e4c3b05a 100644 --- a/graalvm/nativeimage/rules.bzl +++ b/graalvm/nativeimage/rules.bzl @@ -13,17 +13,21 @@ load( _DEBUG = "DEBUG_CONDITION", _GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE", _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", + _NATIVE_IMAGE_TEST_ATTRS = "NATIVE_IMAGE_TEST_ATTRS", _NATIVE_IMAGE_SHARED_LIB_ATTRS = "NATIVE_IMAGE_SHARED_LIB_ATTRS", _OUTPUT_GROUPS = "OUTPUT_GROUPS", _OPTIMIZATION_MODE = "OPTIMIZATION_MODE_CONDITION", _graal_binary_implementation = "graal_binary_implementation", _graal_shared_binary_implementation = "graal_shared_binary_implementation", + _graal_test_binary_implementation = "graal_test_binary_implementation", ) load( "//internal/native_image:settings.bzl", "NativeImageInfo", ) +_DEFAULT_NATIVE_IMAGE_TESTUTILS = Label("@rules_graalvm//graalvm/testing") + _DEFAULT_NATIVE_IMAGE_SETTINGS = Label("@rules_graalvm//internal/native_image:defaults") _DEFAULT_CHECK_TOOLCHAINS_CONDITION = select({ @@ -36,6 +40,22 @@ _EXEUCTABLE_NAME_CONDITION = select({ "//conditions:default": "%target%-bin", }) +_TEST_NAME_CONDITION = select({ + "@bazel_tools//src/conditions:windows": "%target%-test.exe", + "//conditions:default": "%target%-test", +}) + +_DEFAULT_NATIVE_IMAGE_TESTDEPS = [ + Label("@maven_gvm//:org_graalvm_sdk_nativeimage"), + Label("@maven_gvm//:org_graalvm_buildtools_junit_platform_native"), + Label("@maven_gvm//:org_junit_jupiter_junit_jupiter_api"), + Label("@maven_gvm//:org_junit_jupiter_junit_jupiter_engine"), + Label("@maven_gvm//:org_junit_jupiter_junit_jupiter_params"), + Label("@maven_gvm//:org_junit_platform_junit_platform_console"), + Label("@maven_gvm//:org_junit_platform_junit_platform_commons"), + Label("@maven_gvm//:org_junit_platform_junit_platform_launcher"), +] + _SHARED_LIB_NAME_CONDITION = select({ "//conditions:default": "%target%", }) @@ -54,36 +74,48 @@ _modern_rule_attrs = { ), } -_native_image = rule( - implementation = _graal_binary_implementation, - attrs = dicts.add(_NATIVE_IMAGE_ATTRS, **_modern_rule_attrs), - executable = True, - fragments = [ +_modern_rule_options = { + "fragments": [ "apple", + "coverage", "cpp", "java", "platform", "xcode", ], - toolchains = use_cpp_toolchain() + [ + "toolchains": use_cpp_toolchain() + [ _GVM_TOOLCHAIN_TYPE, ], +} + +_native_image = rule( + implementation = _graal_binary_implementation, + attrs = dicts.add(_NATIVE_IMAGE_ATTRS, **_modern_rule_attrs), + executable = True, + **_modern_rule_options, +) + +_native_image_test = rule( + implementation = _graal_test_binary_implementation, + executable = True, + test = True, + attrs = dicts.add(_NATIVE_IMAGE_TEST_ATTRS, dicts.add(_modern_rule_attrs, **{ + "_native_image_test_utils": attr.label( + mandatory = False, + default = _DEFAULT_NATIVE_IMAGE_TESTUTILS, + ), + "_native_test_deps": attr.label_list( + mandatory = False, + default = _DEFAULT_NATIVE_IMAGE_TESTDEPS, + ) + })), + **_modern_rule_options, ) _native_image_shared_library = rule( implementation = _graal_shared_binary_implementation, attrs = dicts.add(_NATIVE_IMAGE_SHARED_LIB_ATTRS, **_modern_rule_attrs), - executable = True, - fragments = [ - "apple", - "cpp", - "java", - "platform", - "xcode", - ], - toolchains = use_cpp_toolchain() + [ - _GVM_TOOLCHAIN_TYPE, - ], + **_modern_rule_options, ) _NATIVE_IMAGE_UTILS = struct( @@ -180,7 +212,136 @@ def native_image( main_class = main_class, include_resources = include_resources, reflection_configuration = reflection_configuration, + reflection_configurations = reflection_configurations, jni_configuration = jni_configuration, + jni_configurations = jni_configurations, + resource_configuration = resource_configuration, + resource_configurations = resource_configurations, + proxy_configuration = proxy_configuration, + proxy_configurations = proxy_configurations, + serialization_configuration = serialization_configuration, + serialization_configurations = serialization_configurations, + initialize_at_build_time = initialize_at_build_time, + initialize_at_run_time = initialize_at_run_time, + native_features = native_features, + debug = debug, + optimization_mode = optimization_mode, + shared_library = shared_library, + data = data, + extra_args = extra_args, + check_toolchains = check_toolchains, + static_zlib = static_zlib, + c_compiler_option = c_compiler_option, + allow_fallback = allow_fallback, + executable_name = executable_name, + native_image_tool = native_image_tool, + native_image_settings = native_image_settings, + profiles = profiles, + additional_outputs = additional_outputs, + default_outputs = default_outputs, + **kwargs + ) + +def native_image_test( + name, + tests, + deps = [], + main_class = None, + discovery = True, + executable_name = _TEST_NAME_CONDITION, + include_resources = None, + reflection_configuration = None, + reflection_configurations = [], + jni_configuration = None, + jni_configurations = [], + resource_configuration = None, + resource_configurations = [], + proxy_configuration = None, + proxy_configurations = [], + serialization_configuration = None, + serialization_configurations = [], + initialize_at_build_time = [], + initialize_at_run_time = [], + native_features = [], + debug = _DEBUG, + optimization_mode = _OPTIMIZATION_MODE, + shared_library = None, + static_zlib = None, + c_compiler_option = [], + data = [], + extra_args = [], + allow_fallback = False, + check_toolchains = _DEFAULT_CHECK_TOOLCHAINS_CONDITION, + native_image_tool = None, # uses toolchains by default + native_image_settings = [_DEFAULT_NATIVE_IMAGE_SETTINGS], + profiles = [], + additional_outputs = [], + default_outputs = True, + **kwargs): + """Generates and compiles a GraalVM native image from a Java library target. + + Args: + name: Name of the target; required. + tests: Java test targets to build and run natively. + deps: Dependency `java_library` targets to assemble the classpath from. Mandatory. + main_class: Testrunner to use; defaults to Bazel's test runner. + discovery: Enable test discovery support; injects classes to discover tests. Defaults to `True`. + executable_name: Set the name of the output binary; defaults to `%target%-test`, or `%target%-test.exe` on Windows. + The special string `%target%`, if present, is replaced with `name`. + include_resources: Glob to pass to `IncludeResources`. No default; optional. + reflection_configuration: Reflection configuration file. No default; optional. + reflection_configurations: Reflection configuration file. No default; optional. + jni_configuration: JNI configuration file. No default; optional. + jni_configurations: Multiple JNI configuration files. No default; optional. + resource_configuration: Configuration file for embedded resources. No default; optional. + resource_configurations: Configuration files for embedded resources. No default; optional. + proxy_configuration: Configuration file for Java class proxies. No default; optional. + proxy_configurations: Configuration files for Java class proxies. No default; optional. + serialization_configuration: Configuration file for Java class proxies. No default; optional. + serialization_configurations: Configuration files for Java class proxies. No default; optional. + initialize_at_build_time: Classes or patterns to pass to `--initialize-at-build-time`. No default; optional. + initialize_at_run_time: Classes or patterns to pass to `--initialize-at-run-time`. No default; optional. + native_features: GraalVM `Feature` classes to include and apply. No default; optional. + debug: Whether to include debug symbols; by default, this flag's state is managed by Bazel. Passing + `--compilation_mode=dbg` is sufficient to flip this to `True`, or it can be overridden via this parameter. + optimization_mode: Behaves the same as `debug`; normally, this flag's state is managed by Bazel. Passing + `--compilation_mode=fastbuild|opt|dbg` is sufficient to set this flag, or it can be overridden via this + parameter. + shared_library: Build a shared library binary instead of an executable. + static_zlib: A cc_library or cc_import target that provides zlib as a static library. + On Linux, this is used when Graal statically links zlib into the binary, e.g. with + `-H:+StaticExecutableWithDynamicLibC`. + c_compiler_option: Extra C compiler options to pass through `native-image`. No default; optional. + data: Data files to make available during the compilation. No default; optional. + extra_args: Extra `native-image` args to pass. Last wins. No default; optional. + allow_fallback: Whether to allow fall-back to a partial native image; defaults to `False`. + additional_outputs: Additional outputs to expect from the rule (for example, polyglot language resources). + check_toolchains: Whether to perform toolchain checks in `native-image`; defaults to `True` on Windows, `False` otherwise. + native_image_tool: Specific `native-image` executable target to use. + native_image_settings: Suite(s) of Native Image build settings to use. + profiles: Profiles to use for profile-guided optimization (PGO) and obtained from a native image compiled with `--pgo-instrument`. + default_outputs: Whether to consider default output files; when `False`, the developer specifies all outputs on top of the + binary itself. + **kwargs: Extra keyword arguments are passed to the underlying `native_image` rule. + """ + + _native_image_test( + name = name, + tests = tests, + deps = deps, + main_class = main_class, + discovery = discovery, + include_resources = include_resources, + reflection_configuration = reflection_configuration, + reflection_configurations = reflection_configurations, + jni_configuration = jni_configuration, + jni_configurations = jni_configurations, + resource_configuration = resource_configuration, + resource_configurations = resource_configurations, + proxy_configuration = proxy_configuration, + proxy_configurations = proxy_configurations, + serialization_configuration = serialization_configuration, + serialization_configurations = serialization_configurations, initialize_at_build_time = initialize_at_build_time, initialize_at_run_time = initialize_at_run_time, native_features = native_features, diff --git a/graalvm/testing/BUILD.bazel b/graalvm/testing/BUILD.bazel new file mode 100644 index 00000000..c1c19ef7 --- /dev/null +++ b/graalvm/testing/BUILD.bazel @@ -0,0 +1,23 @@ +load( + "@rules_java//java:defs.bzl", + "java_library", +) + +package(default_visibility = [ + "@//:__subpackages__", +]) + +java_library( + name = "testing", + testonly = True, + srcs = [ + "NativeTestRunner.java", + "NativeTestFeature.java", + "NativeTestLauncher.java", + ], + deps = [ + "@maven_gvm//:org_graalvm_sdk_nativeimage", + "@maven_gvm//:org_graalvm_buildtools_junit_platform_native", + "@maven_gvm//:org_junit_platform_junit_platform_launcher", + ], +) diff --git a/graalvm/testing/NativeTestFeature.java b/graalvm/testing/NativeTestFeature.java new file mode 100644 index 00000000..e644db0a --- /dev/null +++ b/graalvm/testing/NativeTestFeature.java @@ -0,0 +1,15 @@ + +package graalvm.testing; + +import org.graalvm.nativeimage.hosted.Feature; +import java.util.Collections; +import java.util.List; + +public final class NativeTestFeature implements Feature { + @Override + public List> getRequiredFeatures() { + return Collections.singletonList( + org.graalvm.junit.platform.JUnitPlatformFeature.class + ); + } +} diff --git a/graalvm/testing/NativeTestLauncher.java b/graalvm/testing/NativeTestLauncher.java new file mode 100644 index 00000000..641a2f6f --- /dev/null +++ b/graalvm/testing/NativeTestLauncher.java @@ -0,0 +1,16 @@ +package graalvm.testing; + +import org.graalvm.junit.platform.NativeImageJUnitLauncher; +import org.junit.platform.launcher.Launcher; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestPlan; + +public final class NativeTestLauncher extends NativeImageJUnitLauncher { + public NativeTestLauncher(Launcher launcher, TestPlan testPlan) { + super(launcher, testPlan); + } + + public static void exec(String entry, String suite, boolean discovery, String[] args) { + NativeImageJUnitLauncher.main(); + } +} diff --git a/graalvm/testing/NativeTestRunner.java b/graalvm/testing/NativeTestRunner.java new file mode 100644 index 00000000..958098d0 --- /dev/null +++ b/graalvm/testing/NativeTestRunner.java @@ -0,0 +1,16 @@ +package graalvm.testing; + +public final class NativeTestRunner { + private static final String discoveryProperty = "bazel.graalvm.testing.discovery"; + private static final String entryWrapped = "bazel.graalvm.testing.wrappedEntry"; + private static final String bazelSuite = "bazel.test_suite"; + + public static void main(String[] args) { + NativeTestLauncher.exec( + System.getProperty(entryWrapped), + System.getProperty(bazelSuite), + "true".equals(System.getProperty(discoveryProperty)), + args + ); + } +} diff --git a/graalvm/testing/defs.bzl b/graalvm/testing/defs.bzl new file mode 100644 index 00000000..c7b204d6 --- /dev/null +++ b/graalvm/testing/defs.bzl @@ -0,0 +1,21 @@ +"Defines common values used for native testing." + +load( + "//internal/testing:bzl", + _NATIVE_TEST_ENTRYPOINT = "NATIVE_TEST_ENTRYPOINT", + _DEFAULT_WRAPPED_ENTRYPOINT = "DEFAULT_WRAPPED_ENTRYPOINT", + _DEFAULT_NATIVE_BASE_ENTRYPOINT = "DEFAULT_NATIVE_BASE_ENTRYPOINT", + _NATIVE_TEST_FEATURE = "NATIVE_TEST_FEATURE", +) + +# Top-level entrypoint for native tests (unless user provides their own). +NATIVE_TEST_ENTRYPOINT = _NATIVE_TEST_ENTRYPOINT + +# Default Bazel entrypoint wrapped by the top-level entrypoint. +DEFAULT_WRAPPED_ENTRYPOINT = _DEFAULT_WRAPPED_ENTRYPOINT + +# Default GraalVM test discovery entrypoint overridden by the top-level entrypoint. +DEFAULT_NATIVE_BASE_ENTRYPOINT = _DEFAULT_NATIVE_BASE_ENTRYPOINT + +# Compile-time feature which configures reflective access to entrypoints and tests. +NATIVE_TEST_FEATURE = _NATIVE_TEST_FEATURE diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index 72324ff4..c5ad0731 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -1,5 +1,10 @@ "Logic to assemble `native-image` options." +load( + "//internal/native_image:testing.bzl", + _NATIVE_TEST_ENTRYPOINT = "NATIVE_TEST_ENTRYPOINT", +) + _NATIVE_IMAGE_SHARED_TMP_DIR_TPL = "native-shlib-%s" _DEFAULT_NATIVE_IMAGE_ARGS = [ @@ -263,9 +268,13 @@ def assemble_native_build_options( # @TODO(sgammon): only append with gvm version > 23.1.x # "-H:+UnlockExperimentalVMOptions" + is_test = ctx.attr._is_test + # main class is required unless we are building a shared library if ctx.attr.shared_library: args.add("--shared") + elif is_test: + pass # no main class for tests elif ctx.attr.main_class == None or ctx.attr.main_class == "": fail(""" Native Image build failure: `main_class` attribute is mandatory in `native_image` or `graal_binary` targets, @@ -289,6 +298,13 @@ def assemble_native_build_options( ) else: args.add(ctx.attr.main_class, format = "-H:Class=%s") + elif is_test: + # it's a test and we have no entrypoint class, so we should use the default + # entrypoint provided by this package. + args.add( + _NATIVE_TEST_ENTRYPOINT, + format = "-H:Class=%s", + ) # binary path supports expansion _arg_formatted( diff --git a/internal/native_image/common.bzl b/internal/native_image/common.bzl index c51a65f0..98506ae2 100644 --- a/internal/native_image/common.bzl +++ b/internal/native_image/common.bzl @@ -167,6 +167,9 @@ _NATIVE_IMAGE_BASE_ATTRS = { "_cc_toolchain": attr.label( default = Label(_BAZEL_CURRENT_CPP_TOOLCHAIN), ), + "_is_test": attr.bool( + default = False, + ), "_linux_constraint": attr.label( default = Label(_LINUX_CONSTRAINT), ), @@ -333,4 +336,5 @@ MACOS_CONSTRAINT = _MACOS_CONSTRAINT WINDOWS_CONSTRAINT = _WINDOWS_CONSTRAINT NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_BIN_ATTRS NATIVE_IMAGE_SHARED_LIB_ATTRS = _NATIVE_IMAGE_SHAREDLIB_ATTRS +NATIVE_IMAGE_TEST_ATTRS = _NATIVE_IMAGE_TEST_ATTRS prepare_native_image_rule_context = _prepare_native_image_rule_context diff --git a/internal/native_image/rules.bzl b/internal/native_image/rules.bzl index 004c6c2b..899255b0 100644 --- a/internal/native_image/rules.bzl +++ b/internal/native_image/rules.bzl @@ -20,11 +20,18 @@ load( _GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE", _NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS", _NATIVE_IMAGE_SHARED_LIB_ATTRS = "NATIVE_IMAGE_SHARED_LIB_ATTRS", + _NATIVE_IMAGE_TEST_ATTRS = "NATIVE_IMAGE_TEST_ATTRS", _OPTIMIZATION_MODE_CONDITION = "OPTIMIZATION_MODE_CONDITION", _OUTPUT_GROUPS = "OUTPUT_GROUPS", _RULES_REPO = "RULES_REPO", _prepare_native_image_rule_context = "prepare_native_image_rule_context", ) +load( + "//internal/native_image:testing.bzl", + _DEFAULT_WRAPPED_ENTRYPOINT = "DEFAULT_WRAPPED_ENTRYPOINT", + _DEFAULT_NATIVE_BASE_ENTRYPOINT = "DEFAULT_NATIVE_BASE_ENTRYPOINT", + _NATIVE_TEST_FEATURE = "NATIVE_TEST_FEATURE", +) load( "//internal/native_image:toolchain.bzl", _resolve_cc_toolchain = "resolve_cc_toolchain", @@ -54,10 +61,34 @@ def _prepare_execution_env(ctx, base_env = {}): }) return effective +def _create_testrunner_entry_script(ctx, binary, test_args = []): + """Merge available test args from the user, and from the testrunner script to create a shell entrypoint.""" + + formatted_args = " ".join([ctx.expand_location(i) for i in test_args]) + + # create a wrapper shell script which will invoke the testrunner script with the correct args + script = ctx.actions.declare_file( + "%s-native-testrunner.sh" % ctx.label.name, + ) + ctx.actions.write( + script, + """ +#!/bin/bash +set -euo pipefail +exec {binary} {args} + """.format( + binary = binary.short_path, + args = formatted_args, + ), + ) + return script + def _graal_binary_implementation(ctx): output_groups = {} + is_test = ctx.attr._is_test graal_attr = ctx.attr.native_image_tool extra_tool_deps = [] + direct_inputs = [] gvm_toolchain = None # build a suite of modular-capable dependencies @@ -70,18 +101,64 @@ def _graal_binary_implementation(ctx): ]) modular_jars = modulepath_depset.to_list() - classpath_depset = depset(transitive = [ + # build deps list of utilities (for example, injected test deps) + utils_deps = [] + if is_test: + utils_deps.append(depset(ctx.files._native_image_test_utils)) + utils_deps.append(depset(transitive = [ + dep[JavaInfo].transitive_runtime_jars + for dep in ctx.attr._native_test_deps + ] + [ + dep[JavaInfo].transitive_compile_time_jars + for dep in ctx.attr._native_test_deps + ])) + + # build classpath depset, withholding any deps which are modular; we include compile-time + # deps here as well, since GVM should be able to see them. + depset_transitive = [ f for f in [ dep[JavaInfo].transitive_runtime_jars for dep in ctx.attr.deps ] if f not in modular_jars + ] + depset_transitive.extend([ + f for f in + [ + dep[JavaInfo].transitive_compile_time_jars + for dep in ctx.attr.deps + ] + if f not in modular_jars ]) + depset_transitive.extend( + utils_deps + ) + + # if this is a test target, include transitive test dependencies + if is_test: + depset_transitive.append(depset(transitive = [ + test[JavaInfo].transitive_runtime_jars + for test in ctx.attr.tests + ] + [ + test[JavaInfo].transitive_compile_time_jars + for test in ctx.attr.tests + ])) + for test in ctx.attr.tests: + depset_transitive.append(test.files) + + # seal our classpath depset, we're ready to use it + classpath_depset = depset(transitive = depset_transitive) graal = None - direct_inputs = [] - transitive_inputs = [classpath_depset] + transitive_inputs = [ + classpath_depset, + modulepath_depset, + ] + + # if this is a test, we need to include the test sources as inputs + if is_test: + direct_inputs.extend(ctx.files.tests) # resolve via toolchains info = ctx.toolchains[_GVM_TOOLCHAIN_TYPE].graalvm @@ -143,6 +220,32 @@ def _graal_binary_implementation(ctx): bin_postfix = _BIN_POSTFIX_SO args = ctx.actions.args().use_param_file("@%s", use_always=True) + + # if we're running tests or doing other special stuff, we may need to inject features into + # the graalvm build context. + test_args = [] + injected_args = [] + injected_features = [] + if is_test: + injected_features.append(_NATIVE_TEST_FEATURE) + test_args.append("-Dbazel.graalvm.testing=true") + test_args.append("-Dbazel.graalvm.native=true") + test_args.append("-Dbazel.graalvm.testing.discovery=%s" % (ctx.attr.discovery and "true" or "false")) + test_args.append("-Dbazel.graalvm.testing.nativeEntry=%s" % _DEFAULT_NATIVE_BASE_ENTRYPOINT) + test_args.append("-Dbazel.graalvm.testing.wrappedEntry=%s" % (ctx.attr.main_class or _DEFAULT_WRAPPED_ENTRYPOINT)) + injected_args.append("-R:-Dbazel.graalvm.testing=true") + injected_args.append("-R:-Dbazel.graalvm.native=true") + injected_args.extend(test_args) + + # enable test discovery if requested + if ctx.attr.discovery: + injected_args.append("-DtestDiscovery") + + # if the user provided features via the `native_features` attribute, consider those, too. + if ctx.attr.native_features: + injected_features.extend(ctx.attr.native_features) + + # prepare rule context and outputs all_outputs = _prepare_native_image_rule_context( ctx, args, @@ -152,8 +255,11 @@ def _graal_binary_implementation(ctx): gvm_toolchain, bin_postfix = bin_postfix, modulepath_depset = modulepath_depset, + injected_features = injected_features, ) binary = all_outputs[0] + + # prepare execution environment execution_env = _prepare_execution_env( ctx, native_toolchain.env, @@ -164,6 +270,12 @@ def _graal_binary_implementation(ctx): direct_inputs, transitive = transitive_inputs, ) + target_type = "executable" + if ctx.attr.shared_library: + target_type = "shared lib" + elif is_test: + target_type = "test" + run_params = { "outputs": all_outputs, "executable": graal, @@ -173,7 +285,7 @@ def _graal_binary_implementation(ctx): "execution_requirements": {k: "" for k in native_toolchain.execution_requirements}, "progress_message": "Native Image __target__ (__mode__) %{label}" .replace("__mode__", _build_action_message(ctx)) - .replace("__target__", ctx.attr.shared_library and "[shared lib]" or "[executable]"), + .replace("__target__", "[%s]" % target_type), "toolchain": Label(_GVM_TOOLCHAIN_TYPE), } @@ -246,24 +358,37 @@ def _graal_binary_implementation(ctx): # if it's not a shared library, our default output is the binary produced output_groups[_OUTPUT_GROUPS.DEFAULT] = depset([binary]) + # if we are building a test, we need to create a shell script which wraps the test's + # execution, and sets up the args and environment correctly. then, we need to swap the + # main output binary for this wrapper. + entrypoint = binary + extra_runfiles = [] + if is_test: + entrypoint = _create_testrunner_entry_script( + ctx, + binary, + test_args, + ) + extra_runfiles.append(binary) + # prepare all runfiles all_runfiles = ctx.runfiles( collect_data = True, collect_default = True, - files = [], + files = extra_runfiles, ) if runfiles != None: all_runfiles = all_runfiles.merge(runfiles) return output_infos + [ DefaultInfo( - executable = binary, + executable = entrypoint, files = depset(all_outputs), runfiles = all_runfiles, ), OutputGroupInfo( **output_groups - ) + ), ] def _wrap_actions_for_graal(actions): @@ -297,9 +422,11 @@ DEFAULT_GVM_REPO = _DEFAULT_GVM_REPO BAZEL_CURRENT_CPP_TOOLCHAIN = _BAZEL_CURRENT_CPP_TOOLCHAIN NATIVE_IMAGE_ATTRS = _NATIVE_IMAGE_ATTRS NATIVE_IMAGE_SHARED_LIB_ATTRS = _NATIVE_IMAGE_SHARED_LIB_ATTRS +NATIVE_IMAGE_TEST_ATTRS = _NATIVE_IMAGE_TEST_ATTRS GVM_TOOLCHAIN_TYPE = _GVM_TOOLCHAIN_TYPE OUTPUT_GROUPS = _OUTPUT_GROUPS DEBUG_CONDITION = _DEBUG_CONDITION OPTIMIZATION_MODE_CONDITION = _OPTIMIZATION_MODE_CONDITION graal_binary_implementation = _graal_binary_implementation graal_shared_binary_implementation = _graal_binary_implementation +graal_test_binary_implementation = _graal_binary_implementation diff --git a/internal/native_image/testing.bzl b/internal/native_image/testing.bzl new file mode 100644 index 00000000..647199b7 --- /dev/null +++ b/internal/native_image/testing.bzl @@ -0,0 +1,13 @@ +"Internals for testing with GraalVM native images." + +# Top-level entrypoint for native tests (unless user provides their own). +NATIVE_TEST_ENTRYPOINT = "graalvm.testing.NativeTestRunner" + +# Default Bazel entrypoint wrapped by the top-level entrypoint. +DEFAULT_WRAPPED_ENTRYPOINT = "com.google.testing.junit.runner.BazelTestRunner" + +# Default GraalVM test discovery entrypoint overridden by the top-level entrypoint. +DEFAULT_NATIVE_BASE_ENTRYPOINT = "org.graalvm.junit.platform.NativeImageJUnitLauncher" + +# Compile-time feature which configures reflective access to entrypoints and tests. +NATIVE_TEST_FEATURE = "graalvm.testing.NativeTestFeature" diff --git a/internal/testing.bzl b/internal/testing.bzl new file mode 100644 index 00000000..defa3fd9 --- /dev/null +++ b/internal/testing.bzl @@ -0,0 +1,21 @@ +"Defines common values used for native testing." + +load( + "//internal/native_image/testing:bzl", + _NATIVE_TEST_ENTRYPOINT = "NATIVE_TEST_ENTRYPOINT", + _DEFAULT_WRAPPED_ENTRYPOINT = "DEFAULT_WRAPPED_ENTRYPOINT", + _DEFAULT_NATIVE_BASE_ENTRYPOINT = "DEFAULT_NATIVE_BASE_ENTRYPOINT", + _NATIVE_TEST_FEATURE = "NATIVE_TEST_FEATURE", +) + +# Top-level entrypoint for native tests (unless user provides their own). +NATIVE_TEST_ENTRYPOINT = _NATIVE_TEST_ENTRYPOINT + +# Default Bazel entrypoint wrapped by the top-level entrypoint. +DEFAULT_WRAPPED_ENTRYPOINT = _DEFAULT_WRAPPED_ENTRYPOINT + +# Default GraalVM test discovery entrypoint overridden by the top-level entrypoint. +DEFAULT_NATIVE_BASE_ENTRYPOINT = _DEFAULT_NATIVE_BASE_ENTRYPOINT + +# Compile-time feature which configures reflective access to entrypoints and tests. +NATIVE_TEST_FEATURE = _NATIVE_TEST_FEATURE diff --git a/maven_install.json b/maven_install.json index e18f863f..40d03564 100755 --- a/maven_install.json +++ b/maven_install.json @@ -1,8 +1,29 @@ { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": 1409611957, - "__RESOLVED_ARTIFACTS_HASH": -1141381396, + "__INPUT_ARTIFACTS_HASH": 617447018, + "__RESOLVED_ARTIFACTS_HASH": -2008138335, "artifacts": { + "junit:junit": { + "shasums": { + "jar": "59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a", + "sources": "9f43fea92033ad82bcad2ae44cec5c82abc9d6ee4b095cab921d11ead98bf2ff" + }, + "version": "4.12" + }, + "org.apiguardian:apiguardian-api": { + "shasums": { + "jar": "b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38", + "sources": "277a7a4315412817beb6655b324dc7276621e95ebff00b8bf65e17a27b685e2d" + }, + "version": "1.1.2" + }, + "org.graalvm.buildtools:junit-platform-native": { + "shasums": { + "jar": "b3f1f35878fdf3d2040e75f0fd5a787f03bf33c567419f81f4ce935726ea38fe", + "sources": "117c6752e28c6335c506c2d5fd945d9b4f6d0aeb9a6a4c960f19e1cc61e8efad" + }, + "version": "0.9.28" + }, "org.graalvm.compiler:compiler": { "shasums": { "jar": "dc6ae2eba4e26d0e049b13f4eee739c3d4d338af92ad9dd489c9399599c9713c", @@ -79,9 +100,94 @@ "sources": "34c3883109533eb82a0a9b43d4852fe7368f35d30d3c79c3dada623681dc3fbb" }, "version": "23.1.1" + }, + "org.hamcrest:hamcrest-core": { + "shasums": { + "jar": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", + "sources": "e223d2d8fbafd66057a8848cc94222d63c3cedd652cc48eddc0ab5c39c0f84df" + }, + "version": "1.3" + }, + "org.junit.jupiter:junit-jupiter": { + "shasums": { + "jar": "8e4bde23ee28fc443975654a7b28c410a3b78d6be96b78c99ab73695ec344f7c", + "sources": "bd628b06b83b0d8830b53747b7f466beebca12d4808f117660ac06e47af99d1c" + }, + "version": "5.10.0" + }, + "org.junit.jupiter:junit-jupiter-api": { + "shasums": { + "jar": "108088fd7ea46a8e65a0ce7f5d75ae3ff7865606770a078715f5a6e5709e17d8", + "sources": "34fbf1f58dac2db51ab44f22f547fcee185b342d046c3ac119ec00dd2ba98e75" + }, + "version": "5.10.0" + }, + "org.junit.jupiter:junit-jupiter-engine": { + "shasums": { + "jar": "57ea48e6f795200791065bbc86b70b84cd05367c5c9f2ac8f9268e27154c88a8", + "sources": "050476b6fa4a57db3152f52403860019a5588d480d653bc7a1df5bcc84376211" + }, + "version": "5.10.0" + }, + "org.junit.jupiter:junit-jupiter-params": { + "shasums": { + "jar": "f259a7322cce375430c2236a2dcb24d4a49d22045b723ad85af88e11704391c2", + "sources": "7d20740d1dded4cb1de5805c3da3293b6a5e2991ad3b64539aa575c9638719dc" + }, + "version": "5.10.0" + }, + "org.junit.platform:junit-platform-commons": { + "shasums": { + "jar": "6083db08ca11fca1e16099d0dcfede0193d80b3762b276349d80d3da536791b2", + "sources": "ebeb653947017ad2eadc5e9f38eab56400003886d9edf6f336890906e8c905b3" + }, + "version": "1.10.0" + }, + "org.junit.platform:junit-platform-console": { + "shasums": { + "jar": "5c43a8dccbb24781a1880ce0287e81290eb8fd23fa6800a346cec219a46b21a8", + "sources": "31abe626be8e567e99366667a1242e2d469e3e828d40efca65017662df4f61c6" + }, + "version": "1.10.0" + }, + "org.junit.platform:junit-platform-engine": { + "shasums": { + "jar": "cd338efd02ee73966ea754e0c0c71e1a11f4af5db9c2003e4b6137e119155abe", + "sources": "17ac74964fcd82c57130623afe72a99105ca107fc96cb53f169b3a8c9c444c83" + }, + "version": "1.10.0" + }, + "org.junit.platform:junit-platform-launcher": { + "shasums": { + "jar": "8c60b661ac170701a635dfc67565efbb8c85b5c5cdd5a4a9576e3a015c7111a4", + "sources": "f98514c156fe6a257659e2c4e964193ffc1d68df1e003d0d0470b24b9055787e" + }, + "version": "1.10.0" + }, + "org.junit.platform:junit-platform-reporting": { + "shasums": { + "jar": "a0cdce1cc588fb902bdd08c7f24624ef72b131873eea09f063e6ee6ff453f654", + "sources": "3da58799df48f4a280f4e4ea7a92d5e97d2e357ac1b98885afc04a4445457713" + }, + "version": "1.10.0" + }, + "org.opentest4j:opentest4j": { + "shasums": { + "jar": "48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b", + "sources": "724a24e3a68267d5ebac9411389a15638a71e50c62448ffa58f59c34d5c1ebb2" + }, + "version": "1.3.0" } }, "dependencies": { + "junit:junit": [ + "org.hamcrest:hamcrest-core" + ], + "org.graalvm.buildtools:junit-platform-native": [ + "org.junit.jupiter:junit-jupiter", + "org.junit.platform:junit-platform-console", + "org.junit.platform:junit-platform-launcher" + ], "org.graalvm.compiler:compiler": [ "org.graalvm.sdk:collections", "org.graalvm.sdk:word", @@ -118,9 +224,91 @@ ], "org.graalvm.sdk:nativeimage": [ "org.graalvm.sdk:word" + ], + "org.junit.jupiter:junit-jupiter": [ + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter-params" + ], + "org.junit.jupiter:junit-jupiter-api": [ + "org.apiguardian:apiguardian-api", + "org.junit.platform:junit-platform-commons", + "org.opentest4j:opentest4j" + ], + "org.junit.jupiter:junit-jupiter-engine": [ + "org.apiguardian:apiguardian-api", + "org.junit.jupiter:junit-jupiter-api", + "org.junit.platform:junit-platform-engine" + ], + "org.junit.jupiter:junit-jupiter-params": [ + "org.apiguardian:apiguardian-api", + "org.junit.jupiter:junit-jupiter-api" + ], + "org.junit.platform:junit-platform-commons": [ + "org.apiguardian:apiguardian-api" + ], + "org.junit.platform:junit-platform-console": [ + "org.apiguardian:apiguardian-api", + "org.junit.platform:junit-platform-reporting" + ], + "org.junit.platform:junit-platform-engine": [ + "org.apiguardian:apiguardian-api", + "org.junit.platform:junit-platform-commons", + "org.opentest4j:opentest4j" + ], + "org.junit.platform:junit-platform-launcher": [ + "org.apiguardian:apiguardian-api", + "org.junit.platform:junit-platform-engine" + ], + "org.junit.platform:junit-platform-reporting": [ + "org.apiguardian:apiguardian-api", + "org.junit.platform:junit-platform-launcher" ] }, "packages": { + "junit:junit": [ + "junit.extensions", + "junit.framework", + "junit.runner", + "junit.textui", + "org.junit", + "org.junit.experimental", + "org.junit.experimental.categories", + "org.junit.experimental.max", + "org.junit.experimental.results", + "org.junit.experimental.runners", + "org.junit.experimental.theories", + "org.junit.experimental.theories.internal", + "org.junit.experimental.theories.suppliers", + "org.junit.internal", + "org.junit.internal.builders", + "org.junit.internal.matchers", + "org.junit.internal.requests", + "org.junit.internal.runners", + "org.junit.internal.runners.model", + "org.junit.internal.runners.rules", + "org.junit.internal.runners.statements", + "org.junit.matchers", + "org.junit.rules", + "org.junit.runner", + "org.junit.runner.manipulation", + "org.junit.runner.notification", + "org.junit.runners", + "org.junit.runners.model", + "org.junit.runners.parameterized", + "org.junit.validator" + ], + "org.apiguardian:apiguardian-api": [ + "org.apiguardian.api" + ], + "org.graalvm.buildtools:junit-platform-native": [ + "org.graalvm.junit.platform", + "org.graalvm.junit.platform.config.core", + "org.graalvm.junit.platform.config.jupiter", + "org.graalvm.junit.platform.config.platform", + "org.graalvm.junit.platform.config.util", + "org.graalvm.junit.platform.config.vintage" + ], "org.graalvm.compiler:compiler": [ "org.graalvm.compiler.api.directives", "org.graalvm.compiler.api.replacements", @@ -495,10 +683,109 @@ "com.oracle.truffle.compiler", "com.oracle.truffle.compiler.hotspot", "com.oracle.truffle.compiler.hotspot.libgraal" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest", + "org.hamcrest.core", + "org.hamcrest.internal" + ], + "org.junit.jupiter:junit-jupiter-api": [ + "org.junit.jupiter.api", + "org.junit.jupiter.api.condition", + "org.junit.jupiter.api.extension", + "org.junit.jupiter.api.extension.support", + "org.junit.jupiter.api.function", + "org.junit.jupiter.api.io", + "org.junit.jupiter.api.parallel" + ], + "org.junit.jupiter:junit-jupiter-engine": [ + "org.junit.jupiter.engine", + "org.junit.jupiter.engine.config", + "org.junit.jupiter.engine.descriptor", + "org.junit.jupiter.engine.discovery", + "org.junit.jupiter.engine.discovery.predicates", + "org.junit.jupiter.engine.execution", + "org.junit.jupiter.engine.extension", + "org.junit.jupiter.engine.support" + ], + "org.junit.jupiter:junit-jupiter-params": [ + "org.junit.jupiter.params", + "org.junit.jupiter.params.aggregator", + "org.junit.jupiter.params.converter", + "org.junit.jupiter.params.provider", + "org.junit.jupiter.params.shadow.com.univocity.parsers.annotations", + "org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.helpers", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.beans", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.fields", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.input", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.input.concurrent", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.iterators", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.processor.core", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.record", + "org.junit.jupiter.params.shadow.com.univocity.parsers.common.routine", + "org.junit.jupiter.params.shadow.com.univocity.parsers.conversions", + "org.junit.jupiter.params.shadow.com.univocity.parsers.csv", + "org.junit.jupiter.params.shadow.com.univocity.parsers.fixed", + "org.junit.jupiter.params.shadow.com.univocity.parsers.tsv", + "org.junit.jupiter.params.support" + ], + "org.junit.platform:junit-platform-commons": [ + "org.junit.platform.commons", + "org.junit.platform.commons.annotation", + "org.junit.platform.commons.function", + "org.junit.platform.commons.logging", + "org.junit.platform.commons.support", + "org.junit.platform.commons.util" + ], + "org.junit.platform:junit-platform-console": [ + "org.junit.platform.console", + "org.junit.platform.console.options", + "org.junit.platform.console.shadow.picocli", + "org.junit.platform.console.tasks" + ], + "org.junit.platform:junit-platform-engine": [ + "org.junit.platform.engine", + "org.junit.platform.engine.discovery", + "org.junit.platform.engine.reporting", + "org.junit.platform.engine.support.config", + "org.junit.platform.engine.support.descriptor", + "org.junit.platform.engine.support.discovery", + "org.junit.platform.engine.support.filter", + "org.junit.platform.engine.support.hierarchical", + "org.junit.platform.engine.support.store" + ], + "org.junit.platform:junit-platform-launcher": [ + "org.junit.platform.launcher", + "org.junit.platform.launcher.core", + "org.junit.platform.launcher.listeners", + "org.junit.platform.launcher.listeners.discovery", + "org.junit.platform.launcher.listeners.session", + "org.junit.platform.launcher.tagexpression" + ], + "org.junit.platform:junit-platform-reporting": [ + "org.junit.platform.reporting.legacy", + "org.junit.platform.reporting.legacy.xml", + "org.junit.platform.reporting.open.xml", + "org.junit.platform.reporting.shadow.org.opentest4j.reporting.events.api", + "org.junit.platform.reporting.shadow.org.opentest4j.reporting.events.core", + "org.junit.platform.reporting.shadow.org.opentest4j.reporting.events.java", + "org.junit.platform.reporting.shadow.org.opentest4j.reporting.events.root", + "org.junit.platform.reporting.shadow.org.opentest4j.reporting.schema" + ], + "org.opentest4j:opentest4j": [ + "org.opentest4j" ] }, "repositories": { "https://maven.pkg.st/": [ + "junit:junit", + "junit:junit:jar:sources", + "org.apiguardian:apiguardian-api", + "org.apiguardian:apiguardian-api:jar:sources", + "org.graalvm.buildtools:junit-platform-native", + "org.graalvm.buildtools:junit-platform-native:jar:sources", "org.graalvm.compiler:compiler", "org.graalvm.compiler:compiler:jar:sources", "org.graalvm.nativeimage:native-image-base", @@ -520,9 +807,37 @@ "org.graalvm.sdk:word", "org.graalvm.sdk:word:jar:sources", "org.graalvm.truffle:truffle-compiler", - "org.graalvm.truffle:truffle-compiler:jar:sources" + "org.graalvm.truffle:truffle-compiler:jar:sources", + "org.hamcrest:hamcrest-core", + "org.hamcrest:hamcrest-core:jar:sources", + "org.junit.jupiter:junit-jupiter", + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-api:jar:sources", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter-engine:jar:sources", + "org.junit.jupiter:junit-jupiter-params", + "org.junit.jupiter:junit-jupiter-params:jar:sources", + "org.junit.jupiter:junit-jupiter:jar:sources", + "org.junit.platform:junit-platform-commons", + "org.junit.platform:junit-platform-commons:jar:sources", + "org.junit.platform:junit-platform-console", + "org.junit.platform:junit-platform-console:jar:sources", + "org.junit.platform:junit-platform-engine", + "org.junit.platform:junit-platform-engine:jar:sources", + "org.junit.platform:junit-platform-launcher", + "org.junit.platform:junit-platform-launcher:jar:sources", + "org.junit.platform:junit-platform-reporting", + "org.junit.platform:junit-platform-reporting:jar:sources", + "org.opentest4j:opentest4j", + "org.opentest4j:opentest4j:jar:sources" ], "https://maven.google.com/": [ + "junit:junit", + "junit:junit:jar:sources", + "org.apiguardian:apiguardian-api", + "org.apiguardian:apiguardian-api:jar:sources", + "org.graalvm.buildtools:junit-platform-native", + "org.graalvm.buildtools:junit-platform-native:jar:sources", "org.graalvm.compiler:compiler", "org.graalvm.compiler:compiler:jar:sources", "org.graalvm.nativeimage:native-image-base", @@ -544,9 +859,37 @@ "org.graalvm.sdk:word", "org.graalvm.sdk:word:jar:sources", "org.graalvm.truffle:truffle-compiler", - "org.graalvm.truffle:truffle-compiler:jar:sources" + "org.graalvm.truffle:truffle-compiler:jar:sources", + "org.hamcrest:hamcrest-core", + "org.hamcrest:hamcrest-core:jar:sources", + "org.junit.jupiter:junit-jupiter", + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-api:jar:sources", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter-engine:jar:sources", + "org.junit.jupiter:junit-jupiter-params", + "org.junit.jupiter:junit-jupiter-params:jar:sources", + "org.junit.jupiter:junit-jupiter:jar:sources", + "org.junit.platform:junit-platform-commons", + "org.junit.platform:junit-platform-commons:jar:sources", + "org.junit.platform:junit-platform-console", + "org.junit.platform:junit-platform-console:jar:sources", + "org.junit.platform:junit-platform-engine", + "org.junit.platform:junit-platform-engine:jar:sources", + "org.junit.platform:junit-platform-launcher", + "org.junit.platform:junit-platform-launcher:jar:sources", + "org.junit.platform:junit-platform-reporting", + "org.junit.platform:junit-platform-reporting:jar:sources", + "org.opentest4j:opentest4j", + "org.opentest4j:opentest4j:jar:sources" ], "https://repo1.maven.org/maven2/": [ + "junit:junit", + "junit:junit:jar:sources", + "org.apiguardian:apiguardian-api", + "org.apiguardian:apiguardian-api:jar:sources", + "org.graalvm.buildtools:junit-platform-native", + "org.graalvm.buildtools:junit-platform-native:jar:sources", "org.graalvm.compiler:compiler", "org.graalvm.compiler:compiler:jar:sources", "org.graalvm.nativeimage:native-image-base", @@ -568,7 +911,29 @@ "org.graalvm.sdk:word", "org.graalvm.sdk:word:jar:sources", "org.graalvm.truffle:truffle-compiler", - "org.graalvm.truffle:truffle-compiler:jar:sources" + "org.graalvm.truffle:truffle-compiler:jar:sources", + "org.hamcrest:hamcrest-core", + "org.hamcrest:hamcrest-core:jar:sources", + "org.junit.jupiter:junit-jupiter", + "org.junit.jupiter:junit-jupiter-api", + "org.junit.jupiter:junit-jupiter-api:jar:sources", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter-engine:jar:sources", + "org.junit.jupiter:junit-jupiter-params", + "org.junit.jupiter:junit-jupiter-params:jar:sources", + "org.junit.jupiter:junit-jupiter:jar:sources", + "org.junit.platform:junit-platform-commons", + "org.junit.platform:junit-platform-commons:jar:sources", + "org.junit.platform:junit-platform-console", + "org.junit.platform:junit-platform-console:jar:sources", + "org.junit.platform:junit-platform-engine", + "org.junit.platform:junit-platform-engine:jar:sources", + "org.junit.platform:junit-platform-launcher", + "org.junit.platform:junit-platform-launcher:jar:sources", + "org.junit.platform:junit-platform-reporting", + "org.junit.platform:junit-platform-reporting:jar:sources", + "org.opentest4j:opentest4j", + "org.opentest4j:opentest4j:jar:sources" ] }, "version": "2" diff --git a/tools/bazel/cache.bazelrc b/tools/bazel/cache.bazelrc index 033730f2..3a7cb095 100644 --- a/tools/bazel/cache.bazelrc +++ b/tools/bazel/cache.bazelrc @@ -1,7 +1,8 @@ build:disk-cache --disk_cache=~/.cache/bazel -build:buildless --remote_cache=https://global.less.build +build:buildless --remote_cache=https://bazel.less.build +build:buildless --remote_upload_local_results=true build --modify_execution_info=PackageTar=+no-remote build --remote_local_fallback @@ -12,4 +13,3 @@ build --incompatible_default_to_explicit_init_py build --experimental_remote_merkle_tree_cache build --experimental_remote_cache_compression build --experimental_guard_against_concurrent_changes - diff --git a/tools/defs/BUILD.bazel b/tools/defs/BUILD.bazel new file mode 100644 index 00000000..e69de29b diff --git a/tools/defs/junit5.bzl b/tools/defs/junit5.bzl new file mode 100644 index 00000000..f40cbd9b --- /dev/null +++ b/tools/defs/junit5.bzl @@ -0,0 +1,50 @@ +"JUnit5 test support." + +load("@rules_java//java:defs.bzl", "java_test") + +def java_junit5_test(name, srcs, test_package, deps = [], runtime_deps = [], **kwargs): + """Define a JUnit 5 test. + + Args: + name: Name of the test target. + srcs: Sources for the test. + test_package: The package to test. + deps: List of dependencies. + runtime_deps: List of runtime dependencies. + **kwargs: Additional arguments to pass to java_test. + """ + + FILTER_KWARGS = [ + "main_class", + "use_testrunner", + "args", + ] + + for arg in FILTER_KWARGS: + if arg in kwargs.keys(): + kwargs.pop(arg) + + junit_console_args = [] + if test_package: + junit_console_args.extend([ + "--select-package", test_package + ]) + else: + junit_console_args.append("--scan-class-path") + + java_test( + name = name, + srcs = srcs, + use_testrunner = False, + main_class = "org.junit.platform.console.ConsoleLauncher", + args = junit_console_args, + deps = deps + [ + "@maven_gvm//:org_junit_jupiter_junit_jupiter_api", + "@maven_gvm//:org_junit_jupiter_junit_jupiter_params", + "@maven_gvm//:org_junit_jupiter_junit_jupiter_engine", + ], + runtime_deps = runtime_deps + [ + "@maven_gvm//:org_junit_platform_junit_platform_console", + ], + **kwargs + ) From 454dc5c41ddf4a930cb5664eb9983568bcce9ce7 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Sun, 14 Jan 2024 14:30:39 -0800 Subject: [PATCH 40/41] chore: relock bzlmod for tests Signed-off-by: Sam Gammon --- example/integration_tests/bzlmod/MODULE.bazel.lock | 2 +- example/integration_tests/components-ce/MODULE.bazel.lock | 2 +- example/integration_tests/components-oracle/MODULE.bazel.lock | 2 +- example/integration_tests/inert/MODULE.bazel.lock | 2 +- example/integration_tests/shared-lib/MODULE.bazel.lock | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/integration_tests/bzlmod/MODULE.bazel.lock b/example/integration_tests/bzlmod/MODULE.bazel.lock index a256ae6f..fcac14b4 100644 --- a/example/integration_tests/bzlmod/MODULE.bazel.lock +++ b/example/integration_tests/bzlmod/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" + "rules_graalvm": "661de9433891f4824dce2a9447e4532dd15f886e3bab30ad91a3a6ed8998bbcf" }, "moduleDepGraph": { "": { diff --git a/example/integration_tests/components-ce/MODULE.bazel.lock b/example/integration_tests/components-ce/MODULE.bazel.lock index a2e48a65..ea2bb7a7 100644 --- a/example/integration_tests/components-ce/MODULE.bazel.lock +++ b/example/integration_tests/components-ce/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" + "rules_graalvm": "661de9433891f4824dce2a9447e4532dd15f886e3bab30ad91a3a6ed8998bbcf" }, "moduleDepGraph": { "": { diff --git a/example/integration_tests/components-oracle/MODULE.bazel.lock b/example/integration_tests/components-oracle/MODULE.bazel.lock index 89e09d41..d3cdc10c 100644 --- a/example/integration_tests/components-oracle/MODULE.bazel.lock +++ b/example/integration_tests/components-oracle/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" + "rules_graalvm": "661de9433891f4824dce2a9447e4532dd15f886e3bab30ad91a3a6ed8998bbcf" }, "moduleDepGraph": { "": { diff --git a/example/integration_tests/inert/MODULE.bazel.lock b/example/integration_tests/inert/MODULE.bazel.lock index 678d4de6..747e78a8 100644 --- a/example/integration_tests/inert/MODULE.bazel.lock +++ b/example/integration_tests/inert/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" + "rules_graalvm": "661de9433891f4824dce2a9447e4532dd15f886e3bab30ad91a3a6ed8998bbcf" }, "moduleDepGraph": { "": { diff --git a/example/integration_tests/shared-lib/MODULE.bazel.lock b/example/integration_tests/shared-lib/MODULE.bazel.lock index a256ae6f..fcac14b4 100644 --- a/example/integration_tests/shared-lib/MODULE.bazel.lock +++ b/example/integration_tests/shared-lib/MODULE.bazel.lock @@ -14,7 +14,7 @@ }, "localOverrideHashes": { "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787", - "rules_graalvm": "dc53fbbe269b450a74414cc27a801d520fcbdeeeac04b1b0f9179ba111207326" + "rules_graalvm": "661de9433891f4824dce2a9447e4532dd15f886e3bab30ad91a3a6ed8998bbcf" }, "moduleDepGraph": { "": { From 72d7f6b8a7c13a23666e1c91ec5932a154912894 Mon Sep 17 00:00:00 2001 From: Sam Gammon Date: Thu, 25 Jan 2024 22:28:41 +0000 Subject: [PATCH 41/41] fix: expansion of profiles attr Signed-off-by: Sam Gammon --- internal/native_image/builder.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/native_image/builder.bzl b/internal/native_image/builder.bzl index c5ad0731..487126d4 100644 --- a/internal/native_image/builder.bzl +++ b/internal/native_image/builder.bzl @@ -364,7 +364,7 @@ def assemble_native_build_options( args, ctx.attr.include_resources, format = "-H:IncludeResources=%s", - context = ctx.attr.profiles, + context = ctx.attr.include_resources, ) # if a static build is being performed against hermetic zlib, configure it @@ -378,7 +378,7 @@ def assemble_native_build_options( if ctx.files.profiles: # pgo profiles support expansion args.add_joined( - _expand_vars(ctx, ctx.files.profiles, ctx.attr.profiles), + _expand_vars(ctx, [f.path for f in ctx.files.profiles], ctx.attr.profiles), join_with = ",", format_joined = "--pgo=%s", )