Skip to content

Commit a366b76

Browse files
authored
Update formatting of --extern flags passed to rustc (bazelbuild#892)
* Added test for re-exported symbols * Added check for `extern` flags as well
1 parent 1aea1a6 commit a366b76

File tree

10 files changed

+162
-1
lines changed

10 files changed

+162
-1
lines changed

rust/private/rustc.bzl

+1-1
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ def _crate_to_link_flag(crate_info):
868868
Returns:
869869
list: Link flags for the current crate info
870870
"""
871-
return ["--extern", "{}={}".format(crate_info.name, crate_info.dep.output.path)]
871+
return ["--extern={}={}".format(crate_info.name, crate_info.dep.output.path)]
872872

873873
def _get_crate_dirname(crate):
874874
"""A helper macro used by `add_crate_link_flags` for getting the directory name of the current crate's output path

test/unit/common.bzl

+12
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ def assert_argv_contains_prefix_suffix(env, action, prefix, suffix):
2929
),
3030
)
3131

32+
def assert_argv_contains_prefix(env, action, prefix):
33+
for found_flag in action.argv:
34+
if found_flag.startswith(prefix):
35+
return
36+
unittest.fail(
37+
env,
38+
"Expected an arg with prefix '{prefix}' in {args}".format(
39+
prefix = prefix,
40+
args = action.argv,
41+
),
42+
)
43+
3244
def assert_action_mnemonic(env, action, mnemonic):
3345
if not action.mnemonic == mnemonic:
3446
unittest.fail(

test/unit/exports/BUILD.bazel

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
load(":exports_test.bzl", "exports_test_suite")
2+
3+
exports_test_suite(
4+
name = "exports_test_suite",
5+
)

test/unit/exports/exports_test.bzl

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""Unittest to verify re-exported symbols propagate to downstream crates"""
2+
3+
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
4+
load("//test/unit:common.bzl", "assert_argv_contains_prefix", "assert_argv_contains_prefix_suffix")
5+
6+
def _exports_test_impl(ctx, dependencies, externs):
7+
env = analysistest.begin(ctx)
8+
target = analysistest.target_under_test(env)
9+
10+
action = target.actions[0]
11+
asserts.equals(env, action.mnemonic, "Rustc")
12+
13+
# Transitive symbols that get re-exported are expected to be located by a `-Ldependency` flag.
14+
# The assert below ensures that each dependnecy flag is passed to the Rustc action. For details see
15+
# https://doc.rust-lang.org/rustc/command-line-arguments.html#-l-add-a-directory-to-the-library-search-path
16+
for dep in dependencies:
17+
assert_argv_contains_prefix_suffix(
18+
env = env,
19+
action = action,
20+
prefix = "-Ldependency",
21+
suffix = dep,
22+
)
23+
24+
for dep in externs:
25+
assert_argv_contains_prefix(
26+
env = env,
27+
action = action,
28+
prefix = "--extern={}=".format(dep),
29+
)
30+
31+
return analysistest.end(env)
32+
33+
def _lib_exports_test_impl(ctx):
34+
# This test is only expected to be used with
35+
# `//test/unit/exports/lib_c`
36+
return _exports_test_impl(
37+
ctx = ctx,
38+
dependencies = ["lib_a", "lib_b"],
39+
externs = ["lib_b"],
40+
)
41+
42+
def _test_exports_test_impl(ctx):
43+
# This test is only expected to be used with
44+
# `//test/unit/exports/lib_c:lib_c_test`
45+
return _exports_test_impl(
46+
ctx = ctx,
47+
dependencies = ["lib_a", "lib_b"],
48+
externs = ["lib_b"],
49+
)
50+
51+
lib_exports_test = analysistest.make(_lib_exports_test_impl)
52+
test_exports_test = analysistest.make(_test_exports_test_impl)
53+
54+
def exports_test_suite(name):
55+
"""Entry-point macro called from the BUILD file.
56+
57+
Args:
58+
name (str): Name of the macro.
59+
"""
60+
61+
lib_exports_test(
62+
name = "lib_exports_test",
63+
target_under_test = "//test/unit/exports/lib_c",
64+
)
65+
66+
test_exports_test(
67+
name = "test_exports_test",
68+
target_under_test = "//test/unit/exports/lib_c:lib_c_test",
69+
)
70+
71+
native.test_suite(
72+
name = name,
73+
tests = [
74+
":lib_exports_test",
75+
":test_exports_test",
76+
],
77+
)

test/unit/exports/lib_a/BUILD.bazel

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
load("//rust:defs.bzl", "rust_library")
2+
3+
package(default_visibility = ["//test:__subpackages__"])
4+
5+
rust_library(
6+
name = "lib_a",
7+
srcs = ["src/lib.rs"],
8+
edition = "2018",
9+
)

test/unit/exports/lib_a/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pub fn greeting_from(from: &str) -> String {
2+
format!("Hello from {}!", from)
3+
}
4+
5+
pub fn greeting_a() -> String {
6+
greeting_from("lib_a")
7+
}

test/unit/exports/lib_b/BUILD.bazel

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
load("//rust:defs.bzl", "rust_library")
2+
3+
package(default_visibility = ["//test:__subpackages__"])
4+
5+
rust_library(
6+
name = "lib_b",
7+
srcs = ["src/lib.rs"],
8+
edition = "2018",
9+
deps = ["//test/unit/exports/lib_a"],
10+
)

test/unit/exports/lib_b/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// The functionality from `lib_a` should be usable within this crate
2+
pub use lib_a::{greeting_a, greeting_from};
3+
4+
pub fn greeting_b() -> String {
5+
greeting_from("lib_b")
6+
}

test/unit/exports/lib_c/BUILD.bazel

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
load("//rust:defs.bzl", "rust_library", "rust_test")
2+
3+
package(default_visibility = ["//test:__subpackages__"])
4+
5+
rust_library(
6+
name = "lib_c",
7+
srcs = ["src/lib.rs"],
8+
edition = "2018",
9+
deps = ["//test/unit/exports/lib_b"],
10+
)
11+
12+
rust_test(
13+
name = "lib_c_test",
14+
crate = ":lib_c",
15+
)

test/unit/exports/lib_c/src/lib.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// This symbol is an export that `lib_b` exports are re-exports from `lib_a`.
2+
use lib_b::greeting_from;
3+
4+
pub fn greeting_c() -> String {
5+
greeting_from("lib_c")
6+
}
7+
8+
#[cfg(test)]
9+
mod test {
10+
use super::*;
11+
12+
use lib_b::{greeting_a, greeting_b};
13+
14+
#[test]
15+
fn test_all_greetings() {
16+
assert_eq!(greeting_a(), "Hello from lib_a!".to_owned());
17+
assert_eq!(greeting_b(), "Hello from lib_b!".to_owned());
18+
assert_eq!(greeting_c(), "Hello from lib_c!".to_owned());
19+
}
20+
}

0 commit comments

Comments
 (0)