How to get list diff in Skylark? - bazel

I'd like to do something like:
srcs = glob(["*.proto"]) - ["some.proto"],
That particular syntax isn't valid in Skylark. How do I go about accomplishing a list diff in Skylark?

glob provides a exclude attribute, e.g.:
glob(
[
".editorconfig",
".gitattributes",
"third_party/eigen-*/**",
],
exclude = ["devertexwahn/flatland/copy.bara.sky"],
),

Related

Is there a workaround for nested selects in Bazel build?

I have a Bazel build file that selects what files and defines to include in my library based on 2 possible backends (A and B). I use select to do this, but I also want a default behavior to let another variable set them (for example, platform). Since this would require nested selects, I can workaround it by having an intermediate filegroup target for the default behavior (platform based). But I'm not sure what to do about the defines which are just a list of strings. This is an example of how I configured the BUILD file:
filegroup(
name = "_backend_based_on_platform_srcs",
srcs = select({
"//darwin": _backend_a_srcs,
"//linux": _backend_b_srcs,
})
)
filegroup(
name = "headers",
srcs = glob([
"include/common/*.hpp",
]) + select({
"//backend_a": _backend_a_srcs,
"//backend_b": _backend_b_srcs,
"//backend_default": [":_backend_based_on_platform_srcs"],
}),
)
cc_library(
name = "custom_lib",
hdrs = [
":headers",
],
defines = select({
"//backend_a": _backend_a_defines,
"//backend_b": _backend_b_defines,
#"//backend_default": [":_backend_based_on_platform_defines"],
}),
includes = ["include"],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
I'd like to have an intermediate target for the defines so that I can put a select in it, but I don't know if that exists. I tried using alias, but that can only take a string and not a list of strings (multiple define constants). Is there something else I can try to get this to work?

Creating multiple similar genrules and using their output

I have a genrule that looks like the below. It basically runs a simple go template tool that gets a resource name, a json file and template and outputs the rendered file. I have a bunch of resources that all need to be in separate files and ultimately packaged into a container.
resources = ["foo", "bar"]
[genrule(
name = "generate_" + resource + "_config",
srcs = [
"//some:tool:config.tmpl",
"//some:json",
],
outs = [resource + ".hcl"],
cmd = "$(location //some/tool:template) -resource " + resource + " -json_path=$(location //some:json) -template=$(location //some/tool:config.tmpl) -out=$#",
tools = [
"/some/tool:template",
],
) for resource in resources]
The above will generate a few rules named generate_foo_config and generate_bar_config and the files output correctly. I however cannot figure out how to use each one without specifying them directly in a filegroup or pkg_tar rule without enumerating each one. I would like to be able to add a new thing to the resources variable, and have it automatically included in the filegroup or tar for use in a build rule later. Is this possible?
Use a list comprehension, like you've got creating the genrules. Something like this:
pkg_tar(
name = "all_resources",
srcs = [":generate_" + resource + "_config" for resource in resources],
)
You can also put the list in a variable in the BUILD file to use it multiple times:
all_resources = [":generate_" + resource + "_config" for resource in resources]
pkg_tar(
name = "all_resources",
srcs = all_resources,
)
filegroup(
name = "resources_filegroup",
srcs = all_resources,
)

How to concantenate select objects to a list in bazel

I have a bazel target with attribute that must be a list.
However, I need selectively add elements to the list based on the outcome of a select.
glob_tests(
# some stuff
exclude = [
"a.foo",
] + if_A([
"x.foo",
]) + if_B([
"y.foo",
]),
)
In the above code snippet, the functions if_A and if_B return select objects.
But when I run this as is, I get an error stating that a sequence object was expected but a select object was encountered instead.
How can I convert the select objects to sequence objects?
(I assume glob_test is a macro that calls the builtin function glob.) globs are evaluated when a BUILD file is loaded, which is before any configuration is known. This means glob cannot take any select objects as inputs because the knowledge to turn select objects into lists is not present.
The way to solve this is to lift the select calls above the globs like this
some_test(
name = "some_test",
srcs = select({
"//cond1": glob(["t*", "s*"], exclude=["thing"]),
"//cond2": glob(["t*", "s*"], exclude=["something else"]),
}),
)
instead of
some_test(
name = "some_test",
srcs = glob(
["t*", "s*"],
exclude=select({
"//cond1": ["thing"],
"//cond2": ["something else"],
}),
),
)

What's the best way to select() based on toolchain with bazel?

The documentation (https://docs.bazel.build/configurable-attributes.html) offers the following example, which sadly doesn't work:
cc_library(
name = "my_lib",
deps = select(
{
"//tools/cc_target_os:android": [":android_deps"],
"//tools/cc_target_os:windows": [":windows_deps"],
},
no_match_error = "Please build with an Android or Windows toolchain",
),
)
Matchers such as "#platforms//os:macos" and "#platforms//os:windows" sadly only detect HOST platform but not TARGET platform. This breaks when cross-compiling on a different architecture.
I came up with an "android" matcher that works:
config_setting(
name = "android",
values = {"crosstool_top": "//external:android/crosstool"},
)
But cannot figure out a way to match windows, macos or linux TARGET toolchains.
Thanks!
I think that you are looking for platforms: https://docs.bazel.build/versions/master/platforms.html and the target_compatible_with attribute on cc_library.
I would suggest you want something like:
cc_library(
name = "my_lib_android",
deps = [":android_deps"],
target_compatible_with = [
"#platforms//os:android",
],
)
cc_library(
name = "my_lib_windows",
deps = [":windows_deps"],
target_compatible_with = [
"#platforms//os:windows",
],
)
The user of my_lib would then have to depend on either my_lib_android or my_lib_windows as appropriate.

Podspec - Exclude all but a subfolder

I have a structure like this
target_files/
├──target1/
├──target2/
└──target3/
And I want to include only "target2" for example and exclude the other targets. How I write the spec.exclude_files?
I found this example for excluding files, but I can't understand how to write it for whole folders.
spec.exclude_files = '_private/**/*.{h,m}'
spec.source_files = [ 'target_files/**' ]
spec.exclude_files = [ 'target_files/target1/**', 'target_files/target3/**' ]
or for the case you ask about, more simply:
spec.source_files = [ 'target_files/target2/**' ]
Reference
CocoaPods exclude_files
[CocoaPods]
Pattern: ** - Matches directories recursively.
s.exclude_files = 'target_files/target1/', 'target_files/target3/'
The opposite is source_files[About]

Resources