The Chromium Chronicle #15: Restricting Target Visibility
Episode 15: by Joe Mason in Montreal, PQ (November, 2020)
Previous episodes
Chrome is a big project with many sub-systems. It's common to find code written for one component that would be useful elsewhere, but might have hidden restrictions. For safety, limit external access to dangerous functionality. For instance, a custom function tuned for specific performance needs:
// Blazing fast for 2-char strings, O(n^3) otherwise.
std::string ConcatShortStringsFast(const std::string& a, const std::string& b);
There are several ways to restrict access. GN visibility rules stop code outside your component from depending on a target. By default targets are visible to all, but you can modify that:
# In components/restricted_component/BUILD.gn
visibility = [
# Applies to all targets in this file.
# Only the given targets can depend on them.
"//components/restricted_component:*",
"//components/authorized_other_component:a_single_target",
]
source_set("internal") {
# This dangerous target should be locked down even more.
visibility = [ "//components/restricted_component:privileged_target" ]
}
Visibility declarations are validated with gn check
, which runs as part of every GN build.
Another mechanism is DEPS include_rules
, which limits access to header files. Every directory inherits include_rules
from its parent, and can modify those rules in its own DEPS
file. All header files included from outside directories must be allowed by the include_rules
.
# In //components/authorized_other_component/DEPS
include_rules = [
# Common directories like //base are inherited from
# //components/DEPS or //DEPS. Also allow includes from
# restricted_component, but not restricted_component/internal.
"+components/restricted_component",
"-components/restricted_component/internal",
# But do allow a single header from internal, for testing.
"+components/restricted_component/internal/test_support.h",
]
To ensure these dependencies are appropriate, changes that add a directory to include_rules
must be approved by that directory's OWNERS
. No approval is needed to restrict a directory using include_rules
! You can ensure that everyone changing your component remembers not to use certain headers by adding an include_rule
forbidding them.
include_rules
are checked by the presubmit, so you won't see any errors until you try to upload a change. To test include_rules
without uploading, run buildtools/checkdeps/checkdeps.py <directory>
.