Skip to content

Commit fe8e5a1

Browse files
author
Jonathan Watson
committed
test(import_cc): add import_cc test harness
Change-Id: If59bd355e850e98ea881c2789d5701d969ead783
1 parent 4198e97 commit fe8e5a1

8 files changed

Lines changed: 257 additions & 1 deletion

File tree

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ local_path_override(
1717
path = "blueprint",
1818
)
1919

20+
bazel_dep(name = "rules_cc", version = "0.2.14", dev_dependency = True)
2021
bazel_dep(name = "rules_foreign_cc", version = "0.15.0", dev_dependency = True)
2122

2223
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")

MODULE.bazel.lock

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
2+
load("//tests/bazel_cc_import/bazel:buildbp.bzl", "bp_content")
3+
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")
6+
7+
def _include_dir_relative_path(header, include_dirs):
8+
best = None
9+
for include_dir in include_dirs:
10+
for path in [header.short_path, header.path]:
11+
if path != include_dir and paths.starts_with(path, include_dir):
12+
relative = paths.relativize(path, include_dir)
13+
if best == None or len(relative) < len(best):
14+
best = relative
15+
return best
16+
17+
def _get_headers(compilation_info):
18+
include_dirs = compilation_info.system_includes.to_list() + \
19+
compilation_info.includes.to_list() + \
20+
compilation_info.external_includes.to_list()
21+
include_dirs = collections.uniq(include_dirs)
22+
23+
headers = {}
24+
for header in compilation_info.headers.to_list():
25+
include_path = _include_dir_relative_path(header, include_dirs)
26+
if include_path:
27+
headers[paths.normalize(include_path)] = header
28+
else:
29+
headers[paths.normalize(header.short_path)] = header
30+
31+
return headers
32+
33+
def _symlink_headers(ctx, module_dir, dir_name, headers):
34+
outputs = []
35+
36+
for include_path in sorted(headers.keys()):
37+
out = ctx.actions.declare_file(module_dir + "/" + dir_name + "/" + include_path)
38+
ctx.actions.symlink(output = out, target_file = headers[include_path])
39+
outputs.append(out)
40+
41+
return outputs
42+
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+
60+
out = ctx.actions.declare_file(target_name + "/build.bp")
61+
ctx.actions.write(out, bp_content(target_name, src, includes, defines))
62+
63+
outputs = [out] + header_outputs
64+
65+
return [
66+
OutputGroupInfo(bob_import_cc_bp = depset(outputs)),
67+
]
68+
69+
bob_import_cc_aspect = aspect(
70+
implementation = _bob_import_cc_aspect_impl,
71+
attr_aspects = [], # TODO we will have to traverse things for more complex cases.
72+
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
def _quote(value):
2+
return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"") + "\""
3+
4+
def _string_list(name, values):
5+
if not values:
6+
return ""
7+
out = " " + name + ": [\n"
8+
for value in sorted(values):
9+
out += " " + _quote(value) + ",\n"
10+
out += " ],\n"
11+
return out
12+
13+
def bp_content(name, src, includes, defines):
14+
content = "bob_import_cc {\n"
15+
content += " name: " + _quote(name) + ",\n"
16+
if src:
17+
content += " src: " + _quote(src) + ",\n"
18+
content += _string_list("includes", includes)
19+
content += _string_list("defines", defines)
20+
content += " target: \"target\",\n"
21+
content += "}\n"
22+
return content
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
def _sanitize(value):
2+
sanitized = ""
3+
for i in range(len(value)):
4+
c = value[i]
5+
if (c >= "A" and c <= "Z") or (c >= "a" and c <= "z") or (c >= "0" and c <= "9"):
6+
sanitized += c
7+
else:
8+
sanitized += "_"
9+
return sanitized
10+
11+
def _strip_label_prefix(value):
12+
for i in range(len(value)):
13+
c = value[i]
14+
if c != "@" and c != "/":
15+
return value[i:]
16+
return ""
17+
18+
def bp_target_name(label):
19+
return _sanitize(_strip_label_prefix(str(label)))

tests/bazel_cc_import/build.bp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
bob_binary {
2+
name: "bob_test_bazel_cc_import_header_only_normal",
3+
srcs: ["consumer/header_only/normal.c"],
4+
header_libs: ["tests_bazel_cc_import_bazel_header_only_normal_normal"],
5+
}
6+
7+
bob_binary {
8+
name: "bob_test_bazel_cc_import_header_only_includes",
9+
srcs: ["consumer/header_only/includes.c"],
10+
header_libs: ["tests_bazel_cc_import_bazel_header_only_includes_includes"],
11+
}
12+
13+
bob_binary {
14+
name: "bob_test_bazel_cc_import_header_only_strip_prefix",
15+
srcs: ["consumer/header_only/strip_prefix.c"],
16+
header_libs: ["tests_bazel_cc_import_bazel_header_only_strip_prefix_strip_prefix"],
17+
}
18+
19+
bob_alias {
20+
name: "bob_test_bazel_import",
21+
srcs: [
22+
"bob_test_bazel_cc_import_header_only_normal",
23+
"bob_test_bazel_cc_import_header_only_includes",
24+
"bob_test_bazel_cc_import_header_only_strip_prefix",
25+
],
26+
}

tests/bazel_cc_import/run_test.sh

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env bash
2+
set -eEuo pipefail
3+
4+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
TESTS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
6+
BOB_ROOT="$(cd "${TESTS_DIR}/.." && pwd)"
7+
BUILD_DIR="${1:-build-bazel-import}"
8+
BOB_BUILD_DIR="${BOB_ROOT}/${BUILD_DIR}"
9+
BAZEL_OUTPUT_USER_ROOT="${BOB_BUILD_DIR}.bazel_output_user_root"
10+
GENERATED_BPLIST="${BOB_BUILD_DIR}.bplist"
11+
BAZEL_STARTUP_ARGS=(--output_user_root="${BAZEL_OUTPUT_USER_ROOT}")
12+
13+
cleanup() {
14+
if [[ -n "${BAZEL:-}" ]]; then
15+
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" shutdown >/dev/null 2>&1 || true
16+
fi
17+
rm -rf "${BOB_BUILD_DIR}" "${BAZEL_OUTPUT_USER_ROOT}" "${GENERATED_BPLIST}"
18+
}
19+
20+
trap cleanup EXIT
21+
trap 'echo "<------------- $(basename "${0}") failed"' ERR
22+
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+
}
36+
37+
if command -v bazelisk >/dev/null 2>&1; then
38+
BAZEL=bazelisk
39+
elif command -v bazel >/dev/null 2>&1; then
40+
BAZEL=bazel
41+
else
42+
echo "Skipping bazel_import test: neither bazelisk nor bazel is available"
43+
exit 0
44+
fi
45+
46+
pushd "${BOB_ROOT}" >/dev/null
47+
48+
"${BAZEL}" "${BAZEL_STARTUP_ARGS[@]}" clean
49+
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
59+
)
60+
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+
)
66+
67+
68+
for path in "${EXPECTED_BUILD_BPS[@]}"; do
69+
require_file "${path}"
70+
done
71+
72+
for path in "${EXPECTED_HEADER_LINKS[@]}"; do
73+
require_symlink "${path}"
74+
done
75+
76+
{
77+
printf './bazel_cc_import/build.bp\n'
78+
printf '%s\n' "${EXPECTED_BUILD_BPS[@]}" | sort | sed 's#^#../#'
79+
printf './bob/Blueprints\n'
80+
printf './bob/blueprint/Blueprints\n'
81+
} > "${GENERATED_BPLIST}"
82+
83+
source "${TESTS_DIR}/bootstrap_utils.sh"
84+
create_link .. "${TESTS_DIR}/bob"
85+
86+
rm -rf "${BOB_BUILD_DIR}"
87+
export CONFIGNAME="bob.config"
88+
export SRCDIR="${TESTS_DIR}"
89+
export BUILDDIR="${BOB_BUILD_DIR}"
90+
export BLUEPRINT_LIST_FILE="${GENERATED_BPLIST}"
91+
export BOB_LOG_WARNINGS_FILE="${BOB_BUILD_DIR}/.bob.warnings.csv"
92+
export BOB_META_FILE="${BOB_BUILD_DIR}/.bob.meta.json"
93+
export BOB_LOG_WARNINGS=""
94+
export BOB_CONFIG_PLUGINS="${TESTS_DIR}/plugins/test_plugin"
95+
96+
"${BOB_ROOT}/bootstrap_linux.bash"
97+
ln -sf "bob" "${BOB_BUILD_DIR}/buildme"
98+
"${BOB_BUILD_DIR}/config"
99+
"${BOB_BUILD_DIR}/buildme" bob_test_bazel_import
100+
101+
TEST_EXECUTABLES=(
102+
bob_test_bazel_cc_import_header_only_normal
103+
bob_test_bazel_cc_import_header_only_includes
104+
bob_test_bazel_cc_import_header_only_strip_prefix
105+
)
106+
107+
for executable in "${TEST_EXECUTABLES[@]}"; do
108+
env "${BOB_BUILD_DIR}/target/executable/${executable}"
109+
done
110+
111+
popd >/dev/null

tests/build_tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ if [ "$OS" != "OSX" ]; then
293293
check_dep_updated "host_bin toc linking" "${build_dir}" "${SRC}" "${UPDATE[@]}"
294294
fi
295295

296+
echo -e "\n* \e[1;32mChecking Bazel cc_import workflow\e[0m"
297+
tests/bazel_cc_import/run_test.sh build-bazel-import
298+
296299
# Check gcc-ar inference when cross-compiler name includes a prefix
297300
echo -e "\n* \e[1;32mChecking gcc-ar inference\e[0m"
298301
build_dir=build-gcc-ar

0 commit comments

Comments
 (0)