Skip to content

Commit 74f179c

Browse files
authored
use @rules_build_error to test compilation errors (#40)
Change-Id: Ic168ae06baefd3de234357eb8087f50dd6e331f3
1 parent d900fd7 commit 74f179c

16 files changed

Lines changed: 294 additions & 418 deletions

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,28 @@ auto main() -> int
8282
results in the follow build error (snippet):
8383

8484
```console:example/ctest_fail.log
85-
external/skytest/src/detail/test_style.hpp:43:27: error: the value of 'n' is not usable in a constant expression
85+
./src/detail/test_style.hpp:43:27: error: constexpr variable 'value<skytest::detail::static_closure<f>>' must be initialized by a constant expression
8686
43 | static constexpr auto value = std::optional<bool>{bool{F{}()}};
87-
| ^~~~~
88-
ctest_fail.cpp:9:15: note: 'int n' is not const
87+
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88+
./src/test.hpp:46:39: note: in instantiation of static data member 'skytest::detail::test_style::compile_time::value' requested here
89+
46 | result.compile_time = S::template value<F>;
90+
| ^
91+
./src/test.hpp:71:5: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
92+
71 | assign_impl(static_closure<f>{});
93+
| ^
94+
external/llvm_toolchain_llvm/bin/../include/c++/v1/__functional/operations.h:374:37: note: read of non-const variable 'n' is not allowed in a constant expression
95+
374 | return std::forward<_T1>(__t) < std::forward<_T2>(__u);
96+
| ^
97+
./src/detail/predicate.hpp:38:24: note: in call to 'static_cast<const std::less<void> &>(*this).operator()<const int &, const int &>(0, n)'
98+
38 | const auto value = static_cast<const F&>(*this)(std::as_const(args)...);
99+
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100+
example/ctest_fail.cpp:10:47: note: (skipping 2 calls in backtrace; use -fconstexpr-backtrace-limit=0 to see all)
101+
10 | "read non-const"_ctest = [] { return expect(lt(0, n)); };
102+
| ^
103+
example/ctest_fail.cpp:9:15: note: declared here
89104
9 | static auto n = 0;
90105
| ^
106+
1 error generated.
91107
92108
```
93109

WORKSPACE.bazel

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,34 @@ COMMON_CXX_WARNINGS = [
2222
"-Wimplicit-fallthrough",
2323
]
2424

25+
# `@rules_cc` depends on `com_google_protobuf`
26+
http_archive(
27+
name = "com_google_protobuf",
28+
integrity = "sha256-K2lcservjhc/iEI17m1V9XGG6V2J67MTYe5Vy1/RuZY=",
29+
strip_prefix = "protobuf-31.0",
30+
urls = [
31+
"https://github.com/protocolbuffers/protobuf/archive/v31.0.tar.gz",
32+
],
33+
)
34+
35+
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
36+
37+
protobuf_deps()
38+
39+
load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies")
40+
41+
rules_java_dependencies()
42+
43+
load("@rules_java//java:repositories.bzl", "rules_java_toolchains")
44+
45+
rules_java_toolchains()
46+
47+
# use a recent version of `@rules_cc` for `@rules_build_error`
2548
http_archive(
2649
name = "rules_cc",
27-
sha256 = "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf",
28-
strip_prefix = "rules_cc-0.0.9",
29-
urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz"],
50+
sha256 = "712d77868b3152dd618c4d64faaddefcc5965f90f5de6e6dd1d5ddcd0be82d42",
51+
strip_prefix = "rules_cc-0.1.1",
52+
urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.1/rules_cc-0.1.1.tar.gz"],
3053
)
3154

3255
TOOLCHAINS_LLVM_COMMIT = "4ab573b1b87a57791ef2f9ccee71cbad80a2abb9"
@@ -184,12 +207,11 @@ python_register_toolchains(
184207
python_version = "3.11",
185208
)
186209

187-
load("@python3_11//:defs.bzl", "interpreter")
188210
load("@rules_python//python:pip.bzl", "pip_parse")
189211

190212
pip_parse(
191213
name = "pip",
192-
python_interpreter_target = interpreter,
214+
python_interpreter_target = "@python3_11_host//:python",
193215
requirements_lock = "//tools:requirements.lock",
194216
)
195217

@@ -225,3 +247,22 @@ py_library(
225247
load("//tools:local_config_info.bzl", "local_config_info")
226248

227249
local_config_info(name = "local_config_info")
250+
251+
RULES_BUILD_ERROR_COMMIT = "4ea1a4fa702b16389c7eb3b695ef97a23dfe9330"
252+
253+
http_archive(
254+
name = "rules_build_error",
255+
sha256 = "db4363c0346b1e12a58d32e6c9d8b7036fcb0655a2a6391d21a6f13b8bfaed1a",
256+
strip_prefix = "rules_build_error-{commit}".format(
257+
commit = RULES_BUILD_ERROR_COMMIT,
258+
),
259+
url = "https://github.com/yuyawk/rules_build_error/archive/{commit}.tar.gz".format(
260+
commit = RULES_BUILD_ERROR_COMMIT,
261+
),
262+
)
263+
264+
http_archive(
265+
name = "rules_multirun",
266+
sha256 = "0e124567fa85287874eff33a791c3bbdcc5343329a56faa828ef624380d4607c",
267+
url = "https://github.com/keith/rules_multirun/releases/download/0.9.0/rules_multirun.0.9.0.tar.gz",
268+
)

example/BUILD.bazel

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
load("@rules_build_error//lang/cc:defs.bzl", "cc_build_error")
12
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
2-
load("//rules:sh_binary_template.bzl", "sh_binary_template")
33
load("//rules:binary_log.bzl", "synchronized_binary_log")
4+
load("@rules_multirun//:defs.bzl", "multirun")
45

56
cc_library(
67
name = "skytest_wrapper",
@@ -31,10 +32,15 @@ synchronized_binary_log(
3132
src = ":minimal_fail",
3233
)
3334

34-
sh_binary_template(
35+
cc_build_error(
3536
name = "ctest_fail",
36-
srcs = ["ctest_fail.sh.tmpl"],
37-
data = ["ctest_fail.cpp"],
37+
src = "ctest_fail.cpp",
38+
copts = [
39+
"-fno-diagnostics-color",
40+
"-fconstexpr-backtrace-limit=1",
41+
"-ftemplate-backtrace-limit=1",
42+
],
43+
deps = [":skytest_wrapper"],
3844
)
3945

4046
synchronized_binary_log(
@@ -131,38 +137,15 @@ cc_binary(
131137
deps = [":skytest_wrapper"],
132138
)
133139

134-
update_targets = [
135-
":minimal_pass_log.update.sh",
136-
":minimal_fail_log.update.sh",
137-
":additional_output_log.update.sh",
138-
":user_defined_predicates_log.update.sh",
139-
":described_predicates_log.update.sh",
140-
":described_predicates_20_log.update.sh",
141-
]
142-
143-
genrule(
144-
name = "update_all_sh",
145-
srcs = update_targets,
146-
outs = ["update_all.sh"],
147-
cmd = """
148-
set -euo pipefail
149-
echo "set -euo pipefail" > $@
150-
echo "" >> $@
151-
echo "for cmd in {update_targets}; do" >> $@
152-
echo " \"\\$$cmd\"" >> $@
153-
echo "done" >> $@
154-
""".format(
155-
update_targets = " ".join([
156-
"$(rootpath {})".format(x)
157-
for x in update_targets
158-
]),
159-
),
160-
tags = ["manual"],
161-
visibility = ["//visibility:private"],
162-
)
163-
164-
sh_binary(
140+
multirun(
165141
name = "update_all",
166-
srcs = ["update_all.sh"],
167-
data = update_targets,
142+
commands = [
143+
":ctest_fail_log.update",
144+
":minimal_pass_log.update",
145+
":minimal_fail_log.update",
146+
":additional_output_log.update",
147+
":user_defined_predicates_log.update",
148+
":described_predicates_log.update",
149+
":described_predicates_20_log.update",
150+
],
168151
)

example/ctest_fail.log

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
1-
external/skytest/src/detail/test_style.hpp:43:27: error: the value of 'n' is not usable in a constant expression
1+
./src/detail/test_style.hpp:43:27: error: constexpr variable 'value<skytest::detail::static_closure<f>>' must be initialized by a constant expression
22
43 | static constexpr auto value = std::optional<bool>{bool{F{}()}};
3-
| ^~~~~
4-
ctest_fail.cpp:9:15: note: 'int n' is not const
3+
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
./src/test.hpp:46:39: note: in instantiation of static data member 'skytest::detail::test_style::compile_time::value' requested here
5+
46 | result.compile_time = S::template value<F>;
6+
| ^
7+
./src/test.hpp:71:5: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
8+
71 | assign_impl(static_closure<f>{});
9+
| ^
10+
external/llvm_toolchain_llvm/bin/../include/c++/v1/__functional/operations.h:374:37: note: read of non-const variable 'n' is not allowed in a constant expression
11+
374 | return std::forward<_T1>(__t) < std::forward<_T2>(__u);
12+
| ^
13+
./src/detail/predicate.hpp:38:24: note: in call to 'static_cast<const std::less<void> &>(*this).operator()<const int &, const int &>(0, n)'
14+
38 | const auto value = static_cast<const F&>(*this)(std::as_const(args)...);
15+
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16+
example/ctest_fail.cpp:10:47: note: (skipping 2 calls in backtrace; use -fconstexpr-backtrace-limit=0 to see all)
17+
10 | "read non-const"_ctest = [] { return expect(lt(0, n)); };
18+
| ^
19+
example/ctest_fail.cpp:9:15: note: declared here
520
9 | static auto n = 0;
621
| ^
22+
1 error generated.

rules/BUILD.bazel

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,4 @@
1-
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
2-
load(
3-
"@local_config_info//:defs.bzl",
4-
"BAZEL_BIN",
5-
"BAZEL_EXTERNAL_DIR",
6-
"BAZEL_WORKSPACE_ROOT",
7-
"XDG_CACHE_HOME",
8-
)
9-
101
exports_files(
11-
["skytest_test.sh"],
12-
visibility = ["//test:__pkg__"],
13-
)
14-
15-
expand_template(
16-
name = "gen_prelude_sh",
17-
out = "prelude.sh",
18-
substitutions = {
19-
"$BAZEL_BIN": BAZEL_BIN,
20-
"$BAZEL_EXTERNAL_DIR": BAZEL_EXTERNAL_DIR,
21-
"$BAZEL_WORKSPACE_ROOT": BAZEL_WORKSPACE_ROOT,
22-
"$XDG_CACHE_HOME": XDG_CACHE_HOME,
23-
},
24-
tags = ["manual"],
25-
template = "prelude.sh.tmpl",
26-
visibility = ["//visibility:private"],
27-
)
28-
29-
sh_library(
30-
name = "prelude_sh",
31-
srcs = ["prelude.sh"],
32-
visibility = [
33-
"//example:__pkg__",
34-
"//test:__pkg__",
35-
],
2+
["copy_to_workspace.bash"],
3+
visibility = ["//example:__pkg__"],
364
)

rules/binary_log.bzl

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,57 @@ Rule for generating and testing log files for a binary's output
33
"""
44

55
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
6-
load("@local_config_info//:defs.bzl", "BAZEL_WORKSPACE_ROOT")
6+
load("@rules_build_error//lang/cc:defs.bzl", "CcBuildErrorInfo")
77

8-
def binary_log(
9-
name,
10-
src,
11-
log):
12-
"""
13-
Create a log file from running a binary.
8+
def _log_from_build_error(ctx):
9+
output = ctx.actions.declare_file(ctx.attr.log)
10+
input = ctx.attr.src[CcBuildErrorInfo].compile_stderr
1411

15-
Args:
16-
name: string
17-
Name for `binary_log` rule
18-
src: string_label
19-
Source binary file to run
20-
log: string
21-
Filename for created log.
22-
"""
23-
native.genrule(
24-
name = name,
25-
tools = [src],
26-
outs = [log],
27-
cmd = "$(execpath {}) &> $@ || true".format(src),
28-
testonly = True,
29-
tags = ["manual"],
30-
visibility = ["//visibility:private"],
31-
target_compatible_with = select({
32-
# log files will differ for Clang and GCC due to how types are
33-
# printed.
34-
"@rules_cc//cc/compiler:gcc": ["@platforms//:incompatible"],
35-
"//conditions:default": [],
36-
}),
12+
# remove lines with platform-specific information
13+
# e.g.
14+
# In file included from bazel-out/darwin_arm64-fastbuild/bin/_virtual_includes/skytest/skytest/skytest.hpp:12:
15+
ctx.actions.run_shell(
16+
inputs = [input],
17+
outputs = [output],
18+
command = "grep -v '^In file included from' {input} > {output}".format(
19+
input = input.path,
20+
output = output.path,
21+
),
22+
progress_message = "Generating log from {}".format(ctx.attr.src.label),
3723
)
3824

25+
return [DefaultInfo(files = depset([output]))]
26+
27+
def _log_from_binary(ctx):
28+
output = ctx.actions.declare_file(ctx.attr.log)
29+
bin = ctx.attr.src.files.to_list()[0]
30+
31+
ctx.actions.run_shell(
32+
inputs = [bin],
33+
outputs = [output],
34+
command = "{bin} &> {output} || true".format(
35+
bin = bin.path,
36+
output = output.path,
37+
),
38+
progress_message = "Generating log from {}".format(ctx.attr.src.label),
39+
)
40+
41+
return [DefaultInfo(files = depset([output]))]
42+
43+
def _binary_log_impl(ctx):
44+
if CcBuildErrorInfo in ctx.attr.src:
45+
return _log_from_build_error(ctx)
46+
return _log_from_binary(ctx)
47+
48+
binary_log = rule(
49+
implementation = _binary_log_impl,
50+
attrs = {
51+
"src": attr.label(mandatory = True),
52+
"log": attr.string(mandatory = True),
53+
},
54+
provides = [DefaultInfo],
55+
)
56+
3957
def synchronized_binary_log(
4058
name,
4159
src,
@@ -57,41 +75,36 @@ def synchronized_binary_log(
5775
name = name + "_gen",
5876
src = src,
5977
log = generated_log,
60-
)
61-
62-
label = native.package_relative_label(name)
63-
log = log or src_name + ".log"
64-
65-
native.genrule(
66-
name = name + "_update_sh",
67-
srcs = [log],
68-
tools = [src],
69-
outs = [name + ".update.sh"],
70-
cmd = """
71-
set -euo pipefail
72-
echo "set -euo pipefail" > $@
73-
echo "" >> $@
74-
echo "{workspace_dir}/$(execpath {src}) &> {workspace_dir}/$(rootpath {log}) || true" >> $@
75-
""".format(
76-
src = src,
77-
log = log,
78-
workspace_dir = BAZEL_WORKSPACE_ROOT,
79-
),
8078
tags = ["manual"],
8179
visibility = ["//visibility:private"],
80+
target_compatible_with = select({
81+
# log files will differ for Clang and GCC due to how types are
82+
# printed.
83+
"@rules_cc//cc/compiler:gcc": ["@platforms//:incompatible"],
84+
"//conditions:default": [],
85+
}),
8286
)
8387

88+
log = log or src_name + ".log"
89+
8490
diff_test(
8591
name = name,
8692
file1 = log,
87-
file2 = generated_log,
93+
file2 = name + "_gen",
8894
failure_message = "To update, run:\n\nbazel run {}.update".format(
89-
str(label).replace("@//", "//"),
95+
str(native.package_relative_label(name)).replace("@//", "//"),
9096
),
9197
)
9298

9399
native.sh_binary(
94100
name = name + ".update",
95-
srcs = [name + ".update.sh"],
96-
data = [src],
101+
srcs = [Label("copy_to_workspace.bash")],
102+
data = [
103+
log,
104+
name + "_gen",
105+
],
106+
args = [
107+
"$(rootpath :{})".format(name + "_gen"),
108+
"$(rootpath :{})".format(log),
109+
],
97110
)

0 commit comments

Comments
 (0)