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.h" 6 7#include "base/bind.h" 8#include "base/strings/string_util.h" 9#include "base/strings/stringprintf.h" 10#include "tools/gn/config_values_extractors.h" 11#include "tools/gn/deps_iterator.h" 12#include "tools/gn/filesystem_utils.h" 13#include "tools/gn/scheduler.h" 14#include "tools/gn/substitution_writer.h" 15 16namespace { 17 18typedef std::set<const Config*> ConfigSet; 19 20// Merges the public configs from the given target to the given config list. 21void MergePublicConfigsFrom(const Target* from_target, 22 UniqueVector<LabelConfigPair>* dest) { 23 const UniqueVector<LabelConfigPair>& pub = from_target->public_configs(); 24 dest->Append(pub.begin(), pub.end()); 25} 26 27// Like MergePublicConfigsFrom above except does the "all dependent" ones. This 28// additionally adds all configs to the all_dependent_configs_ of the dest 29// target given in *all_dest. 30void MergeAllDependentConfigsFrom(const Target* from_target, 31 UniqueVector<LabelConfigPair>* dest, 32 UniqueVector<LabelConfigPair>* all_dest) { 33 const UniqueVector<LabelConfigPair>& all = 34 from_target->all_dependent_configs(); 35 for (size_t i = 0; i < all.size(); i++) { 36 all_dest->push_back(all[i]); 37 dest->push_back(all[i]); 38 } 39} 40 41Err MakeTestOnlyError(const Target* from, const Target* to) { 42 return Err(from->defined_from(), "Test-only dependency not allowed.", 43 from->label().GetUserVisibleName(false) + "\n" 44 "which is NOT marked testonly can't depend on\n" + 45 to->label().GetUserVisibleName(false) + "\n" 46 "which is marked testonly. Only targets with \"testonly = true\"\n" 47 "can depend on other test-only targets.\n" 48 "\n" 49 "Either mark it test-only or don't do this dependency."); 50} 51 52Err MakeStaticLibDepsError(const Target* from, const Target* to) { 53 return Err(from->defined_from(), 54 "Complete static libraries can't depend on static libraries.", 55 from->label().GetUserVisibleName(false) + 56 "\n" 57 "which is a complete static library can't depend on\n" + 58 to->label().GetUserVisibleName(false) + 59 "\n" 60 "which is a static library.\n" 61 "\n" 62 "Use source sets for intermediate targets instead."); 63} 64 65} // namespace 66 67Target::Target(const Settings* settings, const Label& label) 68 : Item(settings, label), 69 output_type_(UNKNOWN), 70 all_headers_public_(true), 71 check_includes_(true), 72 complete_static_lib_(false), 73 testonly_(false), 74 hard_dep_(false), 75 toolchain_(NULL) { 76} 77 78Target::~Target() { 79} 80 81// static 82const char* Target::GetStringForOutputType(OutputType type) { 83 switch (type) { 84 case UNKNOWN: 85 return "Unknown"; 86 case GROUP: 87 return "Group"; 88 case EXECUTABLE: 89 return "Executable"; 90 case SHARED_LIBRARY: 91 return "Shared library"; 92 case STATIC_LIBRARY: 93 return "Static library"; 94 case SOURCE_SET: 95 return "Source set"; 96 case COPY_FILES: 97 return "Copy"; 98 case ACTION: 99 return "Action"; 100 case ACTION_FOREACH: 101 return "ActionForEach"; 102 default: 103 return ""; 104 } 105} 106 107Target* Target::AsTarget() { 108 return this; 109} 110 111const Target* Target::AsTarget() const { 112 return this; 113} 114 115bool Target::OnResolved(Err* err) { 116 DCHECK(output_type_ != UNKNOWN); 117 DCHECK(toolchain_) << "Toolchain should have been set before resolving."; 118 119 // Copy our own dependent configs to the list of configs applying to us. 120 configs_.Append(all_dependent_configs_.begin(), all_dependent_configs_.end()); 121 MergePublicConfigsFrom(this, &configs_); 122 123 // Copy our own libs and lib_dirs to the final set. This will be from our 124 // target and all of our configs. We do this specially since these must be 125 // inherited through the dependency tree (other flags don't work this way). 126 for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) { 127 const ConfigValues& cur = iter.cur(); 128 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); 129 all_libs_.append(cur.libs().begin(), cur.libs().end()); 130 } 131 132 PullDependentTargetInfo(); 133 PullForwardedDependentConfigs(); 134 PullRecursiveHardDeps(); 135 136 FillOutputFiles(); 137 138 if (!CheckVisibility(err)) 139 return false; 140 if (!CheckTestonly(err)) 141 return false; 142 if (!CheckNoNestedStaticLibs(err)) 143 return false; 144 145 return true; 146} 147 148bool Target::IsLinkable() const { 149 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; 150} 151 152bool Target::IsFinal() const { 153 return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY || 154 (output_type_ == STATIC_LIBRARY && complete_static_lib_); 155} 156 157std::string Target::GetComputedOutputName(bool include_prefix) const { 158 DCHECK(toolchain_) 159 << "Toolchain must be specified before getting the computed output name."; 160 161 const std::string& name = output_name_.empty() ? label().name() 162 : output_name_; 163 164 std::string result; 165 if (include_prefix) { 166 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); 167 const std::string& prefix = tool->output_prefix(); 168 // Only add the prefix if the name doesn't already have it. 169 if (!StartsWithASCII(name, prefix, true)) 170 result = prefix; 171 } 172 173 result.append(name); 174 return result; 175} 176 177bool Target::SetToolchain(const Toolchain* toolchain, Err* err) { 178 DCHECK(!toolchain_); 179 DCHECK_NE(UNKNOWN, output_type_); 180 toolchain_ = toolchain; 181 182 const Tool* tool = toolchain->GetToolForTargetFinalOutput(this); 183 if (tool) 184 return true; 185 186 // Tool not specified for this target type. 187 if (err) { 188 *err = Err(defined_from(), "This target uses an undefined tool.", 189 base::StringPrintf( 190 "The target %s\n" 191 "of type \"%s\"\n" 192 "uses toolchain %s\n" 193 "which doesn't have the tool \"%s\" defined.\n\n" 194 "Alas, I can not continue.", 195 label().GetUserVisibleName(false).c_str(), 196 GetStringForOutputType(output_type_), 197 label().GetToolchainLabel().GetUserVisibleName(false).c_str(), 198 Toolchain::ToolTypeToName( 199 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str())); 200 } 201 return false; 202} 203 204void Target::PullDependentTargetInfo() { 205 // Gather info from our dependents we need. 206 for (DepsIterator iter(this, DepsIterator::LINKED_ONLY); !iter.done(); 207 iter.Advance()) { 208 const Target* dep = iter.target(); 209 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); 210 MergePublicConfigsFrom(dep, &configs_); 211 212 // Direct dependent libraries. 213 if (dep->output_type() == STATIC_LIBRARY || 214 dep->output_type() == SHARED_LIBRARY || 215 dep->output_type() == SOURCE_SET) 216 inherited_libraries_.push_back(dep); 217 218 // Inherited libraries and flags are inherited across static library 219 // boundaries. 220 if (!dep->IsFinal()) { 221 inherited_libraries_.Append(dep->inherited_libraries().begin(), 222 dep->inherited_libraries().end()); 223 224 // Inherited library settings. 225 all_lib_dirs_.append(dep->all_lib_dirs()); 226 all_libs_.append(dep->all_libs()); 227 } 228 } 229} 230 231void Target::PullForwardedDependentConfigs() { 232 // Pull public configs from each of our dependency's public deps. 233 for (size_t dep = 0; dep < public_deps_.size(); dep++) 234 PullForwardedDependentConfigsFrom(public_deps_[dep].ptr); 235 236 // Forward public configs if explicitly requested. 237 for (size_t dep = 0; dep < forward_dependent_configs_.size(); dep++) { 238 const Target* from_target = forward_dependent_configs_[dep].ptr; 239 240 // The forward_dependent_configs_ must be in the deps (public or private) 241 // already, so we don't need to bother copying to our configs, only 242 // forwarding. 243 DCHECK(std::find_if(private_deps_.begin(), private_deps_.end(), 244 LabelPtrPtrEquals<Target>(from_target)) != 245 private_deps_.end() || 246 std::find_if(public_deps_.begin(), public_deps_.end(), 247 LabelPtrPtrEquals<Target>(from_target)) != 248 public_deps_.end()); 249 250 PullForwardedDependentConfigsFrom(from_target); 251 } 252} 253 254void Target::PullForwardedDependentConfigsFrom(const Target* from) { 255 public_configs_.Append(from->public_configs().begin(), 256 from->public_configs().end()); 257} 258 259void Target::PullRecursiveHardDeps() { 260 for (DepsIterator iter(this, DepsIterator::LINKED_ONLY); !iter.done(); 261 iter.Advance()) { 262 if (iter.target()->hard_dep()) 263 recursive_hard_deps_.insert(iter.target()); 264 265 // Android STL doesn't like insert(begin, end) so do it manually. 266 // TODO(brettw) this can be changed to 267 // insert(iter.target()->begin(), iter.target()->end()) 268 // when Android uses a better STL. 269 for (std::set<const Target*>::const_iterator cur = 270 iter.target()->recursive_hard_deps().begin(); 271 cur != iter.target()->recursive_hard_deps().end(); ++cur) 272 recursive_hard_deps_.insert(*cur); 273 } 274} 275 276void Target::FillOutputFiles() { 277 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); 278 switch (output_type_) { 279 case GROUP: 280 case SOURCE_SET: 281 case COPY_FILES: 282 case ACTION: 283 case ACTION_FOREACH: { 284 // These don't get linked to and use stamps which should be the first 285 // entry in the outputs. These stamps are named 286 // "<target_out_dir>/<targetname>.stamp". 287 dependency_output_file_ = GetTargetOutputDirAsOutputFile(this); 288 dependency_output_file_.value().append(GetComputedOutputName(true)); 289 dependency_output_file_.value().append(".stamp"); 290 break; 291 } 292 case EXECUTABLE: 293 // Executables don't get linked to, but the first output is used for 294 // dependency management. 295 CHECK_GE(tool->outputs().list().size(), 1u); 296 dependency_output_file_ = 297 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( 298 this, tool, tool->outputs().list()[0]); 299 break; 300 case STATIC_LIBRARY: 301 // Static libraries both have dependencies and linking going off of the 302 // first output. 303 CHECK(tool->outputs().list().size() >= 1); 304 link_output_file_ = dependency_output_file_ = 305 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( 306 this, tool, tool->outputs().list()[0]); 307 break; 308 case SHARED_LIBRARY: 309 CHECK(tool->outputs().list().size() >= 1); 310 if (tool->link_output().empty() && tool->depend_output().empty()) { 311 // Default behavior, use the first output file for both. 312 link_output_file_ = dependency_output_file_ = 313 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( 314 this, tool, tool->outputs().list()[0]); 315 } else { 316 // Use the tool-specified ones. 317 if (!tool->link_output().empty()) { 318 link_output_file_ = 319 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( 320 this, tool, tool->link_output()); 321 } 322 if (!tool->depend_output().empty()) { 323 dependency_output_file_ = 324 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( 325 this, tool, tool->depend_output()); 326 } 327 } 328 break; 329 case UNKNOWN: 330 default: 331 NOTREACHED(); 332 } 333} 334 335bool Target::CheckVisibility(Err* err) const { 336 for (DepsIterator iter(this); !iter.done(); iter.Advance()) { 337 if (!Visibility::CheckItemVisibility(this, iter.target(), err)) 338 return false; 339 } 340 return true; 341} 342 343bool Target::CheckTestonly(Err* err) const { 344 // If the current target is marked testonly, it can include both testonly 345 // and non-testonly targets, so there's nothing to check. 346 if (testonly()) 347 return true; 348 349 // Verify no deps have "testonly" set. 350 for (DepsIterator iter(this); !iter.done(); iter.Advance()) { 351 if (iter.target()->testonly()) { 352 *err = MakeTestOnlyError(this, iter.target()); 353 return false; 354 } 355 } 356 357 return true; 358} 359 360bool Target::CheckNoNestedStaticLibs(Err* err) const { 361 // If the current target is not a complete static library, it can depend on 362 // static library targets with no problem. 363 if (!(output_type() == Target::STATIC_LIBRARY && complete_static_lib())) 364 return true; 365 366 // Verify no deps are static libraries. 367 for (DepsIterator iter(this); !iter.done(); iter.Advance()) { 368 if (iter.target()->output_type() == Target::STATIC_LIBRARY) { 369 *err = MakeStaticLibDepsError(this, iter.target()); 370 return false; 371 } 372 } 373 374 // Verify no inherited libraries are static libraries. 375 for (size_t i = 0; i < inherited_libraries().size(); ++i) { 376 if (inherited_libraries()[i]->output_type() == Target::STATIC_LIBRARY) { 377 *err = MakeStaticLibDepsError(this, inherited_libraries()[i]); 378 return false; 379 } 380 } 381 return true; 382} 383