We are seeing duplicate builds of the same target in Bazel and wondering what could cause this.
Here is a sample output:
[52,715 / 55,135] 12 action running
Bazel package: some-pkg - Target: a_target - Generating files at bazel-out/host/bin/some-pkg/a_target_generate [for host]; 264s remote-cache, processwrapper-sandbox
Bazel package: some-pkg - Target: a_target - Generating files at bazel-out/k8-fastbuild/bin/some-pkg/a_target_generate; 264s remote-cache, processwrapper-sandbox
...
We have not been able to identify the issue. It looks like this is only happening on Linux but not on Macs.
The target a_target is a custom_rule target. It should be platform independent.
custom_rule = rule(
attrs = dict(
...
_custom_rule_java_binary = attr.label(
cfg = "host",
default = Label("//tools/bazel/build/rules/custom-rule:custom_rule_bin"),
executable = True,
),
_singlejar = attr.label(
cfg = "host",
default = Label("#bazel_tools//tools/jdk:singlejar"),
executable = True,
allow_files = True,
),
),
implementation = ...,
)
custom_rule_bin is defined as follow:
java_library(
name = "custom_rule",
srcs = glob(["src/main/java/**/*.java"]),
deps = [
...,
],
)
java_binary(
name = "custom_rule_bin",
visibility = ["//visibility:public"],
main_class = "...",
runtime_deps = [
"#org_slf4j_simple",
":custom_rule",
"//some-pkg:some_pkg", # same some-pkg where a_target is built twice
],
)
The difference is that one says "for host" and the other doesn't. Anyone knows what the extra "for host" build is?
I do have a feeling that it's somehow related to the cfg attribute on the custom rule. This is likely coming from some example code. We use the same value on all our rules which generate code. This custom rule is special because it requires code from the application being built by Bazel to run and generate additional code.
Any insights appreciated why host would be wrong and what would be the correct value.
Any ideas/tips how to debug this?
First, one note is that the host configuration is being mostly deprecated, and "exec" is usually preferred. Some info about that is here: https://bazel.build/rules/rules#configurations.
What's happening is that that target is being depended upon in multiple configurations, and so bazel will build that target in each configuration. You can use cquery to figure out what's going on
As a very simple example:
genrule(
name = "gen_bin",
outs = ["bin"],
srcs = [":gen_lib"],
exec_tools = [":gen_tool"],
cmd = "touch $#",
)
genrule(
name = "gen_tool",
outs = ["tool"],
srcs = [":gen_lib"],
cmd = "touch $#",
)
genrule(
name = "gen_lib",
outs = ["lib"],
cmd = "touch $#; sleep 10",
)
Building bin, bazel runs the gen_lib genrule twice (in parallel):
$ bazel build bin
INFO: Analyzed target //:bin (5 packages loaded, 16 targets configured).
INFO: Found 1 target...
[1 / 5] 2 actions running
Executing genrule //:gen_lib; 1s linux-sandbox
Executing genrule //:gen_lib; 1s linux-sandbox
bazel config gives the configurations that are currently in the in-memory build graph:
$ bazel config
Available configurations:
5b39bc31deb1f1d37f1f858e7eec3964394eacce5bede4456dd59d417af4a6e9 (exec)
723da02ae6d0c5577e98242c8f06ca1bd1c6d7b295c97345ac31b844bfe8f79c
8960923b9e7dc13418be101268efd8e57d80283213d18174705345598b699c6b
fd805cc1de357c04c7abac1b40bae600e3d9ee56a8d17af0c28b5031ca09bfb9 (host)
then cquery:
$ bazel cquery "rdeps(//..., gen_lib)"
INFO: Analyzed 3 targets (0 packages loaded, 1 target configured).
INFO: Found 3 targets...
//:gen_lib (5b39bc3)
//:gen_lib (8960923)
//:gen_tool (5b39bc3)
//:gen_bin (8960923)
//:gen_tool (8960923)
INFO: Elapsed time: 0.052s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions
(cquery gives the first 7 digits of the configuration hash)
--output=graph gives a dot graph which is a little more useful:
$ bazel cquery "rdeps(//..., gen_lib)" --output=graph > /tmp/graph
$ xdot /tmp/graph
So gen_bin is in the target configuration (8960923), and it depends on gen_lib, so gen_lib will also be built in the target configuration.
gen_bin also depends on gen_tool via the exec_tools attribute, and exec_tools builds everything in the exec configuration (5b39bc3).
gen_tool also depends on gen_lib, and since gen_tool is in the exec configuration, a version of gen_lib is built in the exec configuration.
(There's also another version of gen_tool in the target configuration in the output, and that's an artifact of using //... in the "universe" argument of rdeps(), since //... will capture every target. Similarly, doing bazel build //... would cause gen_tool to be built twice.)
Related
I am trying to use a old version of jdk (7) in bazel for run a java_binary output as tool in the compilation process.
From the example code and following the documentation of bazel config java toolchains
I created a WORKSPACE where get the remotejdk:
load("#bazel_tools//tools/jdk:remote_java_repository.bzl", "remote_java_repository")
remote_java_repository(
name = "remotejdk",
prefix = "remotejdk", # Can be used with --java_runtime_version=openjdk_canary_11
version = "7", # or --java_runtime_version=11
exec_compatible_with = [ # Specifies constraints this JVM is compatible with "#platforms//cpu:arm",
"#platforms//os:linux",
"#platforms//cpu:x86_64"
],
urls=["https://download.java.net/openjdk/jdk7u75/ri/openjdk-7u75-b13-linux-x64-18_dec_2014.tar.gz"],
sha256 = "56d84d0bfc8c1194d501c889765a387e949d6a063feef6608e5e12b8152411fb")
and a BUILD file that define the toolchain
load("#rules_java//java:defs.bzl", "java_binary", "java_library")
load("//:create_file.bzl", "call_java_binary")
load(
"#bazel_tools//tools/jdk:default_java_toolchain.bzl",
"default_java_toolchain", "VANILLA_TOOLCHAIN_CONFIGURATION"
)
default_java_toolchain(
name = "repository_default_toolchain",
configuration = VANILLA_TOOLCHAIN_CONFIGURATION, # One of predefined configurations
java_runtime = "#remotejdk//:jdk", # JDK to use for compilation and toolchain's tools execution
jvm_opts = [],
source_version = "7",
)
call_java_binary(
name = "CreateFile",
)
java_binary(
name = "ProjectRunner",
srcs = ["src/main/java/com/example/ProjectRunner.java"],
main_class = "com.example.ProjectRunner",
deps = [":greeter"],
)
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)
when I try set specifically //:repository_default_toolchain and the language version as descrived in the documentation:
bazel build //:CreateFile --extra_toolchains=//:repository_default_toolchain_definition --java_language_version=7 --java_runtime_version=7
the toolchain is descarted with the error:
Type #bazel_tools//tools/jdk:runtime_toolchain_type: target platform #local_config_platform//:host: Rejected toolchain #remotejdk//:jdk; mismatching config settings: prefix_version_setting
and fallback to openjdk11_linux again.
With bazel query --output=build "#remotejdk_toolchain_config_repo//:toolchain" 2>/dev/null i looked for the value of prefix_version_setting and it is remotejdk_7
which is the proper way to setup jdk 7 as toolchain?
the code is the java example from bazel/examples
Best regards
I am using Bazel rules in NodeJS in my application. The aim is to simply lint a set of files and fail the build if linting fails. What I'm currently experiencing is that the build is successful despite lint errors.
Here's a part of my BUILD file:
load("#npm//htmlhint:index.bzl", "htmlhint")
filegroup(
name = "htmldata",
srcs = glob(["**/*.html"]),
)
htmlhint(
name = "compile",
data = [
"htmlhint.conf",
"//:htmldata"
],
args = [
"--config",
"htmlhint.conf",
"$(locations //:htmldata)"
]
)
I first load the hinting library, then I define a filegroup for all the HTML files that I want to lint. Afterward, I use the rule with its data and arguments.
To run the build, I use the default option via npm script: bazel build //...
Your build file is working as expected. Unfortunately it doesn't do what you want, because when you load the macro from #npm//htmlhint:index.bzl it sets up the nodejs binary which is a runnable target, which means that it will only create runfiles + executable when building. In this case, the build will not run the library.
There are several options to do what you want:
Use the htmlhint_test macro to create a test target.
Create a custom rule that will use the nodejs binary to build some artefacts. In this case, you can force the build to fail.
However, I suggest using the first approach, because if htmlhint is a linting tool, it won't produce any meaningful outputs and is best to keep it as part of the test suite.
Here's what you need to do to set up the compile target as a test target
diff --git a/BUILD.bazel b/BUILD.bazel
index 4e58ac5..3db5dbb 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
## -1,11 +1,11 ##
-load("#npm//htmlhint:index.bzl", "htmlhint")
+load("#npm//htmlhint:index.bzl", "htmlhint_test")
filegroup(
name = "htmldata",
srcs = glob(["**/*.html"]),
)
-htmlhint(
+htmlhint_test(
name = "compile",
data = [
"htmlhint.conf",
Then you can check it with bazel test //....
If you want to see the output just run your compile target with bazel run //path/to:compile
I am beginning to use bazel 2.0
I am building with visual studio 2015
I have a cc_library with deps using select ":windows" and ":linux"
windows and linux were defined as follow
config_setting(
name = "windows",
constraint_values = ["#platforms//os:windows"]
)
config_setting(
name = "linux",
constraint_values = ["#platforms//os:linux"]
)
bazel build base was working (generating the lib)
unfortunately I need to differentiate under windows between 32 bits and 64 bits since I need those target to be built under 32 and 64 bits
I changed "windows" to "windows_x86_64" defined as follow
config_setting(
name = "windows_x86_64",
values = {
"cpu": "#platforms//cpu:x86_64",
"platforms": "#platforms//os:windows",
},
)
bazel build base \
--platforms=#platforms//os:windows \
--cpu=#platforms//cpu:x86_66 \
--incompatible_use_platforms_repo_for_constraints
gives me the following error message
ERROR: While resolving toolchains for target //lib/base:windows_x86_64: Target #platforms//os:windows was referenced as a platform, but does not provide PlatformInfo
ERROR: Analysis of target '//lib/base:base' failed; build aborted: Target #platforms//os:windows was referenced as a platform, but does not provide PlatformInfo
I know I am missing something. I cannot figure out what. I searched what could be this PlatformInfo and how to retrieve it, unsuccessfully.
Any help, pointer appreciated!!!
Thanks
Somewhat confusingly #platforms//... doesn't actually have any platforms defined in it, instead, it has a set of constraint_values that you can use to create a platform.
e.g.
# BUILD.bazel
platform(
name = "windows_x86_32",
constraint_values = [
"#platforms//cpu:x86_32",
"#platforms//os:windows",
],
)
platform(
name = "windows_x86_64",
constraint_values = [
"#platforms//cpu:x86_64",
"#platforms//os:windows",
],
)
# The rest of your build file...
You should then be able to build using the command;
bazel build base --platforms=//:windows_x86_32
# or
bazel build base --platforms=//:windows_x86_64
I'm using Bazel on my CI server for building and testing my C++ library, but I can't retrieve generated reports/logs files.
I wonder if there is a way to refer to those generated files for a further use inside a genrule which can permit me to post-process files (generate HTML...) ?
bazel execution :
$ bazel test //unit:tests
INFO: Analyzed 2 targets (21 packages loaded, 400 targets configured).
INFO: Found 2 test targets...
INFO: Elapsed time: 29,326s, Critical Path: 6,86s
INFO: 22 processes: 22 darwin-sandbox.
INFO: Build completed successfully, 29 total actions
//unit:tests_a PASSED in 0.7s
//unit:tests_b PASSED in 0.7s
Executed 2 out of 2 tests: 2 tests pass.
INFO: Build completed successfully, 29 total actions
generated reports :
$ find bazel-out/ -name '*.xml' -or -name '*.log'
bazel-out//darwin-fastbuild/testlogs/unit/tests_a/test.log
bazel-out//darwin-fastbuild/testlogs/unit/tests_a/test.xml
bazel-out//darwin-fastbuild/testlogs/unit/tests_b/test.log
bazel-out//darwin-fastbuild/testlogs/unit/tests_b/test.xml
WORKSPACE :
load("#bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
strip_prefix = "googletest-release-1.10.0",
)
unit/BUILD :
load("#rules_cc//cc:defs.bzl", "cc_test")
test_suite(name = "tests", tests = glob(["tests_*"]))
cc_test(name = "tests_a", srcs = ["ut.cc"], deps = ["#gtest//:gtest_main"])
cc_test(name = "tests_b", srcs = ["ut.cc"], deps = ["#gtest//:gtest_main"])
unit/ut.cc :
#include "gtest/gtest.h"
TEST(HelloTest, GetGreet) {
EXPECT_EQ(1, 1);
}
i think you can save report gen by bazel test via PATH indicated by the env var: TEST_UNDECLARED_OUTPUTS_DIR。bazel test will save your report in bazel-out/k8-fastbuild/testlogs////<test_binary_targrt>/test.outputs/outputs.zip
check this out:https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions
I have a code generator tool that generates C/C++ code. This code generator tool is compiled with crosstool1. The generated C/C++ code needs to be compiled with crosstool2.
So the actions are:
Using Crosstool1 compile 'code_generator'.
Execute 'code_generator' and generate 'generated_code.cpp'
Using Crosstool2 compile 'generated_code.cpp'
Is it possible to make a cc_library() determine the crosstool to use? I saw that Skylark rules now allow a 'toolchains' parameter which I'm not sure how this is used, also I do not want to do the heavy lifting of C/C++ compiling bare bone with Skylark.
Is there an example of using a proper Host Crosstool and Target Crosstool except for the Tenserflow example? I get a headache each time I read it :D
Assume //crosstool1:toolchain is a label for cc_toolchain_suite rule describing first crosstool, //crosstool2:toolchain is a label for cc_toolchain_suite for second crosstool, and the build file for the project is:
cc_binary(
name = "generator",
srcs = [ "main.cc" ],
)
genrule(
name = "generate",
outs = ["generated.cc"],
cmd = "$(location :generator) > $#",
tools = [":generator"],
)
cc_binary(
name = "generated",
srcs = [ "generated.cc" ],
)
Then running:
bazel build --host_crosstool_top=//crosstool1:toolchain --crosstool_top=//crosstool2:toolchain :generated
will do exactly what you describe, it will use crosstool1 to build :generator, and crosstool2 to build generated. Genrules use host configuration by default, so all should just work.