Is there a splat operator in Starlark / Bazel? - bazel

Is there a splat operator in Bazel? Like pythons *, or Javacripts ...?
I'm interested in the case where I need to unpack a list into another. What I would like to achieve is something like this:
some_rule (
name = "target_name",
src = [
"file1.txt",
"file2.txt",
*get_more_files()
]
)
In this example get_more_files would return a list of file names, which would be unpacked into src and sit alongside file1.txt and file2.txt.
Note: I am aware of the extend method.

srcs = [ .. ] + get_more_files()
should do the job

Related

Is there a rule representing an ECMAScript library in Bazel rules_nodejs?

Most of my code is represented by ECMA Script libraries that have import and export rather than require statements.
Is there a suggested way to represent such libraries using rules_dotnet?
I am looking for something like this:
load("#build_bazel_rules_nodejs//:index.bzl", "ecmascript_library")
ecmascript_library(
name = "foo",
srcs = [
"foo.js"
],
)
ecmascript_library(
name = "bar",
srcs = [
"bar.js"
],
deps = [
":foo",
],
)
Where Bazel will ensure the search paths for rules consuming bar can find foo.
I would then like to use my library definitions to create bundles for Node.js etc.
How can I accomplish this?

Apply cpu transition to cc_binary rule in Bazel

I've a c target that always must be compiled for darwin_x86_64, no matter the --cpu set when calling bazel build. It's the only target that always must be compiled for a specific cpu in a big project.
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
In the bazel documentation it seems to be possible to do this using transitions. Maybe something like:
def _force_x86_64_impl(settings, attr):
return {"//command_line_option:cpu": "darwin_x86_64"}
force_x86_64 = transition(
implementation = _force_x86_64_impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
)
But how do I tie these two together? I'm probably missing something obvious, but I can't seem to find the relevant documentation over at bazel.build.
You've got the transition defined, now you need to attach it to a rule.
r = rule(
implementation = _r_impl,
attrs = {
"_allowlist_function_transition": attr.label(
default = "#bazel_tools//tools/allowlists/function_transition_allowlist",
),
"srcs": attr.label(cfg = force_x86_64),
},
)
def _r_impl(ctx):
return [DefaultInfo(files = ctx.attr.srcs[0][DefaultInfo].files)]
This defines a rule that attaches the appropriate transition to the srcs you pass it, and then simply forwards the list of files from DefaultInfo. Depending on what you're doing, this might be sufficient, or you might also want to forward the runfiles contained in DefaultInfo and/or other providers.
Use target_compatible_with
Example (only compiled on Windows):
cc_library(
name = "win_driver_lib",
srcs = ["win_driver_lib.cc"],
target_compatible_with = [
"#platforms//cpu:x86_64",
"#platforms//os:windows",
],
)

How to reference the source directory of a `bazel` BUILD file?

I have something like the following:
sh_binary(
…
args = [
"path/to/this/build/file/relative/to/workspace/root",
],
…
)
Is there a way to compute/generate "path/to/this/build/file/relative/to/workspace/root" so that if the BUILD file is moved, args wouldn't have to be changed? Something similar to $(location) (I haven't gotten $(location) to work since it would introduce a circular dependency)?
Adding the BUILD file as a data dependency allows you to get its $(location):
sh_binary(
…
args = ["$(location BUILD.bazel)"],
data = ["BUILD.bazel"],
…
)

How can I define an owner to an empty_dir using container_image or container_layer from bazel rules_docker?

