Skip to content

Commit 4bb74db

Browse files
fix(import_cc): reject unsupported Bazel imports
Fail early when Bazel imports use dynamic_deps or expose multiple library/binary outputs from a single target. Add regression coverage for dynamic binary deps and multi-output CMake imports. Change-Id: Icb8524b813a612d11582a82a15945e35ecdca451 Signed-off-by: Jordan Bonser <jordan.bonser@arm.com>
1 parent 11402c9 commit 4bb74db

6 files changed

Lines changed: 122 additions & 11 deletions

File tree

tests/bazel_cc_import/bazel/BUILD.bazel

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,15 @@ gen_bob_import(
1515
"//tests/bazel_cc_import/bazel/library/simple:static",
1616
],
1717
)
18+
19+
gen_bob_import(
20+
name = "dynamic_deps_unsupported_test",
21+
tags = ["manual"],
22+
deps = ["//tests/bazel_cc_import/bazel/binary/dynamic"],
23+
)
24+
25+
gen_bob_import(
26+
name = "multi_output_unsupported_test",
27+
tags = ["manual"],
28+
deps = ["//tests/bazel_cc_import/bazel/library/cmake:multiple"],
29+
)

tests/bazel_cc_import/bazel/binary/cmake/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake")
21
load("@bazel_skylib//rules:native_binary.bzl", "native_binary")
2+
load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake")
33

44
filegroup(
55
name = "srcs",

tests/bazel_cc_import/bazel/binary/dynamic/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ cc_binary(
44
name = "dynamic",
55
srcs = ["impl.c"],
66
dynamic_deps = ["//tests/bazel_cc_import/bazel/library/simple:shared"],
7+
visibility = ["//tests/bazel_cc_import/bazel:__pkg__"],
78
deps = ["//tests/bazel_cc_import/bazel/library/simple"],
89
)

tests/bazel_cc_import/bazel/bob_import_cc_aspect.bzl

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
load("@bazel_skylib//lib:collections.bzl", "collections")
2+
load("@bazel_skylib//lib:paths.bzl", "paths")
13
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
24
load("//tests/bazel_cc_import/bazel:buildbp.bzl", "binary_bp_content", "library_bp_content")
35
load("//tests/bazel_cc_import/bazel:name.bzl", "bp_target_name")
4-
load("@bazel_skylib//lib:collections.bzl", "collections")
5-
load("@bazel_skylib//lib:paths.bzl", "paths")
66

77
ImportCcAspectInfo = provider(fields = ["defines", "headers"])
88

@@ -84,18 +84,34 @@ def _symlink_headers(ctx, module_dir, dir_name, headers):
8484

8585
return outputs
8686

87-
def _library_file(target):
87+
def _unique_files_by_path(files):
88+
seen = {}
89+
deduped = []
90+
for file in files:
91+
if file and not seen.get(file.path):
92+
seen[file.path] = True
93+
deduped.append(file)
94+
return deduped
95+
96+
def _file_list(files):
97+
return ", ".join([file.short_path for file in files])
98+
99+
def _library_files(target):
88100
candidates = []
89101

90102
def add_candidate(file):
91103
if _is_library_file(file):
92104
candidates.append(file)
93105

94106
# cc_shared_library has this
95-
for file in target[DefaultInfo].files.to_list():
96-
add_candidate(file)
107+
if DefaultInfo in target:
108+
for file in target[DefaultInfo].files.to_list():
109+
add_candidate(file)
110+
111+
if candidates:
112+
return _unique_files_by_path(candidates)
97113

98-
if not candidates and CcInfo in target:
114+
if CcInfo in target:
99115
linking_context = target[CcInfo].linking_context
100116
for linker_input in linking_context.linker_inputs.to_list():
101117
for library in linker_input.libraries:
@@ -105,8 +121,10 @@ def _library_file(target):
105121
]:
106122
add_candidate(file)
107123

108-
if len(candidates) > 1:
109-
fail("More than one lib output in '" + str(target) + "' " + str(candidates))
124+
return _unique_files_by_path(candidates)
125+
126+
def _library_file(target):
127+
candidates = _library_files(target)
110128

111129
if len(candidates) == 0:
112130
# header only lib
@@ -117,27 +135,63 @@ def _library_file(target):
117135
def _is_library_file(file):
118136
return file.path.endswith(".a") or file.path.endswith(".so")
119137

120-
def _binary_file(target):
138+
def _binary_files(target):
121139
if DefaultInfo not in target:
122-
return None
140+
return []
123141

124142
candidates = []
125143
for file in target[DefaultInfo].files.to_list():
126144
if not file.is_directory and not _is_library_file(file):
127145
candidates.append(file)
128146

