[infra] Use Bazel transitions to allow cc_binary to set their own flags
This will hopefully let us pre-package certain binaries (e.g. DM, fuzz) with more sensible defaults and not make the developer type out all the settings. For CanvasKit, which specifies its own build flags, I think I'll need to make another transition setup, which would go in something like modules/canvaskit/ck_binary_with_flags.bzl or something. Some sausage-case-names were converted to snake_case_names as per go/build-style#target-naming The example this is based off is worth a look through before diving into this: https://github.com/bazelbuild/examples/tree/main/rules/starlark_configurations/cc_binary_selectable_copts Change-Id: Ia919d47f4d1aa25cf294af7918e36d38838c179e Bug: skia:12541 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/472688 Reviewed-by: Ben Wagner <bungeman@google.com> Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
This commit is contained in:
parent
a526199541
commit
f3726c61d2
129
bazel/cc_binary_with_flags.bzl
Normal file
129
bazel/cc_binary_with_flags.bzl
Normal file
@ -0,0 +1,129 @@
|
||||
"""
|
||||
This file contains a way to set flags from BUILD.bazel instead of requiring users to set them from
|
||||
the CLI.
|
||||
|
||||
It is based off of https://github.com/bazelbuild/examples/tree/main/rules/starlark_configurations/cc_binary_selectable_copts
|
||||
|
||||
"""
|
||||
|
||||
_string_flags = [
|
||||
"//bazel/common_config_settings:fontmgr_factory",
|
||||
"//bazel/common_config_settings:with_gl_standard",
|
||||
]
|
||||
|
||||
_string_list_flags = [
|
||||
"//bazel/common_config_settings:gpu_backend",
|
||||
"//bazel/common_config_settings:include_decoder",
|
||||
"//bazel/common_config_settings:include_encoder",
|
||||
"//bazel/common_config_settings:include_fontmgr",
|
||||
]
|
||||
|
||||
# These are the flags that we support setting via set_flags
|
||||
_flags = _string_flags + _string_list_flags
|
||||
|
||||
def _flag_transition_impl(settings, attr):
|
||||
rv = {}
|
||||
for key in settings:
|
||||
# Get the short form of the name. This the short form used as the keys in the
|
||||
# set_flags dictionary.
|
||||
flag_name = key.split(":")[1]
|
||||
|
||||
# If there is an entry in set_flags for the short-version of a flag, use that
|
||||
# value or values. If not, use whatever value is set via flags.
|
||||
flag_setting = attr.set_flags.get(flag_name, settings[key])
|
||||
if key in _string_list_flags:
|
||||
if type(flag_setting) == "list":
|
||||
rv[key] = flag_setting
|
||||
else:
|
||||
rv[key] = [flag_setting] # This usually happens when the default value is used.
|
||||
elif key in _string_flags:
|
||||
if type(flag_setting) == "list":
|
||||
rv[key] = flag_setting[0]
|
||||
else:
|
||||
rv[key] = flag_setting # we know flag_setting is a string (e.g. the default).
|
||||
return rv
|
||||
|
||||
# This defines a Starlark transition and which flags it reads and writes.
|
||||
_flag_transition = transition(
|
||||
implementation = _flag_transition_impl,
|
||||
inputs = _flags,
|
||||
outputs = _flags,
|
||||
)
|
||||
|
||||
# The implementation of transition_rule: all this does is copy the cc_binary's output to
|
||||
# its own output and propagate its runfiles and executable to use for "$ bazel run".
|
||||
#
|
||||
# This makes transition_rule as close to a pure wrapper of cc_binary as possible.
|
||||
def _transition_rule_impl(ctx):
|
||||
actual_binary = ctx.attr.actual_binary[0]
|
||||
outfile = ctx.actions.declare_file(ctx.label.name)
|
||||
cc_binary_outfile = actual_binary[DefaultInfo].files.to_list()[0]
|
||||
|
||||
ctx.actions.run_shell(
|
||||
inputs = [cc_binary_outfile],
|
||||
outputs = [outfile],
|
||||
command = "cp %s %s" % (cc_binary_outfile.path, outfile.path),
|
||||
)
|
||||
return [
|
||||
DefaultInfo(
|
||||
executable = outfile,
|
||||
data_runfiles = actual_binary[DefaultInfo].data_runfiles,
|
||||
),
|
||||
]
|
||||
|
||||
# The purpose of this rule is to take a "set_flags" attribute, invoke a transition that sets
|
||||
# any of _flags to the specified values, then depend on a cc_binary whose deps will be able
|
||||
# to select() on those flags as if the user had set them via the CLI.
|
||||
transition_rule = rule(
|
||||
implementation = _transition_rule_impl,
|
||||
attrs = {
|
||||
# set_flags is a dictionary with the keys being the short-form of a flag name
|
||||
# (e.g. the part that comes after the colon) and the value being a list of values
|
||||
# that the flag should be set to, regardless of the relevant CLI flags.
|
||||
# https://docs.bazel.build/versions/main/skylark/lib/attr.html#string_list_dict
|
||||
"set_flags": attr.string_list_dict(),
|
||||
# This is the cc_binary whose deps will select() on that feature.
|
||||
# Note specifically how it is modified with _flag_transition, which
|
||||
# ensures that the flags propagates down the graph.
|
||||
# https://docs.bazel.build/versions/main/skylark/lib/attr.html#label
|
||||
"actual_binary": attr.label(cfg = _flag_transition),
|
||||
# This is a stock Bazel requirement for any rule that uses Starlark
|
||||
# transitions. It's okay to copy the below verbatim for all such rules.
|
||||
#
|
||||
# The purpose of this requirement is to give the ability to restrict
|
||||
# which packages can invoke these rules, since Starlark transitions
|
||||
# make much larger graphs possible that can have memory and performance
|
||||
# consequences for your build. The allowlist defaults to "everything".
|
||||
# But you can redefine it more strictly if you feel that's prudent.
|
||||
"_allowlist_function_transition": attr.label(
|
||||
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
|
||||
),
|
||||
},
|
||||
# Making this executable means it works with "$ bazel run".
|
||||
executable = True,
|
||||
)
|
||||
|
||||
def cc_binary_with_flags(name, cc_binary_name = "", set_flags = {}, **kwargs):
|
||||
"""Builds a cc_binary as if set_flags were set on the CLI.
|
||||
|
||||
Args:
|
||||
name: string, the name for the rule that is the binary, but with the flags changed via
|
||||
a transition. Any dependents should use this name.
|
||||
cc_binary_name: string, the name of the binary created (not the name of the transition
|
||||
rule). The default is the name with "_native_binary" as a suffix.
|
||||
set_flags: dictionary of string to list of strings. The keys should be the name of the
|
||||
flag, and the values should be the desired valid settings for that flag.
|
||||
**kwargs: Any flags that a cc_binary normally takes.
|
||||
"""
|
||||
if not cc_binary_name:
|
||||
cc_binary_name = name + "_native_binary"
|
||||
transition_rule(
|
||||
name = name,
|
||||
actual_binary = ":%s" % cc_binary_name,
|
||||
set_flags = set_flags,
|
||||
testonly = kwargs.get("testonly", False),
|
||||
)
|
||||
native.cc_binary(
|
||||
name = cc_binary_name,
|
||||
**kwargs
|
||||
)
|
@ -1,5 +1,6 @@
|
||||
load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary")
|
||||
load("//bazel/common_config_settings:defs.bzl", "bool_flag")
|
||||
load("//bazel:cc_binary_with_flags.bzl", "cc_binary_with_flags")
|
||||
|
||||
package(default_visibility = ["//:__subpackages__"])
|
||||
|
||||
@ -44,8 +45,8 @@ filegroup(
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gm-bindings",
|
||||
cc_binary_with_flags(
|
||||
name = "gm_bindings_with_flags",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"gm_bindings.cpp",
|
||||
@ -53,6 +54,7 @@ cc_binary(
|
||||
"//gm:gms", # Required for the registry to work
|
||||
],
|
||||
additional_linker_inputs = ["gm.js"],
|
||||
cc_binary_name = "gm_bindings",
|
||||
linkopts = select({
|
||||
"//bazel/common_config_settings:debug_build": BASE_LINKOPTS + GM_OPTS + DEBUG_OPTS,
|
||||
"//bazel/common_config_settings:release_build": BASE_LINKOPTS + GM_OPTS + RELEASE_OPTS,
|
||||
@ -62,6 +64,20 @@ cc_binary(
|
||||
"SK_GL",
|
||||
"SK_USE_WEBGL",
|
||||
],
|
||||
set_flags = {
|
||||
"include_decoder": [
|
||||
"jpeg_decode_codec",
|
||||
"png_decode_codec",
|
||||
"webp_decode_codec",
|
||||
"gif_decode_codec",
|
||||
],
|
||||
"gpu_backend": [
|
||||
"gl_backend",
|
||||
],
|
||||
"with_gl_standard": [
|
||||
"webgl_standard",
|
||||
],
|
||||
},
|
||||
# This target won't build successfully on its own because of missing emscripten
|
||||
# headers etc. Therefore, we hide it from wildcards.
|
||||
tags = ["manual"],
|
||||
@ -73,9 +89,9 @@ cc_binary(
|
||||
)
|
||||
|
||||
wasm_cc_binary(
|
||||
name = "gm-bindings-wasm",
|
||||
name = "gm_bindings_wasm",
|
||||
testonly = True,
|
||||
cc_target = ":gm-bindings",
|
||||
cc_target = ":gm_bindings_with_flags",
|
||||
)
|
||||
|
||||
# See https://stackoverflow.com/a/57499321 for reference.
|
||||
@ -229,12 +245,40 @@ CK_SRCS = [
|
||||
":include_embedded_font_false": [],
|
||||
})
|
||||
|
||||
cc_binary(
|
||||
name = "canvaskit",
|
||||
cc_binary_with_flags(
|
||||
name = "canvaskit_with_flags",
|
||||
srcs = CK_SRCS,
|
||||
additional_linker_inputs = JS_INTERFACE_FILES,
|
||||
# wasm_cc_binary makes the canvaskit.js/canvaskit.wasm based on the actual name
|
||||
# of the executable.
|
||||
cc_binary_name = "canvaskit",
|
||||
linkopts = CK_OPTS,
|
||||
local_defines = CK_DEFINES,
|
||||
set_flags = {
|
||||
"include_decoder": [
|
||||
"jpeg_decode_codec",
|
||||
"png_decode_codec",
|
||||
"webp_decode_codec",
|
||||
"gif_decode_codec",
|
||||
],
|
||||
"include_encoder": [
|
||||
"jpeg_encode_codec",
|
||||
"png_encode_codec",
|
||||
],
|
||||
# TODO(kjlubick) make this optional, depending on enable_fonts
|
||||
"fontmgr_factory": [
|
||||
"custom_embedded_fontmgr_factory",
|
||||
],
|
||||
"include_fontmgr": [
|
||||
"custom_embedded_fontmgr",
|
||||
],
|
||||
"gpu_backend": [
|
||||
"gl_backend",
|
||||
],
|
||||
"with_gl_standard": [
|
||||
"webgl_standard",
|
||||
],
|
||||
},
|
||||
# This target won't build successfully on its own because of missing emscripten
|
||||
# headers etc. Therefore, we hide it from wildcards.
|
||||
tags = ["manual"],
|
||||
@ -244,8 +288,8 @@ cc_binary(
|
||||
)
|
||||
|
||||
wasm_cc_binary(
|
||||
name = "canvaskit-wasm",
|
||||
cc_target = ":canvaskit",
|
||||
name = "canvaskit_wasm",
|
||||
cc_target = ":canvaskit_with_flags",
|
||||
)
|
||||
|
||||
bool_flag(
|
||||
|
@ -129,37 +129,24 @@ bazel_gms_release:
|
||||
# unit, by letting the cache be used (and not dropped from the sandbox), which gets expensive.
|
||||
# Local testing showed using the local strategy sped up a clean build from 9.5 minutes
|
||||
# to 1 minute. https://docs.bazel.build/versions/main/user-manual.html#strategy-options
|
||||
bazelisk build :gm-bindings-wasm --compilation_mode opt --spawn_strategy=local \
|
||||
--gpu_backend=gl_backend --with_gl_standard=webgl_standard \
|
||||
--include_decoder=jpeg_decode_codec --include_decoder=png_decode_codec \
|
||||
--include_decoder=webp_decode_codec --include_decoder=gif_decode_codec
|
||||
bazelisk build :gm_bindings_wasm --compilation_mode opt --spawn_strategy=local
|
||||
- rm -rf build/
|
||||
mkdir build
|
||||
cp ../../bazel-bin/modules/canvaskit/gm-bindings-wasm/gm-bindings.js build/gm-bindings.js
|
||||
cp ../../bazel-bin/modules/canvaskit/gm-bindings-wasm/gm-bindings.wasm build/gm-bindings.wasm
|
||||
cp ../../bazel-bin/modules/canvaskit/gm_bindings_wasm/gm_bindings.js build/gm_bindings.js
|
||||
cp ../../bazel-bin/modules/canvaskit/gm_bindings_wasm/gm_bindings.wasm build/gm_bindings.wasm
|
||||
|
||||
bazel_gms_debug:
|
||||
# See above note about spawn_strategy
|
||||
bazelisk build :gm-bindings-wasm --compilation_mode dbg --spawn_strategy=local \
|
||||
--gpu_backend=gl_backend --with_gl_standard=webgl_standard \
|
||||
--include_decoder=jpeg_decode_codec --include_decoder=png_decode_codec \
|
||||
--include_decoder=webp_decode_codec --include_decoder=gif_decode_codec
|
||||
bazelisk build :gm_bindings_wasm --compilation_mode dbg --spawn_strategy=local
|
||||
- rm -rf build/
|
||||
mkdir build
|
||||
cp ../../bazel-bin/modules/canvaskit/gm-bindings-wasm/gm-bindings.js build/gm-bindings.js
|
||||
cp ../../bazel-bin/modules/canvaskit/gm-bindings-wasm/gm-bindings.wasm build/gm-bindings.wasm
|
||||
cp ../../bazel-bin/modules/canvaskit/gm_bindings_wasm/gm_bindings.js build/gm_bindings.js
|
||||
cp ../../bazel-bin/modules/canvaskit/gm_bindings_wasm/gm_bindings.wasm build/gm_bindings.wasm
|
||||
|
||||
bazel_canvaskit_debug:
|
||||
# See above note about spawn_strategy
|
||||
# TODO(kjlubick): Can we use transitions to have defaults set?
|
||||
# https://github.com/bazelbuild/examples/tree/main/rules/starlark_configurations/cc_binary_selectable_copts
|
||||
bazelisk build :canvaskit-wasm --compilation_mode dbg --spawn_strategy=local \
|
||||
--gpu_backend=gl_backend --with_gl_standard=webgl_standard \
|
||||
--include_decoder=jpeg_decode_codec --include_decoder=png_decode_codec \
|
||||
--include_decoder=webp_decode_codec --include_decoder=gif_decode_codec \
|
||||
--include_encoder=jpeg_encode_codec --include_encoder=png_encode_codec \
|
||||
--include_fontmgr=custom_embedded_fontmgr --fontmgr_factory=custom_embedded_fontmgr_factory
|
||||
bazelisk build :canvaskit_wasm --compilation_mode dbg --spawn_strategy=local
|
||||
- rm -rf build/
|
||||
mkdir build
|
||||
cp ../../bazel-bin/modules/canvaskit/canvaskit-wasm/canvaskit.js build/canvaskit.js
|
||||
cp ../../bazel-bin/modules/canvaskit/canvaskit-wasm/canvaskit.wasm build/canvaskit.wasm
|
||||
cp ../../bazel-bin/modules/canvaskit/canvaskit_wasm/canvaskit.js build/canvaskit.js
|
||||
cp ../../bazel-bin/modules/canvaskit/canvaskit_wasm/canvaskit.wasm build/canvaskit.wasm
|
||||
|
@ -4,7 +4,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<script type="text/javascript" src="/build/gm-bindings.js"></script>
|
||||
<script type="text/javascript" src="/build/gm_bindings.js"></script>
|
||||
|
||||
<p id="log"></p>
|
||||
<!-- Makes png visible to user -->
|
||||
|
@ -69,6 +69,7 @@ filegroup(
|
||||
"codegen/SkSLSPIRVtoHLSL.h",
|
||||
"codegen/SkSLVMCodeGenerator.cpp",
|
||||
"codegen/SkSLVMCodeGenerator.h",
|
||||
"codegen/SkVMDebugInfo.h",
|
||||
"dsl/DSLBlock.cpp",
|
||||
"dsl/DSLCase.cpp",
|
||||
"dsl/DSLCore.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user