Skip to content

Commit 3986e83

Browse files
author
Jonathan Watson
committed
feat: introduce aspect rule
Change-Id: Iab1588b17e732d528d24033300ea700742ae203c
1 parent 98eeada commit 3986e83

3 files changed

Lines changed: 111 additions & 59 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
load("//tests/bazel_cc_import/bazel:bob_import_cc_aspect.bzl", "gen_bob_import")
2+
3+
gen_bob_import(
4+
name = "test",
5+
deps = [
6+
"//tests/bazel_cc_import/bazel/header_only/includes",
7+
"//tests/bazel_cc_import/bazel/header_only/normal",
8+
"//tests/bazel_cc_import/bazel/header_only/strip_prefix",
9+
],
10+
)

tests/bazel_cc_import/bazel/bob_import_cc_aspect.bzl

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ load("//tests/bazel_cc_import/bazel:name.bzl", "bp_target_name")
44
load("@bazel_skylib//lib:collections.bzl", "collections")
55
load("@bazel_skylib//lib:paths.bzl", "paths")
66

7+
ImportCcAspectInfo = provider(fields = ["defines", "headers"])
8+
79
def _include_dir_relative_path(header, include_dirs):
810
best = None
911
for include_dir in include_dirs:
@@ -22,6 +24,13 @@ def _get_headers(compilation_info):
2224

2325
headers = {}
2426
for header in compilation_info.headers.to_list():
27+
if headers.get(""):
28+
fail("More than one header dir")
29+
30+
if header.is_directory:
31+
headers[""] = header
32+
continue
33+
2534
include_path = _include_dir_relative_path(header, include_dirs)
2635
if include_path:
2736
headers[paths.normalize(include_path)] = header
@@ -30,43 +39,99 @@ def _get_headers(compilation_info):
3039

3140
return headers
3241

42+
def _merge_import_info(info_sets):
43+
headers = {}
44+
defines = []
45+
46+
for info in info_sets:
47+
headers.update(info.headers)
48+
defines.extend(info.defines)
49+
50+
return headers, collections.uniq(defines)
51+
52+
def _compilation_info(target, ctx):
53+
info_sets = []
54+
55+
if CcInfo in target:
56+
compilation_context = target[CcInfo].compilation_context
57+
info_sets.append(
58+
ImportCcAspectInfo(
59+
headers = _get_headers(compilation_context),
60+
defines = compilation_context.defines.to_list(),
61+
),
62+
)
63+
64+
for attr_name in ["deps", "srcs"]:
65+
for dep in getattr(ctx.rule.attr, attr_name, []):
66+
if ImportCcAspectInfo in dep:
67+
info_sets.append(dep[ImportCcAspectInfo])
68+
69+
if not info_sets:
70+
return {}, []
71+
72+
return _merge_import_info(info_sets)
73+
3374
def _symlink_headers(ctx, module_dir, dir_name, headers):
3475
outputs = []
3576

3677
for include_path in sorted(headers.keys()):
37-
out = ctx.actions.declare_file(module_dir + "/" + dir_name + "/" + include_path)
78+
if include_path == "":
79+
out = ctx.actions.declare_directory(module_dir + "/" + dir_name)
80+
else:
81+
out = ctx.actions.declare_file(module_dir + "/" + dir_name + "/" + include_path)
3882
ctx.actions.symlink(output = out, target_file = headers[include_path])
3983
outputs.append(out)
4084

4185
return outputs
4286

43-
def _bob_import_cc_aspect_impl(target, ctx):
44-
defines = []
45-
src = None
46-
header_outputs = []
47-
include_destination = "include"
48-
49-
target_name = bp_target_name(ctx.label)
50-
defines = []
51-
if CcInfo in target:
52-
compilation_context = target[CcInfo].compilation_context
53-
defines = compilation_context.defines.to_list()
54-
headers = _get_headers(compilation_context)
55-
header_outputs = _symlink_headers(ctx, target_name, include_destination, headers)
56-
57-
target_name = bp_target_name(ctx.label)
58-
includes = [include_destination]
59-
87+
def _write_bp(ctx, target_name, src, defines, includes):
6088
out = ctx.actions.declare_file(target_name + "/build.bp")
6189
ctx.actions.write(out, bp_content(target_name, src, includes, defines))
90+
return out
6291

63-
outputs = [out] + header_outputs
92+
def _bob_import_cc_aspect_impl(target, ctx):
93+
headers, defines = _compilation_info(target, ctx)
6494

6595
return [
66-
OutputGroupInfo(bob_import_cc_bp = depset(outputs)),
96+
ImportCcAspectInfo(
97+
headers = headers,
98+
defines = defines,
99+
),
67100
]
68101

69102
bob_import_cc_aspect = aspect(
70103
implementation = _bob_import_cc_aspect_impl,
71-
attr_aspects = [], # TODO we will have to traverse things for more complex cases.
104+
attr_aspects = ["deps", "srcs"],
105+
)
106+
107+
def _gen_bob_import_impl(ctx):
108+
output = []
109+
for dep in ctx.attr.deps:
110+
target_name = bp_target_name(dep.label)
111+
include_destination = "include"
112+
library_destination = "lib"
113+
114+
outputs = []
115+
116+
headers = dep[ImportCcAspectInfo].headers
117+
defines = dep[ImportCcAspectInfo].defines
118+
outputs.extend(_symlink_headers(ctx, target_name, include_destination, headers))
119+
120+
includes = [include_destination]
121+
src = None
122+
123+
outputs.append(_write_bp(ctx, target_name, src, defines, includes))
124+
output.extend(outputs)
125+
126+
return [
127+
DefaultInfo(
128+
files = depset(output),
129+
),
130+
]
131+
132+
gen_bob_import = rule(
133+
implementation = _gen_bob_import_impl,
134+
attrs = {
135+
"deps": attr.label_list(aspects = [bob_import_cc_aspect]),
136+
},
72137
)

tests/bazel_cc_import/run_test.sh

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,76 +6,53 @@ TESTS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
66
BOB_ROOT="$(cd "${TESTS_DIR}/.." && pwd)"
77
BUILD_DIR="${1:-build-bazel-import}"
88
BOB_BUILD_DIR="${BOB_ROOT}/${BUILD_DIR}"
9-
BAZEL_OUTPUT_USER_ROOT="${BOB_BUILD_DIR}.bazel_output_user_root"
109
GENERATED_BPLIST="${BOB_BUILD_DIR}.bplist"
11-
BAZEL_STARTUP_ARGS=(--output_user_root="${BAZEL_OUTPUT_USER_ROOT}")
10+
BAZEL_STARTUP_ARGS=()
1211

1312
cleanup() {
1413
if [[ -n "${BAZEL:-}" ]]; then
1514
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" shutdown >/dev/null 2>&1 || true
1615
fi
17-
rm -rf "${BOB_BUILD_DIR}" "${BAZEL_OUTPUT_USER_ROOT}" "${GENERATED_BPLIST}"
16+
chmod -R u+w "${BOB_BUILD_DIR}" "${GENERATED_BPLIST}" >/dev/null 2>&1 || true
17+
rm -rf "${BOB_BUILD_DIR}" "${GENERATED_BPLIST}"
1818
}
1919

2020
trap cleanup EXIT
2121
trap 'echo "<------------- $(basename "${0}") failed"' ERR
2222

23-
require_file() {
24-
if [[ ! -f "$1" ]]; then
25-
echo "Expected file does not exist: $1" >&2
26-
exit 1
27-
fi
28-
}
29-
30-
require_symlink() {
31-
if [[ ! -L "$1" ]]; then
32-
echo "Expected symlink does not exist: $1" >&2
33-
exit 1
34-
fi
35-
}
3623

3724
if command -v bazelisk >/dev/null 2>&1; then
3825
BAZEL=bazelisk
3926
elif command -v bazel >/dev/null 2>&1; then
4027
BAZEL=bazel
4128
else
42-
echo "Skipping bazel_import test: neither bazelisk nor bazel is available"
29+
echo "Skipping bazel_cc_import test: neither bazelisk nor bazel is available"
4330
exit 0
4431
fi
4532

4633
pushd "${BOB_ROOT}" >/dev/null
4734

4835
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" clean
4936

50-
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" build \
51-
--aspects=//tests/bazel_cc_import/bazel:bob_import_cc_aspect.bzl%bob_import_cc_aspect \
52-
--output_groups=bob_import_cc_bp \
53-
//tests/bazel_cc_import/bazel/header_only/... \
54-
55-
EXPECTED_BUILD_BPS=(
56-
bazel-bin/tests/bazel_cc_import/bazel/header_only/includes/tests_bazel_cc_import_bazel_header_only_includes_includes/build.bp
57-
bazel-bin/tests/bazel_cc_import/bazel/header_only/normal/tests_bazel_cc_import_bazel_header_only_normal_normal/build.bp
58-
bazel-bin/tests/bazel_cc_import/bazel/header_only/strip_prefix/tests_bazel_cc_import_bazel_header_only_strip_prefix_strip_prefix/build.bp
37+
BAZEL_TARGETS=(
38+
//tests/bazel_cc_import/bazel:test
5939
)
6040

61-
EXPECTED_HEADER_LINKS=(
62-
bazel-bin/tests/bazel_cc_import/bazel/header_only/includes/tests_bazel_cc_import_bazel_header_only_includes_includes/include/api.h
63-
bazel-bin/tests/bazel_cc_import/bazel/header_only/normal/tests_bazel_cc_import_bazel_header_only_normal_normal/include/tests/bazel_cc_import/bazel/header_only/normal/api.h
64-
bazel-bin/tests/bazel_cc_import/bazel/header_only/strip_prefix/tests_bazel_cc_import_bazel_header_only_strip_prefix_strip_prefix/include/nested/api.h
65-
)
41+
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" build "${BAZEL_TARGETS[@]}"
6642

43+
mapfile -t GENERATED_BUILD_BPS < <(
44+
find bazel-bin/tests/bazel_cc_import/bazel -type f -name build.bp | sort
45+
)
6746

68-
for path in "${EXPECTED_BUILD_BPS[@]}"; do
69-
require_file "${path}"
70-
done
47+
if [[ ${#GENERATED_BUILD_BPS[@]} -eq 0 ]]; then
48+
echo "No generated build.bp files found under bazel-bin/tests/bazel_cc_import/bazel" >&2
49+
exit 1
50+
fi
7151

72-
for path in "${EXPECTED_HEADER_LINKS[@]}"; do
73-
require_symlink "${path}"
74-
done
7552

7653
{
7754
printf './bazel_cc_import/build.bp\n'
78-
printf '%s\n' "${EXPECTED_BUILD_BPS[@]}" | sort | sed 's#^#../#'
55+
printf '%s\n' "${GENERATED_BUILD_BPS[@]}" | sed 's#^#../#'
7956
printf './bob/Blueprints\n'
8057
printf './bob/blueprint/Blueprints\n'
8158
} > "${GENERATED_BPLIST}"

0 commit comments

Comments
 (0)