Index: tools/gn/target_generator.cc |
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc |
index 12d09fca1527092d16ff2b249a47e72ce739fe14..4821da6097c0b47d06064495fde83500004b11cc 100644 |
--- a/tools/gn/target_generator.cc |
+++ b/tools/gn/target_generator.cc |
@@ -217,25 +217,69 @@ void TargetGenerator::FillDependencies() { |
return; |
} |
-void TargetGenerator::FillOutputs() { |
+void TargetGenerator::FillOutputs(bool allow_substitutions) { |
const Value* value = scope_->GetValue(variables::kOutputs, true); |
if (!value) |
return; |
- std::vector<std::string>& outputs = target_->action_values().outputs(); |
- if (!ExtractListOfStringValues(*value, &outputs, err_)) |
+ SubstitutionList& outputs = target_->action_values().outputs(); |
+ if (!outputs.Parse(*value, err_)) |
+ return; |
+ |
+ if (!allow_substitutions) { |
+ // Verify no substitutions were actually used. |
+ if (!outputs.required_types().empty()) { |
+ *err_ = Err(*value, "Source expansions not allowed here.", |
+ "The outputs of this target used source {{expansions}} but this " |
+ "targe type\ndoesn't support them. Just express the outputs " |
+ "literally."); |
+ return; |
+ } |
+ } |
+ |
+ // Check the substitutions used are valid for this purpose. |
+ if (!EnsureValidSourcesSubstitutions(outputs.required_types(), |
+ value->origin(), err_)) |
return; |
// Validate that outputs are in the output dir. |
- bool allow_templates = target_->output_type() == Target::ACTION_FOREACH || |
- target_->output_type() == Target::COPY_FILES; |
- CHECK(outputs.size() == value->list_value().size()); |
- for (size_t i = 0; i < outputs.size(); i++) { |
+ CHECK(outputs.list().size() == value->list_value().size()); |
+ for (size_t i = 0; i < outputs.list().size(); i++) { |
+ if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i], |
+ value->list_value()[i])) |
+ return; |
+ } |
+} |
+ |
+bool TargetGenerator::EnsureSubstitutionIsInOutputDir( |
+ const SubstitutionPattern& pattern, |
+ const Value& original_value) { |
+ if (pattern.ranges().empty()) { |
+ // Pattern is empty, error out (this prevents weirdness below). |
+ *err_ = Err(original_value, "This has an empty value in it."); |
+ return false; |
+ } |
+ |
+ if (pattern.ranges()[0].type == SUBSTITUTION_LITERAL) { |
+ // If the first thing is a literal, it must start with the output dir. |
if (!EnsureStringIsInOutputDir( |
GetBuildSettings()->build_dir(), |
- outputs[i], value->list_value()[i], allow_templates, err_)) |
- return; |
+ pattern.ranges()[0].literal, original_value, err_)) |
+ return false; |
+ } else { |
+ // Otherwise, the first subrange must be a pattern that expands to |
+ // something in the output directory. |
+ if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) { |
+ *err_ = Err(original_value, |
+ "File is not inside output directory.", |
+ "The given file should be in the output directory. Normally you\n" |
+ "would specify\n\"$target_out_dir/foo\" or " |
+ "\"{{source_gen_dir}}/foo\"."); |
+ return false; |
+ } |
} |
+ |
+ return true; |
} |
void TargetGenerator::FillGenericConfigs(const char* var_name, |