1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "tools/gn/target_generator.h" 6 7#include "tools/gn/action_target_generator.h" 8#include "tools/gn/binary_target_generator.h" 9#include "tools/gn/build_settings.h" 10#include "tools/gn/config.h" 11#include "tools/gn/copy_target_generator.h" 12#include "tools/gn/err.h" 13#include "tools/gn/filesystem_utils.h" 14#include "tools/gn/functions.h" 15#include "tools/gn/group_target_generator.h" 16#include "tools/gn/parse_tree.h" 17#include "tools/gn/scheduler.h" 18#include "tools/gn/scope.h" 19#include "tools/gn/token.h" 20#include "tools/gn/value.h" 21#include "tools/gn/value_extractors.h" 22#include "tools/gn/variables.h" 23 24TargetGenerator::TargetGenerator(Target* target, 25 Scope* scope, 26 const FunctionCallNode* function_call, 27 Err* err) 28 : target_(target), 29 scope_(scope), 30 function_call_(function_call), 31 err_(err) { 32} 33 34TargetGenerator::~TargetGenerator() { 35} 36 37void TargetGenerator::Run() { 38 // All target types use these. 39 if (!FillDependentConfigs()) 40 return; 41 42 if (!FillData()) 43 return; 44 45 if (!FillDependencies()) 46 return; 47 48 if (!FillTestonly()) 49 return; 50 51 if (!Visibility::FillItemVisibility(target_, scope_, err_)) 52 return; 53 54 // Do type-specific generation. 55 DoRun(); 56} 57 58// static 59void TargetGenerator::GenerateTarget(Scope* scope, 60 const FunctionCallNode* function_call, 61 const std::vector<Value>& args, 62 const std::string& output_type, 63 Err* err) { 64 // Name is the argument to the function. 65 if (args.size() != 1u || args[0].type() != Value::STRING) { 66 *err = Err(function_call, 67 "Target generator requires one string argument.", 68 "Otherwise I'm not sure what to call this target."); 69 return; 70 } 71 72 // The location of the target is the directory name with no slash at the end. 73 // FIXME(brettw) validate name. 74 const Label& toolchain_label = ToolchainLabelForScope(scope); 75 Label label(scope->GetSourceDir(), args[0].string_value(), 76 toolchain_label.dir(), toolchain_label.name()); 77 78 if (g_scheduler->verbose_logging()) 79 g_scheduler->Log("Defining target", label.GetUserVisibleName(true)); 80 81 scoped_ptr<Target> target(new Target(scope->settings(), label)); 82 target->set_defined_from(function_call); 83 84 // Create and call out to the proper generator. 85 if (output_type == functions::kCopy) { 86 CopyTargetGenerator generator(target.get(), scope, function_call, err); 87 generator.Run(); 88 } else if (output_type == functions::kAction) { 89 ActionTargetGenerator generator(target.get(), scope, function_call, 90 Target::ACTION, err); 91 generator.Run(); 92 } else if (output_type == functions::kActionForEach) { 93 ActionTargetGenerator generator(target.get(), scope, function_call, 94 Target::ACTION_FOREACH, err); 95 generator.Run(); 96 } else if (output_type == functions::kExecutable) { 97 BinaryTargetGenerator generator(target.get(), scope, function_call, 98 Target::EXECUTABLE, err); 99 generator.Run(); 100 } else if (output_type == functions::kGroup) { 101 GroupTargetGenerator generator(target.get(), scope, function_call, err); 102 generator.Run(); 103 } else if (output_type == functions::kSharedLibrary) { 104 BinaryTargetGenerator generator(target.get(), scope, function_call, 105 Target::SHARED_LIBRARY, err); 106 generator.Run(); 107 } else if (output_type == functions::kSourceSet) { 108 BinaryTargetGenerator generator(target.get(), scope, function_call, 109 Target::SOURCE_SET, err); 110 generator.Run(); 111 } else if (output_type == functions::kStaticLibrary) { 112 BinaryTargetGenerator generator(target.get(), scope, function_call, 113 Target::STATIC_LIBRARY, err); 114 generator.Run(); 115 } else { 116 *err = Err(function_call, "Not a known output type", 117 "I am very confused."); 118 } 119 120 if (err->has_error()) 121 return; 122 123 // Save this target for the file. 124 Scope::ItemVector* collector = scope->GetItemCollector(); 125 if (!collector) { 126 *err = Err(function_call, "Can't define a target in this context."); 127 return; 128 } 129 collector->push_back(new scoped_ptr<Item>(target.PassAs<Item>())); 130} 131 132const BuildSettings* TargetGenerator::GetBuildSettings() const { 133 return scope_->settings()->build_settings(); 134} 135 136bool TargetGenerator::FillSources() { 137 const Value* value = scope_->GetValue(variables::kSources, true); 138 if (!value) 139 return true; 140 141 Target::FileList dest_sources; 142 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, 143 scope_->GetSourceDir(), &dest_sources, err_)) 144 return false; 145 target_->sources().swap(dest_sources); 146 return true; 147} 148 149bool TargetGenerator::FillPublic() { 150 const Value* value = scope_->GetValue(variables::kPublic, true); 151 if (!value) 152 return true; 153 154 // If the public headers are defined, don't default to public. 155 target_->set_all_headers_public(false); 156 157 Target::FileList dest_public; 158 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, 159 scope_->GetSourceDir(), &dest_public, err_)) 160 return false; 161 target_->public_headers().swap(dest_public); 162 return true; 163} 164 165bool TargetGenerator::FillInputs() { 166 const Value* value = scope_->GetValue(variables::kInputs, true); 167 if (!value) { 168 // Older versions used "source_prereqs". Allow use of this variable until 169 // all callers are updated. 170 // TODO(brettw) remove this eventually. 171 value = scope_->GetValue("source_prereqs", true); 172 if (!value) 173 return true; 174 } 175 176 Target::FileList dest_inputs; 177 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, 178 scope_->GetSourceDir(), &dest_inputs, err_)) 179 return false; 180 target_->inputs().swap(dest_inputs); 181 return true; 182} 183 184bool TargetGenerator::FillConfigs() { 185 return FillGenericConfigs(variables::kConfigs, &target_->configs()); 186} 187 188bool TargetGenerator::FillDependentConfigs() { 189 if (!FillGenericConfigs(variables::kAllDependentConfigs, 190 &target_->all_dependent_configs())) 191 return false; 192 if (!FillGenericConfigs(variables::kPublicConfigs, 193 &target_->public_configs())) 194 return false; 195 196 // "public_configs" was previously named "direct_dependent_configs", fall 197 // back to that if public_configs was undefined. 198 if (!scope_->GetValue(variables::kPublicConfigs, false)) { 199 if (!FillGenericConfigs("direct_dependent_configs", 200 &target_->public_configs())) 201 return false; 202 } 203 return true; 204} 205 206bool TargetGenerator::FillData() { 207 const Value* value = scope_->GetValue(variables::kData, true); 208 if (!value) 209 return true; 210 211 Target::FileList dest_data; 212 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value, 213 scope_->GetSourceDir(), &dest_data, err_)) 214 return false; 215 target_->data().swap(dest_data); 216 return true; 217} 218 219bool TargetGenerator::FillDependencies() { 220 if (!FillGenericDeps(variables::kDeps, &target_->private_deps())) 221 return false; 222 if (!FillGenericDeps(variables::kPublicDeps, &target_->public_deps())) 223 return false; 224 if (!FillGenericDeps(variables::kDataDeps, &target_->data_deps())) 225 return false; 226 227 // "data_deps" was previously named "datadeps". For backwards-compat, read 228 // the old one if no "data_deps" were specified. 229 if (!scope_->GetValue(variables::kDataDeps, false)) { 230 if (!FillGenericDeps("datadeps", &target_->data_deps())) 231 return false; 232 } 233 234 // This is a list of dependent targets to have their configs fowarded, so 235 // it goes here rather than in FillConfigs. 236 if (!FillForwardDependentConfigs()) 237 return false; 238 return true; 239} 240 241bool TargetGenerator::FillTestonly() { 242 const Value* value = scope_->GetValue(variables::kTestonly, true); 243 if (value) { 244 if (!value->VerifyTypeIs(Value::BOOLEAN, err_)) 245 return false; 246 target_->set_testonly(value->boolean_value()); 247 } 248 return true; 249} 250 251bool TargetGenerator::FillOutputs(bool allow_substitutions) { 252 const Value* value = scope_->GetValue(variables::kOutputs, true); 253 if (!value) 254 return true; 255 256 SubstitutionList& outputs = target_->action_values().outputs(); 257 if (!outputs.Parse(*value, err_)) 258 return false; 259 260 if (!allow_substitutions) { 261 // Verify no substitutions were actually used. 262 if (!outputs.required_types().empty()) { 263 *err_ = Err(*value, "Source expansions not allowed here.", 264 "The outputs of this target used source {{expansions}} but this " 265 "targe type\ndoesn't support them. Just express the outputs " 266 "literally."); 267 return false; 268 } 269 } 270 271 // Check the substitutions used are valid for this purpose. 272 if (!EnsureValidSourcesSubstitutions(outputs.required_types(), 273 value->origin(), err_)) 274 return false; 275 276 // Validate that outputs are in the output dir. 277 CHECK(outputs.list().size() == value->list_value().size()); 278 for (size_t i = 0; i < outputs.list().size(); i++) { 279 if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i], 280 value->list_value()[i])) 281 return false; 282 } 283 return true; 284} 285 286bool TargetGenerator::EnsureSubstitutionIsInOutputDir( 287 const SubstitutionPattern& pattern, 288 const Value& original_value) { 289 if (pattern.ranges().empty()) { 290 // Pattern is empty, error out (this prevents weirdness below). 291 *err_ = Err(original_value, "This has an empty value in it."); 292 return false; 293 } 294 295 if (pattern.ranges()[0].type == SUBSTITUTION_LITERAL) { 296 // If the first thing is a literal, it must start with the output dir. 297 if (!EnsureStringIsInOutputDir( 298 GetBuildSettings()->build_dir(), 299 pattern.ranges()[0].literal, original_value.origin(), err_)) 300 return false; 301 } else { 302 // Otherwise, the first subrange must be a pattern that expands to 303 // something in the output directory. 304 if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) { 305 *err_ = Err(original_value, 306 "File is not inside output directory.", 307 "The given file should be in the output directory. Normally you\n" 308 "would specify\n\"$target_out_dir/foo\" or " 309 "\"{{source_gen_dir}}/foo\"."); 310 return false; 311 } 312 } 313 314 return true; 315} 316 317bool TargetGenerator::FillGenericConfigs(const char* var_name, 318 UniqueVector<LabelConfigPair>* dest) { 319 const Value* value = scope_->GetValue(var_name, true); 320 if (value) { 321 ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(), 322 ToolchainLabelForScope(scope_), dest, err_); 323 } 324 return !err_->has_error(); 325} 326 327bool TargetGenerator::FillGenericDeps(const char* var_name, 328 LabelTargetVector* dest) { 329 const Value* value = scope_->GetValue(var_name, true); 330 if (value) { 331 ExtractListOfLabels(*value, scope_->GetSourceDir(), 332 ToolchainLabelForScope(scope_), dest, err_); 333 } 334 return !err_->has_error(); 335} 336 337bool TargetGenerator::FillForwardDependentConfigs() { 338 const Value* value = scope_->GetValue( 339 variables::kForwardDependentConfigsFrom, true); 340 if (value) { 341 ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(), 342 ToolchainLabelForScope(scope_), 343 &target_->forward_dependent_configs(), err_); 344 } 345 return !err_->has_error(); 346} 347