| // 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_target_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; |
| } |