Bazel: Make generator configurable

This change introduces an experimental `generator_version` attribute to the
`sapi_library()` rule. Version `1` will select the current interface
generator, which is based on libclang and Python. Setting the attribute to
version `2`, will select the newer interface generator written in C++ that
uses a full clang compiler frontend for parsing. Both emit equivalent header
output, differences in parsing and/or edge cases notwithstanding.

The default, as of now, is still the old version `1` generator.

Note: CMake allows to select the new interface generator globally by setting
`SAPI_ENABLE_GENERATOR`.
PiperOrigin-RevId: 438765013
Change-Id: I69c49a6bcf1751724edb0bce5c3b2beea2097138
This commit is contained in:
Christian Blichmann 2022-04-01 01:34:18 -07:00 committed by Copybara-Service
parent 5d7ea8dd28
commit 4b2c730c5e
3 changed files with 45 additions and 23 deletions

View File

@ -38,6 +38,20 @@ def append_all(arguments, name, values):
def get_embed_dir(): def get_embed_dir():
return native.package_name() return native.package_name()
def make_exec_label(label):
return attr.label(
default = label,
cfg = "exec",
allow_files = True,
executable = True,
)
# buildifier: disable=function-docstring
def select_generator(ctx):
if ctx.attr.generator_version == 1:
return ctx.executable._generator_v1
return ctx.executable._generator_v2
def sort_deps(deps): def sort_deps(deps):
"""Sorts a list of dependencies. """Sorts a list of dependencies.
@ -49,16 +63,16 @@ def sort_deps(deps):
Returns: Returns:
A sorted list of dependencies, with local deps (starting with ":") first. A sorted list of dependencies, with local deps (starting with ":") first.
""" """
deps = depset(deps).to_list() deps = depset(deps).to_list()
colon_deps = [x for x in deps if x.startswith(":")] colon_deps = [x for x in deps if x.startswith(":")]
other_deps = [x for x in deps if not x.startswith(":")] other_deps = [x for x in deps if not x.startswith(":")]
return sorted(colon_deps) + sorted(other_deps) return sorted(colon_deps) + sorted(other_deps)
def sapi_interface_impl(ctx): def _sapi_interface_impl(ctx):
"""Implementation of build rule that generates SAPI interface."""
cpp_toolchain = find_cpp_toolchain(ctx) cpp_toolchain = find_cpp_toolchain(ctx)
use_clang_generator = ctx.executable.generator.basename == "generator_tool" generator = select_generator(ctx)
use_clang_generator = ctx.attr.generator_version == 2
# TODO(szwl): warn if input_files is not set and we didn't find anything # TODO(szwl): warn if input_files is not set and we didn't find anything
input_files_paths = [] input_files_paths = []
@ -137,13 +151,14 @@ def sapi_interface_impl(ctx):
inputs = input_files, inputs = input_files,
outputs = [ctx.outputs.out], outputs = [ctx.outputs.out],
arguments = args, arguments = args,
mnemonic = "SapiInterfaceGen",
progress_message = progress_msg, progress_message = progress_msg,
executable = ctx.executable.generator, executable = generator,
) )
# Build rule that generates SAPI interface. # Build rule that generates SAPI interface.
sapi_interface = rule( sapi_interface = rule(
implementation = sapi_interface_impl, implementation = _sapi_interface_impl,
attrs = { attrs = {
"out": attr.output(mandatory = True), "out": attr.output(mandatory = True),
"embed_dir": attr.string(), "embed_dir": attr.string(),
@ -167,11 +182,16 @@ sapi_interface = rule(
default = 1, default = 1,
values = [1], # Only a single version is defined right now values = [1], # Only a single version is defined right now
), ),
"generator": attr.label( "generator_version": attr.int(
executable = True, default = 1,
cfg = "host", values = [1, 2],
allow_files = True, ),
default = Label("//sandboxed_api/tools/generator2:sapi_generator"), "_generator_v1": make_exec_label(
"//sandboxed_api/tools/generator2:sapi_generator",
),
"_generator_v2": make_exec_label(
# TODO(cblichmann): Add prebuilt version of Clang based generator
"//sandboxed_api/tools/clang_generator:generator_tool",
), ),
"_cc_toolchain": attr.label( "_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
@ -197,7 +217,7 @@ def sapi_library(
input_files = [], input_files = [],
deps = [], deps = [],
tags = [], tags = [],
generator_executable = "//sandboxed_api/tools/generator2:sapi_generator", generator_version = 1,
visibility = None): visibility = None):
"""Provides the implementation of a Sandboxed API library. """Provides the implementation of a Sandboxed API library.
@ -223,8 +243,10 @@ def sapi_library(
should scan for function declarations should scan for function declarations
deps: Extra dependencies to add to the SAPI library deps: Extra dependencies to add to the SAPI library
tags: Extra tags to associate with the target tags: Extra tags to associate with the target
generator_executable: Label of the SAPI interface generator to use generator_version: Which version the the interface generator to use
(experimental). (experimental). Version 1 uses the Python/libclang based `generator2`,
version 2 uses the newer C++ implementation that uses the full clang
compiler front-end for parsing. Both emit equivalent Sandboxed APIs.
visibility: Target visibility visibility: Target visibility
""" """
@ -320,7 +342,7 @@ def sapi_library(
embed_dir = embed_dir, embed_dir = embed_dir,
namespace = namespace, namespace = namespace,
api_version = api_version, api_version = api_version,
generator = generator_executable, generator_version = generator_version,
limit_scan_depth = limit_scan_depth, limit_scan_depth = limit_scan_depth,
**common **common
) )

View File

@ -32,6 +32,8 @@ cc_library(
], ],
copts = sapi_platform_copts(), copts = sapi_platform_copts(),
deps = [ deps = [
"//sandboxed_api/util:fileops",
"//sandboxed_api/util:status",
"@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:btree",
"@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
@ -49,8 +51,6 @@ cc_library(
"@llvm-project//clang:lex", "@llvm-project//clang:lex",
"@llvm-project//clang:tooling", "@llvm-project//clang:tooling",
"@llvm-project//llvm:Support", "@llvm-project//llvm:Support",
"//sandboxed_api/util:fileops",
"//sandboxed_api/util:status",
], ],
) )
@ -64,18 +64,18 @@ cc_test(
copts = sapi_platform_copts(), copts = sapi_platform_copts(),
deps = [ deps = [
":generator", ":generator",
"@com_google_googletest//:gtest_main", "//sandboxed_api:testing",
"//sandboxed_api/util:status_matchers",
"@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor", "@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
"@llvm-project//clang:basic", "@llvm-project//clang:basic",
"@llvm-project//clang:frontend", "@llvm-project//clang:frontend",
"@llvm-project//clang:tooling", "@llvm-project//clang:tooling",
"@llvm-project//llvm:Support", "@llvm-project//llvm:Support",
"//sandboxed_api:testing",
"//sandboxed_api/util:status_matchers",
], ],
) )
@ -91,6 +91,9 @@ cc_binary(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":generator", ":generator",
"//sandboxed_api/util:file_helpers",
"//sandboxed_api/util:fileops",
"//sandboxed_api/util:status",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",
"@com_google_absl//absl/status", "@com_google_absl//absl/status",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
@ -100,8 +103,5 @@ cc_binary(
"@llvm-project//clang:frontend", "@llvm-project//clang:frontend",
"@llvm-project//clang:tooling", "@llvm-project//clang:tooling",
"@llvm-project//llvm:Support", "@llvm-project//llvm:Support",
"//sandboxed_api/util:file_helpers",
"//sandboxed_api/util:fileops",
"//sandboxed_api/util:status",
], ],
) )