Fix configs visibility not always working
Make visibility apply to configs used via public_configs and
all_dependent_configs -- and not just plain configs. Check visibility
after the three are merged, but before they are recursively expanded.
Before the fix, visibility would be silently ignored if a target used
for example public_configs to access a config it shouldn't see.
Add tests to check that config visibility can reject targets in all the
three cases, and that going through a visible helper target still works
(which would break if visibility was checked too late).
Also, mention in the docs that configs can take a visibility flag and
update reference with `out/gn --markdown help all > docs/reference.md`.
Bug: 252, 22
Change-Id: I941e43fecf22c0ac5aba4e674f3048272edc1d7e
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/12140
Reviewed-by: Shai Barack <shayba@google.com>
Reviewed-by: Petr Hosek <phosek@google.com>
Commit-Queue: Shai Barack <shayba@google.com>
diff --git a/docs/reference.md b/docs/reference.md
index 9104076..8984ff4 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -1753,10 +1753,10 @@
The `output_conversion` variable specified the format to write the
value. See `gn help io_conversion`.
- One of `contents` or `data_keys` must be specified; use of `data` will write
- the contents of that value to file, while use of `data_keys` will trigger a
- metadata collection walk based on the dependencies of the target and the
- optional values of the `rebase` and `walk_keys` variables. See
+ One of `contents` or `data_keys` must be specified; use of `contents` will
+ write the contents of that value to file, while use of `data_keys` will
+ trigger a metadata collection walk based on the dependencies of the target and
+ the optional values of the `rebase` and `walk_keys` variables. See
`gn help metadata`.
Collected metadata, if specified, will be returned in postorder of
@@ -2206,6 +2206,7 @@
libs, precompiled_header, precompiled_source, rustflags,
rustenv, swiftflags
Nested configs: configs
+ General: visibility
```
#### **Variables on a target used to apply configs**
diff --git a/src/gn/config_values_extractors_unittest.cc b/src/gn/config_values_extractors_unittest.cc
index 860d87c..3db4bff 100644
--- a/src/gn/config_values_extractors_unittest.cc
+++ b/src/gn/config_values_extractors_unittest.cc
@@ -36,6 +36,7 @@
// Set up dep2, direct and all dependent configs.
Config dep2_all(setup.settings(), Label(SourceDir("//dep2/"), "all"));
+ dep2_all.visibility().SetPublic();
dep2_all.own_values().cflags().push_back("--dep2-all");
dep2_all.own_values().cflags().push_back("--dep2-all");
dep2_all.own_values().include_dirs().push_back(SourceDir("//dep2/all/"));
@@ -43,6 +44,7 @@
ASSERT_TRUE(dep2_all.OnResolved(&err));
Config dep2_direct(setup.settings(), Label(SourceDir("//dep2/"), "direct"));
+ dep2_direct.visibility().SetPublic();
dep2_direct.own_values().cflags().push_back("--dep2-direct");
dep2_direct.own_values().include_dirs().push_back(
SourceDir("//dep2/direct/"));
@@ -58,16 +60,19 @@
// Set up dep1, direct and all dependent configs. Also set up a subconfig
// on "dep1_all" to test sub configs.
Config dep1_all_sub(setup.settings(), Label(SourceDir("//dep1"), "allch"));
+ dep1_all_sub.visibility().SetPublic();
dep1_all_sub.own_values().cflags().push_back("--dep1-all-sub");
ASSERT_TRUE(dep1_all_sub.OnResolved(&err));
Config dep1_all(setup.settings(), Label(SourceDir("//dep1/"), "all"));
+ dep1_all.visibility().SetPublic();
dep1_all.own_values().cflags().push_back("--dep1-all");
dep1_all.own_values().include_dirs().push_back(SourceDir("//dep1/all/"));
dep1_all.configs().push_back(LabelConfigPair(&dep1_all_sub));
ASSERT_TRUE(dep1_all.OnResolved(&err));
Config dep1_direct(setup.settings(), Label(SourceDir("//dep1/"), "direct"));
+ dep1_direct.visibility().SetPublic();
dep1_direct.own_values().cflags().push_back("--dep1-direct");
dep1_direct.own_values().include_dirs().push_back(
SourceDir("//dep1/direct/"));
diff --git a/src/gn/functions.cc b/src/gn/functions.cc
index 6acf41a..fdb130d 100644
--- a/src/gn/functions.cc
+++ b/src/gn/functions.cc
@@ -332,6 +332,7 @@
CONFIG_VALUES_VARS_HELP
R"( Nested configs: configs
+ General: visibility
Variables on a target used to apply configs
diff --git a/src/gn/target.cc b/src/gn/target.cc
index f0af195..44c5f14 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -338,16 +338,16 @@
ScopedTrace trace(TraceItem::TRACE_ON_RESOLVED, label());
trace.SetToolchain(settings()->toolchain_label());
- // Check visibility for just this target's own configs, before dependents are
- // added.
- if (!CheckConfigVisibility(err))
- return false;
-
// Copy this target's own dependent and public configs to the list of configs
// applying to it.
configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end());
MergePublicConfigsFrom(this, &configs_);
+ // Check visibility for just this target's own configs, before dependents are
+ // added, but after public_configs and all_dependent_configs are merged.
+ if (!CheckConfigVisibility(err))
+ return false;
+
// Copy public configs from all dependencies into the list of configs
// applying to this target (configs_).
PullDependentTargetConfigs();
diff --git a/src/gn/target_unittest.cc b/src/gn/target_unittest.cc
index 792c530..311cbf9 100644
--- a/src/gn/target_unittest.cc
+++ b/src/gn/target_unittest.cc
@@ -511,6 +511,54 @@
ASSERT_FALSE(a.OnResolved(&err));
}
+// Test config visibility failure cases.
+TEST_F(TargetTest, VisibilityConfigFails) {
+ TestWithScope setup;
+ Err err;
+
+ Label config_label(SourceDir("//a/"), "config");
+ Config config(setup.settings(), config_label);
+ config.visibility().SetPrivate(config.label().dir());
+ ASSERT_TRUE(config.OnResolved(&err));
+
+ // Make a target using configs. This should fail.
+ TestTarget a(setup, "//app:a", Target::EXECUTABLE);
+ a.configs().push_back(LabelConfigPair(&config));
+ ASSERT_FALSE(a.OnResolved(&err));
+
+ // A target using public_configs should also fail.
+ TestTarget b(setup, "//app:b", Target::EXECUTABLE);
+ b.public_configs().push_back(LabelConfigPair(&config));
+ ASSERT_FALSE(b.OnResolved(&err));
+
+ // A target using all_dependent_configs should fail as well.
+ TestTarget c(setup, "//app:c", Target::EXECUTABLE);
+ c.all_dependent_configs().push_back(LabelConfigPair(&config));
+ ASSERT_FALSE(c.OnResolved(&err));
+}
+
+// Test Config -> Group -> A where the config is group is visible from A but
+// the config isn't, and the config is visible from the group.
+TEST_F(TargetTest, VisibilityConfigGroup) {
+ TestWithScope setup;
+ Err err;
+
+ Label config_label(SourceDir("//a/"), "config");
+ Config config(setup.settings(), config_label);
+ config.visibility().SetPrivate(config.label().dir());
+ ASSERT_TRUE(config.OnResolved(&err));
+
+ // Make a target using the config in the same directory.
+ TestTarget a(setup, "//a:a", Target::GROUP);
+ a.public_configs().push_back(LabelConfigPair(&config));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ // A target depending on a should be okay.
+ TestTarget b(setup, "//app:b", Target::EXECUTABLE);
+ b.private_deps().push_back(LabelTargetPair(&a));
+ ASSERT_TRUE(b.OnResolved(&err));
+}
+
// Test visibility with a single data_dep.
TEST_F(TargetTest, VisibilityDatadeps) {
TestWithScope setup;