|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "tools/gn/binary_target_generator.h" | 
|  |  | 
|  | #include "tools/gn/config_values_generator.h" | 
|  | #include "tools/gn/deps_iterator.h" | 
|  | #include "tools/gn/err.h" | 
|  | #include "tools/gn/filesystem_utils.h" | 
|  | #include "tools/gn/functions.h" | 
|  | #include "tools/gn/parse_tree.h" | 
|  | #include "tools/gn/rust_values_generator.h" | 
|  | #include "tools/gn/rust_variables.h" | 
|  | #include "tools/gn/scope.h" | 
|  | #include "tools/gn/settings.h" | 
|  | #include "tools/gn/value_extractors.h" | 
|  | #include "tools/gn/variables.h" | 
|  |  | 
|  | BinaryTargetGenerator::BinaryTargetGenerator( | 
|  | Target* target, | 
|  | Scope* scope, | 
|  | const FunctionCallNode* function_call, | 
|  | Target::OutputType type, | 
|  | Err* err) | 
|  | : TargetGenerator(target, scope, function_call, err), output_type_(type) {} | 
|  |  | 
|  | BinaryTargetGenerator::~BinaryTargetGenerator() = default; | 
|  |  | 
|  | void BinaryTargetGenerator::DoRun() { | 
|  | target_->set_output_type(output_type_); | 
|  |  | 
|  | if (!FillOutputName()) | 
|  | return; | 
|  |  | 
|  | if (!FillOutputPrefixOverride()) | 
|  | return; | 
|  |  | 
|  | if (!FillOutputDir()) | 
|  | return; | 
|  |  | 
|  | if (!FillOutputExtension()) | 
|  | return; | 
|  |  | 
|  | if (!FillSources()) | 
|  | return; | 
|  |  | 
|  | if (!FillPublic()) | 
|  | return; | 
|  |  | 
|  | if (!FillFriends()) | 
|  | return; | 
|  |  | 
|  | if (!FillCheckIncludes()) | 
|  | return; | 
|  |  | 
|  | if (!FillConfigs()) | 
|  | return; | 
|  |  | 
|  | if (!FillAllowCircularIncludesFrom()) | 
|  | return; | 
|  |  | 
|  | if (!FillCompleteStaticLib()) | 
|  | return; | 
|  |  | 
|  | if (!ValidateSources()) | 
|  | return; | 
|  |  | 
|  | if (target_->source_types_used().RustSourceUsed()) { | 
|  | RustTargetGenerator rustgen(target_, scope_, function_call_, err_); | 
|  | rustgen.Run(); | 
|  | if (err_->has_error()) | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Config values (compiler flags, etc.) set directly on this target. | 
|  | ConfigValuesGenerator gen(&target_->config_values(), scope_, | 
|  | scope_->GetSourceDir(), err_); | 
|  | gen.Run(); | 
|  | if (err_->has_error()) | 
|  | return; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillSources() { | 
|  | bool ret = TargetGenerator::FillSources(); | 
|  | for (std::size_t i = 0; i < target_->sources().size(); ++i) { | 
|  | const auto& source = target_->sources()[i]; | 
|  | switch (source.type()) { | 
|  | case SourceFile::SOURCE_CPP: | 
|  | case SourceFile::SOURCE_H: | 
|  | case SourceFile::SOURCE_C: | 
|  | case SourceFile::SOURCE_M: | 
|  | case SourceFile::SOURCE_MM: | 
|  | case SourceFile::SOURCE_S: | 
|  | case SourceFile::SOURCE_ASM: | 
|  | case SourceFile::SOURCE_O: | 
|  | case SourceFile::SOURCE_DEF: | 
|  | case SourceFile::SOURCE_GO: | 
|  | case SourceFile::SOURCE_RS: | 
|  | case SourceFile::SOURCE_RC: | 
|  | // These are allowed. | 
|  | break; | 
|  | case SourceFile::SOURCE_UNKNOWN: | 
|  | case SourceFile::SOURCE_NUMTYPES: | 
|  | *err_ = | 
|  | Err(scope_->GetValue(variables::kSources, true)->list_value()[i], | 
|  | std::string("Only source, header, and object files belong in " | 
|  | "the sources of a ") + | 
|  | Target::GetStringForOutputType(target_->output_type()) + | 
|  | ". " + source.value() + " is not one of the valid types."); | 
|  | } | 
|  |  | 
|  | target_->source_types_used().Set(source.type()); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillCompleteStaticLib() { | 
|  | if (target_->output_type() == Target::STATIC_LIBRARY) { | 
|  | const Value* value = scope_->GetValue(variables::kCompleteStaticLib, true); | 
|  | if (!value) | 
|  | return true; | 
|  | if (!value->VerifyTypeIs(Value::BOOLEAN, err_)) | 
|  | return false; | 
|  | target_->set_complete_static_lib(value->boolean_value()); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillFriends() { | 
|  | const Value* value = scope_->GetValue(variables::kFriend, true); | 
|  | if (value) { | 
|  | return ExtractListOfLabelPatterns(*value, scope_->GetSourceDir(), | 
|  | &target_->friends(), err_); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillOutputName() { | 
|  | const Value* value = scope_->GetValue(variables::kOutputName, true); | 
|  | if (!value) | 
|  | return true; | 
|  | if (!value->VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  | target_->set_output_name(value->string_value()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillOutputPrefixOverride() { | 
|  | const Value* value = scope_->GetValue(variables::kOutputPrefixOverride, true); | 
|  | if (!value) | 
|  | return true; | 
|  | if (!value->VerifyTypeIs(Value::BOOLEAN, err_)) | 
|  | return false; | 
|  | target_->set_output_prefix_override(value->boolean_value()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillOutputDir() { | 
|  | const Value* value = scope_->GetValue(variables::kOutputDir, true); | 
|  | if (!value) | 
|  | return true; | 
|  | if (!value->VerifyTypeIs(Value::STRING, err_)) | 
|  | return false; | 
|  |  | 
|  | if (value->string_value().empty()) | 
|  | return true;  // Treat empty string as the default and do nothing. | 
|  |  | 
|  | const BuildSettings* build_settings = scope_->settings()->build_settings(); | 
|  | SourceDir dir = scope_->GetSourceDir().ResolveRelativeDir( | 
|  | *value, err_, build_settings->root_path_utf8()); | 
|  | if (err_->has_error()) | 
|  | return false; | 
|  |  | 
|  | if (!EnsureStringIsInOutputDir(build_settings->build_dir(), dir.value(), | 
|  | value->origin(), err_)) | 
|  | return false; | 
|  | target_->set_output_dir(dir); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::FillAllowCircularIncludesFrom() { | 
|  | const Value* value = | 
|  | scope_->GetValue(variables::kAllowCircularIncludesFrom, true); | 
|  | if (!value) | 
|  | return true; | 
|  |  | 
|  | UniqueVector<Label> circular; | 
|  | ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(), | 
|  | ToolchainLabelForScope(scope_), &circular, err_); | 
|  | if (err_->has_error()) | 
|  | return false; | 
|  |  | 
|  | // Validate that all circular includes entries are in the deps. | 
|  | for (const auto& cur : circular) { | 
|  | bool found_dep = false; | 
|  | for (const auto& dep_pair : target_->GetDeps(Target::DEPS_LINKED)) { | 
|  | if (dep_pair.label == cur) { | 
|  | found_dep = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (!found_dep) { | 
|  | *err_ = Err(*value, "Label not in deps.", | 
|  | "The label \"" + cur.GetUserVisibleName(false) + | 
|  | "\"\nwas not in the deps of this target. " | 
|  | "allow_circular_includes_from only allows\ntargets " | 
|  | "present in the " | 
|  | "deps."); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Add to the set. | 
|  | for (const auto& cur : circular) | 
|  | target_->allow_circular_includes_from().insert(cur); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BinaryTargetGenerator::ValidateSources() { | 
|  | // For Rust targets, if the only source file is the root `sources` can be | 
|  | // omitted/empty. | 
|  | if (scope_->GetValue(variables::kRustCrateRoot, false)) { | 
|  | target_->source_types_used().Set(SourceFile::SOURCE_RS); | 
|  | } | 
|  |  | 
|  | if (target_->source_types_used().MixedSourceUsed()) { | 
|  | *err_ = | 
|  | Err(function_call_, "More than one language used in target sources.", | 
|  | "Mixed sources are not allowed, unless they are " | 
|  | "compilation-compatible (e.g. Objective C and C++)."); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } |