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 <sam@elide.ventures>
  • Loading branch information
sgammon committed Jan 2, 2024
1 parent 89f035e commit ad11d1e
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 20 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 |


18 changes: 15 additions & 3 deletions graalvm/nativeimage/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -53,8 +56,7 @@ _native_image = rule(
"platform",
"xcode",
],
toolchains = [
_BAZEL_CPP_TOOLCHAIN_TYPE,
toolchains = use_cpp_toolchain() + [
_GVM_TOOLCHAIN_TYPE,
],
)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
"""

Expand All @@ -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
)
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
33 changes: 30 additions & 3 deletions internal/native_image/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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),
),
Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -173,7 +201,7 @@ def _prepare_native_image_rule_context(
gvm_toolchain,
bin_postfix,
)
return binary
return outputs

## Exports.

Expand All @@ -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
Expand Down
61 changes: 50 additions & 11 deletions internal/native_image/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand All @@ -112,14 +115,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,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):
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit ad11d1e

Please sign in to comment.