147+
return _unique_files_by_path(candidates)
148+
149+
def _binary_file(target):
150+
candidates = _binary_files(target)
151+
129152
if len(candidates) == 1:
130153
return candidates[0]
131154

132155
return None
133156

157+
def _multiple_outputs_reason(output_type, files):
158+
return "produces multiple " + output_type + " outputs (" + _file_list(files) + "); " + \
159+
"Bob import generation supports one output per Bazel target"
160+
161+
def _fail_on_unsupported_outputs(target):
162+
libraries = _library_files(target)
163+
binaries = _binary_files(target)
164+
165+
if len(libraries) > 1:
166+
fail(_multiple_outputs_reason("library", libraries))
167+
if len(binaries) > 1:
168+
fail(_multiple_outputs_reason("binary", binaries))
169+
if libraries and binaries:
170+
fail(
171+
"produces both library and binary outputs (" + _file_list(libraries + binaries) + "); " +
172+
"Bob import generation supports either one library or one binary per Bazel target",
173+
)
174+
175+
def _target_labels(targets):
176+
return ", ".join([str(target.label) for target in targets])
177+
178+
def _fail_on_unsupported_dynamic_deps(ctx):
179+
dynamic_deps = getattr(ctx.rule.attr, "dynamic_deps", [])
180+
if dynamic_deps:
181+
fail(
182+
"declares dynamic_deps (" + _target_labels(dynamic_deps) + "); " +
183+
"dynamic dependencies are not supported for Bob imports",
184+
)
185+
134186
def _symlink_file(ctx, module_dir, dir_name, file):
135187
destination = paths.join(dir_name, file.basename)
136188
out = ctx.actions.declare_file(module_dir + "/" + destination)
137189
ctx.actions.symlink(output = out, target_file = file)
138190
return destination, out
139191

140192
def _bob_import_cc_aspect_impl(target, ctx):
193+
_fail_on_unsupported_dynamic_deps(ctx)
194+
141195
headers, defines = _compilation_info(target, ctx)
142196

143197
return [
@@ -155,6 +209,8 @@ bob_import_cc_aspect = aspect(
155209
def _gen_bob_import_impl(ctx):
156210
output = []
157211
for dep in ctx.attr.deps:
212+
_fail_on_unsupported_outputs(dep)
213+
158214
target_name = bp_target_name(dep.label)
159215
include_destination = "include"
160216
library_destination = "lib"

tests/bazel_cc_import/bazel/library/cmake/BUILD.bazel

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,13 @@ cmake(
2929
out_static_libs = ["libcmake_test_static.a"],
3030
visibility = ["//tests/bazel_cc_import/bazel:__pkg__"],
3131
)
32+
33+
cmake(
34+
name = "multiple",
35+
copts = ["-DVALUE_A=19"],
36+
defines = ["VALUE_SUM=22"],
37+
lib_source = ":srcs",
38+
out_shared_libs = ["libcmake_test_shared.so"],
39+
out_static_libs = ["libcmake_test_static.a"],
40+
visibility = ["//tests/bazel_cc_import/bazel:__pkg__"],
41+
)

tests/bazel_cc_import/run_test.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,38 @@ BAZEL_TARGETS=(
4040

4141
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" build "${BAZEL_TARGETS[@]}"
4242

43+
assert_bazel_build_fails() {
44+
local target="$1"
45+
local expected="$2"
46+
local log_file
47+
log_file="$(mktemp)"
48+
49+
echo "Checking unsupported Bazel import: ${target}"
50+
51+
if "${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" build "${target}" >"${log_file}" 2>&1; then
52+
echo "Expected '${target}' to fail" >&2
53+
rm -f "${log_file}"
54+
exit 1
55+
fi
56+
57+
if ! grep -Fq "${expected}" "${log_file}"; then
58+
echo "Expected '${target}' failure to contain '${expected}', got:" >&2
59+
cat "${log_file}" >&2
60+
rm -f "${log_file}"
61+
exit 1
62+
fi
63+
64+
rm -f "${log_file}"
65+
}
66+
67+
assert_bazel_build_fails \
68+
//tests/bazel_cc_import/bazel:dynamic_deps_unsupported_test \
69+
"dynamic dependencies are not supported for Bob imports"
70+
71+
assert_bazel_build_fails \
72+
//tests/bazel_cc_import/bazel:multi_output_unsupported_test \
73+
"Bob import generation supports one output per Bazel target"
74+
4375
mapfile -t GENERATED_BUILD_BPS < <(
4476
find bazel-bin/tests/bazel_cc_import/bazel -type f -name build.bp | sort
4577
)

0 commit comments

Comments
 (0)