Commit af8a964b authored by brettw's avatar brettw Committed by Commit bot

Allow multiple set_default calls in GN.

Allow multipe set_defaults calls in GN to override one another, and allow
imported .gni files with set_defaults calls in them to not collide with
existing defaults settings as long as the settings are the same.

This will allow us to be more flexible with defaults, in particular, to
allow the defaults for templates to move to the template declaration location
rather than having to reside in BUILDCONFIG.

Add an android condition around an android-specific config in base I noticed
when testing this patch.

BUG=627978

Review-Url: https://codereview.chromium.org/2148993002
Cr-Commit-Position: refs/heads/master@{#405539}
parent 805bf6aa
...@@ -108,8 +108,10 @@ if (is_nacl) { ...@@ -108,8 +108,10 @@ if (is_nacl) {
} }
} }
config("android_system_libs") { if (is_android) {
libs = [ "log" ] # Used by logging.cc. config("android_system_libs") {
libs = [ "log" ] # Used by logging.cc.
}
} }
# Base and everything it depends on should be a static library rather than # Base and everything it depends on should be a static library rather than
......
...@@ -27,9 +27,14 @@ const char kSetDefaults_Help[] = ...@@ -27,9 +27,14 @@ const char kSetDefaults_Help[] =
"\n" "\n"
" set_defaults can be used for built-in target types (\"executable\",\n" " set_defaults can be used for built-in target types (\"executable\",\n"
" \"shared_library\", etc.) and custom ones defined via the \"template\"\n" " \"shared_library\", etc.) and custom ones defined via the \"template\"\n"
" command.\n" " command. It can be called more than once and the most recent call in\n"
" any scope will apply, but there is no way to refer to the previous\n"
" defaults and modify them (each call to set_defaults must supply a\n"
" complete list of all defaults it wants). If you want to share\n"
" defaults, store them in a separate variable.\n"
"\n"
"Example\n"
"\n" "\n"
"Example:\n"
" set_defaults(\"static_library\") {\n" " set_defaults(\"static_library\") {\n"
" configs = [ \"//tools/mything:settings\" ]\n" " configs = [ \"//tools/mything:settings\" ]\n"
" }\n" " }\n"
...@@ -49,27 +54,6 @@ Value RunSetDefaults(Scope* scope, ...@@ -49,27 +54,6 @@ Value RunSetDefaults(Scope* scope,
return Value(); return Value();
const std::string& target_type(args[0].string_value()); const std::string& target_type(args[0].string_value());
// Ensure there aren't defaults already set.
//
// It might be nice to allow multiple calls set mutate the defaults. The
// main case for this is where some local portions of the code want
// additional defaults they specify in an imported file.
//
// Currently, we don't allow imports to clobber anything, so this wouldn't
// work. Additionally, allowing this would be undesirable since we don't
// want multiple imports to each try to set defaults, since it might look
// like the defaults are modified by each one in sequence, while in fact
// imports would always clobber previous values and it would be confusing.
//
// If we wanted this, the solution would be to allow imports to overwrite
// target defaults set up by the default build config only. That way there
// are no ordering issues, but this would be more work.
if (scope->GetTargetDefaults(target_type)) {
*err = Err(function->function(),
"This target type defaults were already set.");
return Value();
}
if (!block) { if (!block) {
FillNeedsBlockError(function, err); FillNeedsBlockError(function, err);
return Value(); return Value();
......
...@@ -298,18 +298,27 @@ bool Scope::NonRecursiveMergeTo(Scope* dest, ...@@ -298,18 +298,27 @@ bool Scope::NonRecursiveMergeTo(Scope* dest,
} }
if (!options.clobber_existing) { if (!options.clobber_existing) {
if (dest->GetTargetDefaults(current_name)) { const Scope* dest_defaults = dest->GetTargetDefaults(current_name);
// TODO(brettw) it would be nice to know the origin of a if (dest_defaults) {
// set_target_defaults so we can give locations for the colliding target if (RecordMapValuesEqual(pair.second->values_,
// defaults. dest_defaults->values_)) {
std::string desc_string(desc_for_err); // Values of the two defaults are equivalent, just ignore the
*err = Err(node_for_err, "Target defaults collision.", // collision.
"This " + desc_string + " contains target defaults for\n" continue;
"\"" + current_name + "\" which would clobber one for the\n" } else {
"same target type in your current scope. It's unfortunate that I'm " // TODO(brettw) it would be nice to know the origin of a
"too stupid\nto tell you the location of where the target defaults " // set_target_defaults so we can give locations for the colliding
"were set. Usually\nthis happens in the BUILDCONFIG.gn file."); // target defaults.
return false; std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Target defaults collision.",
"This " + desc_string + " contains target defaults for\n"
"\"" + current_name + "\" which would clobber one for the\n"
"same target type in your current scope. It's unfortunate that "
"I'm too stupid\nto tell you the location of where the target "
"defaults were set. Usually\nthis happens in the BUILDCONFIG.gn "
"file or in a related .gni file.\n");
return false;
}
} }
} }
...@@ -404,14 +413,7 @@ std::unique_ptr<Scope> Scope::MakeClosure() const { ...@@ -404,14 +413,7 @@ std::unique_ptr<Scope> Scope::MakeClosure() const {
} }
Scope* Scope::MakeTargetDefaults(const std::string& target_type) { Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
if (GetTargetDefaults(target_type))
return nullptr;
std::unique_ptr<Scope>& dest = target_defaults_[target_type]; std::unique_ptr<Scope>& dest = target_defaults_[target_type];
if (dest) {
NOTREACHED(); // Already set.
return dest.get();
}
dest = base::WrapUnique(new Scope(settings_)); dest = base::WrapUnique(new Scope(settings_));
return dest.get(); return dest.get();
} }
...@@ -514,3 +516,17 @@ void Scope::RemoveProvider(ProgrammaticProvider* p) { ...@@ -514,3 +516,17 @@ void Scope::RemoveProvider(ProgrammaticProvider* p) {
DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end()); DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
programmatic_providers_.erase(p); programmatic_providers_.erase(p);
} }
// static
bool Scope::RecordMapValuesEqual(const RecordMap& a, const RecordMap& b) {
if (a.size() != b.size())
return false;
for (const auto& pair : a) {
const auto& found_b = b.find(pair.first);
if (found_b == b.end())
return false; // Item in 'a' but not 'b'.
if (pair.second.value != found_b->second.value)
return false; // Values for variable in 'a' and 'b' are different.
}
return true;
}
...@@ -229,8 +229,7 @@ class Scope { ...@@ -229,8 +229,7 @@ class Scope {
// change, we don't have to copy its values). // change, we don't have to copy its values).
std::unique_ptr<Scope> MakeClosure() const; std::unique_ptr<Scope> MakeClosure() const;
// Makes an empty scope with the given name. Returns NULL if the name is // Makes an empty scope with the given name. Overwrites any existing one.
// already set.
Scope* MakeTargetDefaults(const std::string& target_type); Scope* MakeTargetDefaults(const std::string& target_type);
// Gets the scope associated with the given target name, or null if it hasn't // Gets the scope associated with the given target name, or null if it hasn't
...@@ -311,9 +310,16 @@ class Scope { ...@@ -311,9 +310,16 @@ class Scope {
Value value; Value value;
}; };
typedef base::hash_map<base::StringPiece, Record, base::StringPieceHash>
RecordMap;
void AddProvider(ProgrammaticProvider* p); void AddProvider(ProgrammaticProvider* p);
void RemoveProvider(ProgrammaticProvider* p); void RemoveProvider(ProgrammaticProvider* p);
// Returns true if the two RecordMaps contain the same values (the origins
// of the values may be different).
static bool RecordMapValuesEqual(const RecordMap& a, const RecordMap& b);
// Scopes can have no containing scope (both null), a mutable containing // Scopes can have no containing scope (both null), a mutable containing
// scope, or a const containing scope. The reason is that when we're doing // scope, or a const containing scope. The reason is that when we're doing
// a new target, we want to refer to the base_config scope which will be read // a new target, we want to refer to the base_config scope which will be read
...@@ -329,8 +335,6 @@ class Scope { ...@@ -329,8 +335,6 @@ class Scope {
// for more. // for more.
unsigned mode_flags_; unsigned mode_flags_;
typedef base::hash_map<base::StringPiece, Record, base::StringPieceHash>
RecordMap;
RecordMap values_; RecordMap values_;
// Note that this can't use string pieces since the names are constructed from // Note that this can't use string pieces since the names are constructed from
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment