Skip to content

Commit 60deec0

Browse files
authored
introduce inline_src (#99)
1 parent e004ddc commit 60deec0

File tree

11 files changed

+369
-15
lines changed

11 files changed

+369
-15
lines changed

development/cli/execute_tests.bash

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,9 @@ check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_substr_ma
5151
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_substr_matcher.test
5252
check_bazel_build_error //tests/cc/cpp_compile_error:incorrect_matcher
5353
check_bazel_build_error //tests/cc/cpp_compile_error:incorrect_matcher.test
54+
check_bazel_build_error //tests/cc/cpp_inline_src:incorrect_matcher
55+
check_bazel_build_error //tests/cc/cpp_inline_src:incorrect_matcher.test
56+
check_bazel_build_error //tests/cc/cpp_inline_src:incorrect_extension
57+
check_bazel_build_error //tests/cc/cpp_inline_src:incorrect_extension.test
58+
check_bazel_build_error //tests/cc/c_inline_src:incorrect_extension
59+
check_bazel_build_error //tests/cc/c_inline_src:incorrect_extension.test

examples/cc/BUILD.bazel

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ load(
33
"@rules_build_error//lang/cc:defs.bzl",
44
"cc_build_error",
55
"cc_build_error_test",
6+
"inline_src",
67
)
78
load("@rules_build_error//matcher:defs.bzl", "matcher")
89

@@ -44,3 +45,53 @@ cc_build_error_test(
4445
src = "link_error.cpp",
4546
link_stderr = matcher.contains_basic_regex("Declared.*Undefined"),
4647
)
48+
49+
# With `inline_src`, you can also provide the source as an inline string.
50+
51+
cc_build_error_test(
52+
name = "compile_error_test_with_inline_c",
53+
src = inline_src.c("""
54+
#include <assert.h>
55+
56+
int main(void) {
57+
static_assert(0, "Compile error message for inline src");
58+
return 0;
59+
}
60+
"""),
61+
compile_stderr = matcher.has_substr("static assertion failed"),
62+
)
63+
64+
cc_build_error_test(
65+
name = "compile_error_test_with_inline_cpp",
66+
src = inline_src.cpp("""
67+
constexpr bool Predicate() noexcept { return false; }
68+
69+
int main() {
70+
static_assert(Predicate(), "Compile error message for inline src");
71+
return 0;
72+
}
73+
"""),
74+
compile_stderr = matcher.has_substr("static assertion failed"),
75+
)
76+
77+
cc_build_error_test(
78+
name = "link_error_test_with_inline_c",
79+
src = inline_src.c("""
80+
int DeclaredButUndefined();
81+
int main(void) {
82+
return DeclaredButUndefined();
83+
}
84+
"""),
85+
link_stderr = matcher.has_substr("DeclaredButUndefined"),
86+
)
87+
88+
cc_build_error_test(
89+
name = "link_error_test_with_inline_cpp",
90+
src = inline_src.cpp("""
91+
int DeclaredButUndefined();
92+
int main() {
93+
return DeclaredButUndefined();
94+
}
95+
"""),
96+
link_stderr = matcher.has_substr("DeclaredButUndefined"),
97+
)

inline_src/BUILD.bazel

Whitespace-only changes.

inline_src/inline_src.bzl

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
"""Define the inline source object and its functions.
2+
"""
3+
4+
visibility("//lang/...")
5+
6+
_INLINE_SRC_TYPE = "INLINE_SRC"
7+
8+
def is_inline_src(obj):
9+
"""Test if an object is an inline source object or not.
10+
11+
Args:
12+
An object to test.
13+
14+
Returns:
15+
True it's an inline source object, false otherwise.
16+
"""
17+
return type(obj) == "struct" and getattr(obj, "type", None) == _INLINE_SRC_TYPE
18+
19+
def inline_src_c(content):
20+
"""Construct an inline source object for C.
21+
22+
Args:
23+
content(str): Content of the source file.
24+
25+
Returns:
26+
An inline source object for C.
27+
"""
28+
29+
return struct(
30+
type = _INLINE_SRC_TYPE,
31+
content = content,
32+
extension = "c",
33+
)
34+
35+
def inline_src_cpp(content):
36+
"""Construct an inline source object for C++.
37+
38+
Args:
39+
content(str): Content of the source file.
40+
41+
Returns:
42+
An inline source object for C++.
43+
"""
44+
45+
return struct(
46+
type = _INLINE_SRC_TYPE,
47+
content = content,
48+
extension = "cpp",
49+
)
50+
51+
def _generate_inline_src_rule_impl(ctx):
52+
"""Implementation of `_generate_inline_src_rule`.
53+
54+
Args:
55+
ctx: Rule context.
56+
57+
Returns:
58+
Provider for the rule.
59+
"""
60+
output = ctx.actions.declare_file(ctx.label.name + "." + ctx.attr.extension)
61+
ctx.actions.write(
62+
output = output,
63+
content = ctx.attr.content,
64+
)
65+
return [DefaultInfo(files = depset([output]))]
66+
67+
_generate_inline_src_rule = rule(
68+
implementation = _generate_inline_src_rule_impl,
69+
attrs = {
70+
"content": attr.string(
71+
doc = (
72+
"The content of the source file."
73+
),
74+
mandatory = True,
75+
),
76+
"extension": attr.string(
77+
doc = (
78+
"The extension of the source file."
79+
),
80+
mandatory = True,
81+
),
82+
},
83+
provides = [DefaultInfo],
84+
)
85+
86+
def generate_inline_src(*, name, inline_src, **kwargs):
87+
"""Rule to generate inline source.
88+
89+
Args:
90+
name(str): The name of the target.
91+
inline_src(inline source object): The inline source object to generate.
92+
**kwargs(dict): Passed to internal rules.
93+
"""
94+
if not is_inline_src(inline_src):
95+
fail("Precondition: `inline_src` must be an inline source object.")
96+
97+
_generate_inline_src_rule(
98+
name = name,
99+
content = inline_src.content,
100+
extension = inline_src.extension,
101+
**kwargs
102+
)

lang/cc/README.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
# C/C++ build error
22

3-
Defines some implementations to check build error in C/C++.
3+
Defines some implementations to check build error in C/C++. Each of them can be loaded from `//lang/cc:defs.bzl`.
44

55
## `cc_build_error`
66

77
`cc_build_error` is a rule providing [`CcBuildErrorInfo`](#ccbuilderrorinfo).
88

99
In addition to the common rule attributes listed [here](https://bazel.build/reference/be/common-definitions#common-attributes), it can receive the following attributes (regarding the specific matcher, please refer to [its readme](../../matcher/README.md)):
1010

11-
| Attribute | Description | Type | Is this attribute required? | Other constraints |
12-
| ------------------------ | ------------------------------------------------------------------ | ---------------- | --------------------------- | --------------------------------------------------- |
13-
| name | Name of the target. | str | Yes | |
14-
| src | C/C++ source file to check build | label | Yes | Must be a single file having an extension for C/C++ |
15-
| additional_linker_inputs | Pass these files to the linker command | list of labels | No (defaults to `[]`) | |
16-
| copts | C/C++ compilation options | list of str | No (defaults to `[]`) | |
17-
| deps | The list of CcInfo libraries to be linked in to the binary target. | list of label | No (defaults to `[]`) | Each list element must provide `CcInfo` |
18-
| linkopts | C/C++ linking options | list of str | No (defaults to `[]`) | |
19-
| local_defines | Pre-processor macro definitions | list of str | No (defaults to `[]`) | |
20-
| compile_stderr | Matcher for the stderr message while compiling | specific matcher | No (defaults to no-op) | |
21-
| compile_stdout | Matcher for the stdout message while compiling | specific matcher | No (defaults to no-op) | |
22-
| link_stderr | Matcher for the stderr message while linking | specific matcher | No (defaults to no-op) | |
23-
| link_stdout | Matcher for the stdout message while linking | specific matcher | No (defaults to no-op) | |
11+
| Attribute | Description | Type | Is this attribute required? | Other constraints |
12+
| ------------------------ | ------------------------------------------------------------------ | ---------------------------------------- | --------------------------- | --------------------------------------------------- |
13+
| name | Name of the target. | str | Yes | |
14+
| src | C/C++ source file to check build | label or [an inline source](#inline_src) | Yes | Must be a single file having an extension for C/C++ |
15+
| additional_linker_inputs | Pass these files to the linker command | list of labels | No (defaults to `[]`) | |
16+
| copts | C/C++ compilation options | list of str | No (defaults to `[]`) | |
17+
| deps | The list of CcInfo libraries to be linked in to the binary target. | list of label | No (defaults to `[]`) | Each list element must provide `CcInfo` |
18+
| linkopts | C/C++ linking options | list of str | No (defaults to `[]`) | |
19+
| local_defines | Pre-processor macro definitions | list of str | No (defaults to `[]`) | |
20+
| compile_stderr | Matcher for the stderr message while compiling | specific matcher | No (defaults to no-op) | |
21+
| compile_stdout | Matcher for the stdout message while compiling | specific matcher | No (defaults to no-op) | |
22+
| link_stderr | Matcher for the stderr message while linking | specific matcher | No (defaults to no-op) | |
23+
| link_stdout | Matcher for the stdout message while linking | specific matcher | No (defaults to no-op) | |
2424

2525
### `CcBuildErrorInfo`
2626

@@ -29,3 +29,7 @@ In addition to the common rule attributes listed [here](https://bazel.build/refe
2929
## `cc_build_error_test`
3030

3131
`cc_build_error_test` is a test rule used to verify that `cc_build_error` builds successfully. It accepts the same set of arguments as `cc_build_error`.
32+
33+
## `inline_src`
34+
35+
Using `inline_src`, you can provide source code as an inline string. The function `inline_src.c` generates a C source file, while `inline_src.cpp` generates a C++ source file. Both functions accept a string containing the source code as their argument.

lang/cc/build_error.bzl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ load(
99
"@bazel_tools//tools/cpp:toolchain_utils.bzl",
1010
"find_cpp_toolchain",
1111
)
12+
load(
13+
"//inline_src:inline_src.bzl",
14+
"generate_inline_src",
15+
"is_inline_src",
16+
)
1217
load(
1318
"//lang/private:general_build_actions.bzl",
1419
"DEFAULT_MATCHER",
@@ -614,9 +619,22 @@ def cc_build_error(
614619
}
615620
kwargs.clear()
616621

622+
src = kwargs_try_build.pop("src")
623+
if is_inline_src(src):
624+
inline_src_target = name + "__i"
625+
generate_inline_src(
626+
name = inline_src_target,
627+
inline_src = src,
628+
tags = ["manual"] + tags,
629+
testonly = testonly,
630+
visibility = ["//visibility:private"],
631+
)
632+
src = ":" + inline_src_target
633+
617634
try_build_target = name + "__0"
618635
_try_build(
619636
name = try_build_target,
637+
src = src,
620638
tags = ["manual"] + tags,
621639
os = select({
622640
Label("//platforms/os:linux"): "linux",

lang/cc/defs.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ load(
77
_cc_build_error = "cc_build_error",
88
_cc_build_error_test = "cc_build_error_test",
99
)
10+
load(
11+
":inline_src.bzl",
12+
_inline_src = "inline_src",
13+
)
1014

1115
visibility("public")
1216

1317
cc_build_error = _cc_build_error
1418
cc_build_error_test = _cc_build_error_test
1519
CcBuildErrorInfo = _CcBuildErrorInfo
20+
inline_src = _inline_src

lang/cc/inline_src.bzl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Define `inline_src`.
2+
"""
3+
4+
load(
5+
"//inline_src:inline_src.bzl",
6+
"inline_src_c",
7+
"inline_src_cpp",
8+
)
9+
10+
visibility("private")
11+
12+
inline_src = struct(
13+
c = inline_src_c,
14+
cpp = inline_src_cpp,
15+
)

matcher/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Matcher
22

3-
Defines a struct `matcher`.
3+
Defines a struct `matcher`, which can be loaded from `//matcher:defs.bzl`.
44

55
`matcher` has some member functions each of which receives a pattern string as a positional string argument, and which returns its specific matcher. Each specific matcher can be used to specify the way of validating the build error message (stderr or stdout).
66

tests/cc/c_inline_src/BUILD.bazel

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
load("@bazel_skylib//rules:build_test.bzl", "build_test")
2+
load("//lang/cc:defs.bzl", "inline_src")
3+
load("//matcher:defs.bzl", "matcher")
4+
load("//tests/cc:utils.bzl", "check_build_and_test")
5+
6+
check_build_and_test(
7+
name = "plain",
8+
src = inline_src.c("""
9+
#include <assert.h>
10+
11+
int main(void) {
12+
13+
#ifndef __cplusplus
14+
static_assert(0, "Compile error message for inline src");
15+
#endif
16+
17+
return 0;
18+
}
19+
"""),
20+
)
21+
22+
check_build_and_test(
23+
name = "with_substr_matcher",
24+
src = inline_src.c("""
25+
#include <assert.h>
26+
27+
int main(void) {
28+
29+
#ifndef __cplusplus
30+
static_assert(0, "Compile error message for inline src");
31+
#endif
32+
33+
return 0;
34+
}
35+
"""),
36+
compile_stderr = matcher.has_substr("static assertion failed"),
37+
)
38+
39+
check_build_and_test(
40+
name = "with_basic_regex_matcher",
41+
src = inline_src.c("""
42+
#include <assert.h>
43+
44+
int main(void) {
45+
46+
#ifndef __cplusplus
47+
static_assert(0, "Compile error message for inline src");
48+
#endif
49+
50+
return 0;
51+
}
52+
"""),
53+
compile_stderr = matcher.contains_basic_regex(r"static[[:space:]]assertion \(failed\|error\)"),
54+
)
55+
56+
check_build_and_test(
57+
name = "with_extended_regex_matcher",
58+
src = inline_src.c("""
59+
#include <assert.h>
60+
61+
int main(void) {
62+
63+
#ifndef __cplusplus
64+
static_assert(0, "Compile error message for inline src");
65+
#endif
66+
67+
return 0;
68+
}
69+
"""),
70+
compile_stderr = matcher.contains_extended_regex(r"static[[:space:]]assertion (failed|error)"),
71+
)
72+
73+
build_test(
74+
name = "build_test",
75+
targets = [
76+
":plain",
77+
":with_substr_matcher",
78+
":with_basic_regex_matcher",
79+
":with_extended_regex_matcher",
80+
],
81+
)
82+
83+
# Test case which should fail to build
84+
check_build_and_test(
85+
name = "incorrect_extension",
86+
src = inline_src.cpp("""
87+
#include <assert.h>
88+
89+
int main(void) {
90+
91+
#ifndef __cplusplus
92+
static_assert(0, "Compile error message for inline src");
93+
#endif
94+
95+
return 0;
96+
}
97+
"""),
98+
compile_stderr = matcher.has_substr("static assertion failed"),
99+
tags = ["manual"],
100+
)

0 commit comments

Comments
 (0)