From the PR that implemented empty_dirs, it seems there's support for defining dir owners (with the names argument) and mode into the add_empty_dir method of TarFile class.
But the container_image rule (and container_layer) supports only mode.
This works:
container_image(
name = "with_empty_dirs",
empty_dirs = [
"etc",
"foo",
"bar",
],
mode = "0o777",
)
But this returns an error: "ERROR: (...) no such attribute 'names' in 'container_image_' rule":
container_image(
name = "with_empty_dirs",
empty_dirs = [
"etc",
"foo",
"bar",
],
names = "nginx",
)
Do we need to “write a customized container_image” if we want to add support for owner of empty_dirs?
In a BUILD file, the attribute you're looking for is ownername. See the pkg_tar reference documentation documentation for more details. Also, I don't think you can pass it directly to container_image, you have to create a separate pkg_tar first. Like this:
pkg_tar(
name = "with_empty_dirs_tar",
empty_dirs = [
"etc",
"foo",
"bar",
],
ownername = "nginx.nginx",
)
container_image(
name = "with_empty_dirs",
tars = [":with_empty_dirs_tar"],
)
In general, container_image has a subset of pkg_tar as direct attributes to make simple forms of adding files, but for complex use cases you should create a pkg_tar yourself for full access to all of its features for adding/arranging files and setting their ownership.
The names you see in that PR is a variable in a Python helper tool which the BUILD file rules use as part of the implementation. There's a layer of abstraction between what you write in a BUILD file and that Python code.

How to create a rule from within another rule in Bazel

Situation
I have two Skylark extension rules: blah_library and blah_binary. All of a blah_library's transitive dependencies are propagated by returning a provider(transitive_deps=...), and are handled appropriately by any ultimate dependent blah_binary target.
What I want to do
I want each blah_library to also create a filegroup with all the transitive dependencies mentioned above, so that I can access them separately. E.g., I'd like to be able to pass them in as data dependencies to a cc_binary. In other words:
# Somehow have this automatically create a target named `foo__trans_deps`?
blah_library(
name = "foo",
srcs = [...],
deps = [...],
)
cc_binary(
...,
data = [":foo__trans_deps"],
)
How should I do this? Any help would be appreciated!
What I've tried
Make a macro
I tried making a macro like so:
_real_blah_library = rule(...)
def blah_library(name, *args, **kwargs):
native.filegroup(
name = name + "__trans_deps",
srcs = ???,
)
_real_blah_library(name=name, *args, **kwargs)
But I'm not sure how to access the provider provided by _real_blah_library from within the macro, so I don't know how to populate the filegroup's srcs field...
Modify the blah_library rule's implementation
Right now I have something like:
_blah_provider = provider(fields=['transitive_deps'])
def _blah_library_impl(ctx):
...
trans_deps = []
for dep in ctx.attr.deps:
trans_deps += dep[_blah_provider].trans_deps
return _blah_provider(trans_deps=trans_deps)
blah_library = rule(impl=_blah_library_impl, ...)
I tried adding the following to _blah_library_impl, but it didn't work because apparently native.filegroup can't be called within a rule's implementation ("filegroup() cannot be called during the analysis phase"):
def _blah_library_impl(ctx):
...
trans_deps = []
for dep in ctx.attr.deps:
trans_deps += dep[_blah_provider].trans_deps
native.filegroup(
name = ctx.attr.name + "__trans_deps",
srcs = trans_deps,
)
return _blah_provider(trans_deps=trans_deps)
You can't easily create a filegroup like that, but you can still achieve what you want.
If you want to use the rule in genrule.srcs, filegroup.srcs, cc_binary.data, etc., then return a DefaultInfo provider (along with _blah_provider) and set the files field to the transitive closure of files.
You can refine the solution if you want a different set of files when the rule is in a data attribute vs. when in any other (e.g. srcs): just also set the runfiles-related members in DefaultInfo. (Frankly I don't know the difference between them, I'd just set all runfiles-fields to the same value.)
I ended up making my own special filegroup-like rule, as discussed in the comments under #Laszlo's answer. Here's the raw code in case it's a useful starting point for anyone:
def _whl_deps_filegroup_impl(ctx):
input_wheels = ctx.attr.src[_PyZProvider].transitive_wheels
output_wheels = []
for wheel in input_wheels:
file_name = wheel.basename
output_wheel = ctx.actions.declare_file(file_name)
# TODO(josh): Use symlinks instead of copying. Couldn't figure out how
# to do this due to issues with constructing absolute paths...
ctx.actions.run(
outputs=[output_wheel],
inputs=[wheel],
arguments=[wheel.path, output_wheel.path],
executable="cp",
mnemonic="CopyWheel")
output_wheels.append(output_wheel)
return [DefaultInfo(files=depset(output_wheels))]
whl_deps_filegroup = rule(
_whl_deps_filegroup_impl,
attrs = {
"src": attr.label(),
},
)

Resources