Skip to content

Commit

Permalink
fix: refactor to split classic vs modern rules
Browse files Browse the repository at this point in the history
- fix: unwind combined implementation of classic/modern rules
- fix: classic rules should preserve older functionality
- fix: modern rules should use modern toolchain env
- fix: wrapped/injected `env` while still supporting bazel4
- chore: re-factor commons between old/new rules

Signed-off-by: Sam Gammon <[email protected]>
  • Loading branch information
sgammon committed Sep 4, 2023
1 parent 298d1d9 commit fa2979b
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 178 deletions.
19 changes: 10 additions & 9 deletions graal/graal.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,29 @@ load(
"dicts",
)
load(
"//internal/native_image:rules.bzl",
"//internal/native_image:classic.bzl",
_BAZEL_CPP_TOOLCHAIN_TYPE = "BAZEL_CPP_TOOLCHAIN_TYPE",
_BAZEL_CURRENT_CPP_TOOLCHAIN = "BAZEL_CURRENT_CPP_TOOLCHAIN",
_DEFAULT_GVM_REPO = "DEFAULT_GVM_REPO",
_NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS",
_graal_binary_implementation = "graal_binary_implementation",
)

_DEFAULT_NATIVE_IMAGE_TOOL = Label("%s//:native-image" % _DEFAULT_GVM_REPO)

_native_image = rule(
implementation = _graal_binary_implementation,
attrs = dicts.add(_NATIVE_IMAGE_ATTRS, **{
"native_image_tool": attr.label(
cfg = "exec",
default = Label("%s//:native-image" % _DEFAULT_GVM_REPO),
default = _DEFAULT_NATIVE_IMAGE_TOOL,
allow_files = True,
executable = True,
mandatory = False,
),
"_cc_toolchain": attr.label(
default = Label(_BAZEL_CURRENT_CPP_TOOLCHAIN),
),
"_legacy_rule": attr.bool(
default = True,
),
}),
executable = True,
fragments = [
Expand Down Expand Up @@ -61,6 +60,7 @@ def native_image(
"@bazel_tools//src/conditions:windows": "%target%-bin.exe",
"//conditions:default": "%target%-bin",
}),
native_image_tool = _DEFAULT_NATIVE_IMAGE_TOOL,
**kwargs):

"""Generates and compiles a GraalVM native image from a Java library target.
Expand All @@ -81,6 +81,7 @@ def native_image(
c_compiler_option: Extra C compiler options to pass through `native-image`. No default; optional.
default_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`.
native_image_tool: Specific `native-image` executable target to use.
**kwargs: Extra keyword arguments are passed to the underlying `native_image` rule.
"""

Expand All @@ -99,10 +100,7 @@ def native_image(
check_toolchains = check_toolchains,
c_compiler_option = c_compiler_option,
default_executable_name = default_executable_name,
pass_compiler_path = select({
"@bazel_tools//src/conditions:windows": False,
"//conditions:default": True,
}),
native_image_tool = native_image_tool,
**kwargs
)

Expand All @@ -127,6 +125,7 @@ def graal_binary(
"@bazel_tools//src/conditions:windows": "%target%-bin.exe",
"//conditions:default": "%target%-bin",
}),
native_image_tool = _DEFAULT_NATIVE_IMAGE_TOOL,
**kwargs):

"""Alias for the renamed `native_image` rule. Identical.
Expand All @@ -147,6 +146,7 @@ def graal_binary(
c_compiler_option: Extra C compiler options to pass through `native-image`. No default; optional.
default_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`.
native_image_tool: Specific `native-image` executable target to use.
**kwargs: Extra keyword arguments are passed to the underlying `native_image` rule.
"""

Expand All @@ -165,5 +165,6 @@ def graal_binary(
check_toolchains = check_toolchains,
c_compiler_option = c_compiler_option,
default_executable_name = default_executable_name,
native_image_tool = native_image_tool,
**kwargs
)
5 changes: 1 addition & 4 deletions graalvm/nativeimage/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ _native_image = rule(
executable = True,
mandatory = False,
),
"_legacy_rule": attr.bool(
default = False,
),
"native_image_settings": attr.label_list(
providers = [[NativeImageInfo]],
mandatory = False,
Expand All @@ -48,7 +45,7 @@ _native_image = rule(
],
)

## Exports.
# Exports.
def native_image(name, **kwargs):
"""Macro which defines a GraalVM Native Image target."""
_native_image(
Expand Down
3 changes: 3 additions & 0 deletions internal/native_image/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ package(default_visibility = [
])

exports_files([
"builder.bzl",
"classic.bzl",
"common.bzl",
"rules.bzl",
"settings.bzl",
"toolchain.bzl",
Expand Down
66 changes: 66 additions & 0 deletions internal/native_image/builder.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"Logic to assemble `native-image` options."


def assemble_native_build_options(
ctx,
args,
binary,
classpath_depset,
direct_inputs,
c_compiler_path,
path_list_separator,
gvm_toolchain = None):
"""Assemble the effective arguments to `native-image`."""

args.add("--no-fallback")

# assemble classpath
args.add_joined("-cp", classpath_depset, join_with = path_list_separator)

if gvm_toolchain != None:
args.add(c_compiler_path, format = "--native-compiler-path=%s")

args.add(ctx.attr.main_class, format = "-H:Class=%s")
args.add(binary.basename.replace(".exe", ""), format = "-H:Name=%s")
args.add(binary.dirname, format = "-H:Path=%s")
args.add("-H:+ReportExceptionStackTraces")

if not ctx.attr.check_toolchains:
args.add("-H:-CheckToolchain")

for arg in ctx.attr.extra_args:
args.add(arg)

args.add_all(
ctx.attr.c_compiler_option,
format_each = "-H:CCompilerOption=%s",
)

args.add_joined(
ctx.attr.native_features,
join_with = ",",
format_joined = "-H:Features=%s",
)

args.add_joined(
ctx.attr.initialize_at_build_time,
join_with = ",",
format_joined = "--initialize-at-build-time=%s",
)
args.add_joined(
ctx.attr.initialize_at_run_time,
join_with = ",",
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.include_resources != None:
args.add(ctx.attr.include_resources, format = "-H:IncludeResources=%s")

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")
138 changes: 138 additions & 0 deletions internal/native_image/classic.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
"Legacy ('classic') rules for building with GraalVM on Bazel."

load(
"@bazel_skylib//lib:paths.bzl",
"paths",
)
load(
"@bazel_tools//tools/cpp:toolchain_utils.bzl",
"find_cpp_toolchain",
)
load(
"@bazel_tools//tools/build_defs/cc:action_names.bzl",
"CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME",
"CPP_LINK_EXECUTABLE_ACTION_NAME",
"CPP_LINK_STATIC_LIBRARY_ACTION_NAME",
"C_COMPILE_ACTION_NAME",
)
load(
"//internal/native_image:common.bzl",
_NATIVE_IMAGE_ATTRS = "NATIVE_IMAGE_ATTRS",
_BAZEL_CURRENT_CPP_TOOLCHAIN = "BAZEL_CURRENT_CPP_TOOLCHAIN",
_BAZEL_CPP_TOOLCHAIN_TYPE = "BAZEL_CPP_TOOLCHAIN_TYPE",
_GVM_TOOLCHAIN_TYPE = "GVM_TOOLCHAIN_TYPE",
_DEFAULT_GVM_REPO = "DEFAULT_GVM_REPO",
_RULES_REPO = "RULES_REPO",
_prepare_native_image_rule_context = "prepare_native_image_rule_context",
)

def _graal_binary_classic_implementation(ctx):
graal_attr = ctx.attr.native_image_tool
classpath_depset = depset(transitive = [
dep[JavaInfo].transitive_runtime_jars
for dep in ctx.attr.deps
])

direct_inputs = []
transitive_inputs = [classpath_depset]

if graal_attr != None:
# otherwise, use the legacy code path. the `graal` value is used in the run
# `executable` so it isn't listed in deps for earlier Bazel versions.
graal_inputs, _, _ = ctx.resolve_command(tools = [
graal_attr,
])
graal = graal_inputs[0]
direct_inputs.append(graal)
else:
# still failed to resolve: cannot resolve via either toolchains or attributes.
fail("""
No `native-image` tool found. Please either define a `native_image_tool` in your target,
or install a GraalVM `native-image` toolchain.
""")

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,
)
c_compiler_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = C_COMPILE_ACTION_NAME,
)
ld_executable_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
)
ld_static_lib_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
)
ld_dynamic_lib_path = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
)
transitive_inputs.append(cc_toolchain.all_files)

env = {}
path_set = {}
tool_paths = [c_compiler_path, ld_executable_path, ld_static_lib_path, ld_dynamic_lib_path]
for tool_path in tool_paths:
tool_dir, _, _ = tool_path.rpartition("/")
path_set[tool_dir] = None

paths = sorted(path_set.keys())
if ctx.configuration.host_path_separator == ":":
# HACK: ":" is a proxy for a UNIX-like host.
# The tools returned above may be bash scripts that reference commands
# in directories we might not otherwise include. For example,
# on macOS, wrapped_ar calls dirname.
if "/bin" not in path_set:
paths.append("/bin")
if "/usr/bin" not in path_set:
paths.append("/usr/bin")

# seal paths with hack above
env["PATH"] = ctx.configuration.host_path_separator.join(paths)
args = ctx.actions.args()
binary = _prepare_native_image_rule_context(
ctx,
args,
classpath_depset,
direct_inputs,
c_compiler_path,
)

inputs = depset(
direct_inputs,
transitive = transitive_inputs,
)
ctx.actions.run(
outputs = [binary],
arguments = [args],
executable = graal,
inputs = inputs,
mnemonic = "NativeImage",
env = env,
)

return [DefaultInfo(
executable = binary,
files = depset([binary]),
runfiles = ctx.runfiles(
collect_data = True,
collect_default = True,
files = [],
),
)]

# Exports.
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
graal_binary_implementation = _graal_binary_classic_implementation
Loading

0 comments on commit fa2979b

Please sign in to comment.