blob: cdfd501de77851d46474577b51cd9fa6a6612e1b [file] [log] [blame]
# Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Genrule which provides Apple's Xcode environment."""
load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("//lib:apple_support.bzl", "apple_support")
def _compute_make_variables(
genfiles_dir,
label,
resolved_srcs,
files_to_build):
resolved_srcs_list = resolved_srcs.to_list()
variables = {
"OUTS": " ".join([x.path for x in files_to_build]),
"SRCS": " ".join([x.path for x in resolved_srcs_list]),
}
if len(resolved_srcs_list) == 1:
variables["<"] = resolved_srcs_list[0].path
if len(files_to_build) == 1:
variables["@"] = files_to_build[0].path
variables["@D"] = files_to_build[0].dirname
else:
variables["@D"] = genfiles_dir.path + "/" + label.package
return variables
def _apple_genrule_impl(ctx):
if not ctx.outputs.outs:
fail("apple_genrule must have one or more outputs", attr = "outs")
files_to_build = ctx.outputs.outs
if ctx.attr.executable and len(files_to_build) > 1:
fail(
"if genrules produce executables, they are allowed only one output. " +
"If you need the executable=1 argument, then you should split this " +
"genrule into genrules producing single outputs",
attr = "executable",
)
resolved_srcs = depset(transitive = [dep[DefaultInfo].files for dep in ctx.attr.srcs])
label_dict = {dep.label: dep[DefaultInfo].files.to_list() for dep in ctx.attr.srcs}
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
resolved_inputs, argv, runfiles_manifests = ctx.resolve_command(
command = ctx.attr.cmd,
attribute = "cmd",
expand_locations = True,
make_variables = _compute_make_variables(
ctx.genfiles_dir,
ctx.label,
resolved_srcs,
files_to_build,
),
tools = ctx.attr.tools,
label_dict = label_dict,
execution_requirements = xcode_config.execution_info(),
)
message = ctx.attr.message or "Executing apple_genrule"
extra_args = {}
if ctx.attr.no_sandbox:
extra_args["execution_requirements"] = {"no-sandbox": "1"}
apple_support.run(
actions = ctx.actions,
xcode_config = xcode_config,
apple_fragment = ctx.fragments.apple,
executable = argv[0],
arguments = argv[1:],
inputs = depset(resolved_inputs, transitive = [resolved_srcs]),
outputs = files_to_build,
env = ctx.configuration.default_shell_env,
progress_message = "%s %s" % (message, ctx.label),
mnemonic = "Genrule",
input_manifests = runfiles_manifests,
**extra_args
)
return [
DefaultInfo(
files = depset(files_to_build),
data_runfiles = ctx.runfiles(files = files_to_build),
),
]
# NOTE: This likely could have used `name = "apple_genrule"` and stayed in the
# other bzl file, but this way something like a stardoc shim can directly load
# it and generate from here instead of the macro.
apple_genrule = rule(
implementation = _apple_genrule_impl,
attrs = dicts.add(apple_support.action_required_attrs(), {
"cmd": attr.string(
mandatory = True,
doc = "The command to run. Subject the variable substitution.",
),
"executable": attr.bool(
default = False,
doc = """\
Declare output to be executable. Setting this flag to 1 means the output is an
executable file and can be run using the run command. The genrule must produce
exactly one output in this case.
""",
),
"outs": attr.output_list(
allow_empty = False,
mandatory = True,
doc = """\
A list of files generated by this rule. If the executable flag is set, outs must
contain exactly one label.
""",
),
"srcs": attr.label_list(
allow_files = True,
doc = "A list of inputs for this rule, such as source files to process.",
),
"message": attr.string(
doc = "A progress message to be reported as the rule runs.",
),
"tools": attr.label_list(
cfg = "exec",
allow_files = True,
doc = """\
A list of tool dependencies for this rule, they will be available when the
action is run.
""",
),
"no_sandbox": attr.bool(
doc = "If the sandbox should be disabled when the action is run.",
),
}),
doc = """\
Genrule which provides Apple specific environment and make variables.
This mirrors the native genrule except that it provides a different set of
make variables. This rule will only run on a Mac.
Example of use:
```
load("@build_bazel_apple_support//rules:apple_genrule.bzl", "apple_genrule")
apple_genrule(
name = "world",
outs = ["hi"],
cmd = "touch $@",
)
```
This rule also does location expansion, much like the native genrule.
For example, `$(location hi)` may be used to refer to the output in the
above example.
The set of make variables that are supported for this rule:
* `OUTS`: The outs list. If you have only one output file, you can also use
`$@`.
* `SRCS`: The srcs list (or more precisely, the pathnames of the files
corresponding to labels in the srcs list). If you have only one
source file, you can also use `$<`.
* `<`: srcs, if it's a single file.
* `@`: outs, if it's a single file.
* `@D`: The output directory. If there is only one filename in outs, this
expands to the directory containing that file. If there are
multiple filenames, this variable instead expands to the package's
root directory in the genfiles tree, even if all the generated
files belong to the same subdirectory.
The following environment variables are defined when the rule is executed:
* `DEVELOPER_DIR`: The base developer directory as defined on Apple
architectures, most commonly used in invoking Apple
tools such as xcrun.
* `SDKROOT`: The base SDK directory as defined on Apple architectures, most
commonly used in invoking Apple tools such as xcrun.
NOTE: `DEVELOPER_DIR` and `SDKROOT` are environment variables and *not* make
variables. To refer to them in `cmd` you must use environment variable
syntax (i.e. using `$$`). Example: ```cmd = "xcrun --sdkroot $$SDKROOT clang...```
""",
exec_compatible_with = ["@platforms//os:macos"],
output_to_genfiles = True,
fragments = ["apple"],
)