Skip to content

Commit

Permalink
feat: shared headers, rules_cc support
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
sgammon committed Jan 2, 2024
1 parent 89f035e commit 5643f21
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 8 deletions.
5 changes: 4 additions & 1 deletion docs/api/defs.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ native_image(<a href="#native_image-name">name</a>, <a href="#native_image-deps"
<a href="#native_image-jni_configuration">jni_configuration</a>, <a href="#native_image-initialize_at_build_time">initialize_at_build_time</a>, <a href="#native_image-initialize_at_run_time">initialize_at_run_time</a>, <a href="#native_image-native_features">native_features</a>,
<a href="#native_image-debug">debug</a>, <a href="#native_image-optimization_mode">optimization_mode</a>, <a href="#native_image-shared_library">shared_library</a>, <a href="#native_image-static_zlib">static_zlib</a>, <a href="#native_image-c_compiler_option">c_compiler_option</a>, <a href="#native_image-data">data</a>,
<a href="#native_image-extra_args">extra_args</a>, <a href="#native_image-allow_fallback">allow_fallback</a>, <a href="#native_image-check_toolchains">check_toolchains</a>, <a href="#native_image-native_image_tool">native_image_tool</a>, <a href="#native_image-native_image_settings">native_image_settings</a>,
<a href="#native_image-profiles">profiles</a>, <a href="#native_image-kwargs">kwargs</a>)
<a href="#native_image-profiles">profiles</a>, <a href="#native_image-out_headers">out_headers</a>, <a href="#native_image-additional_outputs">additional_outputs</a>, <a href="#native_image-default_outputs">default_outputs</a>, <a href="#native_image-kwargs">kwargs</a>)
</pre>

Generates and compiles a GraalVM native image from a Java library target.
Expand Down Expand Up @@ -43,6 +43,9 @@ Generates and compiles a GraalVM native image from a Java library target.
| <a id="native_image-native_image_tool"></a>native_image_tool | Specific `native-image` executable target to use. | `None` |
| <a id="native_image-native_image_settings"></a>native_image_settings | Suite(s) of Native Image build settings to use. | `[Label("@rules_graalvm//internal/native_image:defaults")]` |
| <a id="native_image-profiles"></a>profiles | Profiles to use for profile-guided optimization (PGO) and obtained from a native image compiled with `--pgo-instrument`. | `[]` |
| <a id="native_image-out_headers"></a>out_headers | Shared library headers expected to be emitted by the rule (in addition to defaults). | `[]` |
| <a id="native_image-additional_outputs"></a>additional_outputs | Additional outputs to expect from the rule (for example, polyglot language resources). | `[]` |
| <a id="native_image-default_outputs"></a>default_outputs | Whether to consider default output files; when `False`, the developer specifies all outputs on top of the binary itself. | `True` |
| <a id="native_image-kwargs"></a>kwargs | Extra keyword arguments are passed to the underlying `native_image` rule. | none |


16 changes: 15 additions & 1 deletion graalvm/nativeimage/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ 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",
Expand Down Expand Up @@ -53,7 +57,7 @@ _native_image = rule(
"platform",
"xcode",
],
toolchains = [
toolchains = use_cpp_toolchain() + [
_BAZEL_CPP_TOOLCHAIN_TYPE,
_GVM_TOOLCHAIN_TYPE,
],
Expand Down Expand Up @@ -83,6 +87,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.
Expand Down Expand Up @@ -111,10 +118,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.
"""

Expand All @@ -141,5 +152,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
)
5 changes: 3 additions & 2 deletions internal/native_image/classic.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,22 @@ 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,
transitive = transitive_inputs,
)

ctx.actions.run(
outputs = [binary],
outputs = outputs,
arguments = [args],
executable = graal,
inputs = inputs,
Expand Down
19 changes: 18 additions & 1 deletion internal/native_image/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ _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(
Expand Down Expand Up @@ -113,6 +115,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),
),
Expand Down Expand Up @@ -154,6 +161,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.
Expand All @@ -162,6 +172,13 @@ 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)

_assemble_native_build_options(
ctx,
args,
Expand All @@ -173,7 +190,7 @@ def _prepare_native_image_rule_context(
gvm_toolchain,
bin_postfix,
)
return binary
return outputs

## Exports.

Expand Down
52 changes: 49 additions & 3 deletions internal/native_image/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ 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",
Expand Down Expand Up @@ -103,7 +107,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,
Expand All @@ -112,14 +116,15 @@ def _graal_binary_implementation(ctx):
gvm_toolchain,
bin_postfix = bin_postfix,
)
binary = all_outputs[0]

# assemble final inputs
inputs = depset(
direct_inputs,
transitive = transitive_inputs,
)
run_params = {
"outputs": [binary],
"outputs": all_outputs,
"executable": graal,
"inputs": inputs,
"mnemonic": "NativeImage",
Expand Down Expand Up @@ -159,6 +164,45 @@ def _graal_binary_implementation(ctx):
**run_params
)

# if we are building a shared library, prepare `CcInfo` for it, taking care to merge/forward
# our static dependencies.
cc_info = None
if ctx.attr.shared_library:
cc_toolchain = find_cpp_toolchain(ctx)
out_lib = binary
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
linker_input = cc_common.create_linker_input(
owner = ctx.label,
libraries = depset(direct = [
cc_common.create_library_to_link(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
dynamic_library = out_lib,
),
]),
)
compilation_context = cc_common.create_compilation_context()
linking_context = cc_common.create_linking_context(
linker_inputs = depset(direct = [linker_input]),
)
cc_info = cc_common.merge_cc_infos(cc_infos = [
CcInfo(
compilation_context = compilation_context,
linking_context = linking_context,
),
] + [
dep[CcInfo] for dep in ctx.attr.deps if CcInfo in dep]
)
# TODO(sgammon): static zlib?



return [DefaultInfo(
executable = binary,
files = depset([binary]),
Expand All @@ -167,7 +211,9 @@ def _graal_binary_implementation(ctx):
collect_default = True,
files = [],
),
)]
)] + (
cc_info and [cc_info] or []
)

def _wrap_actions_for_graal(actions):
"""Wraps the given ctx.actions struct so that env variables are correctly passed to Graal."""
Expand Down

0 comments on commit 5643f21

Please sign in to comment.