Move SourceFileTypeSet to Target Have the target track which types of source files it contains, and check that only one type exists. Prevents recompution in a few places, but also allows for checking what language a target should be compiled under. Note that it will error out if complilation-incompatible source types are used (e.g. having C and C++ in the same target is fine, but having C and Rust in the same target isn't). Change-Id: I5afb038e4cfa7da79c9f264cee79a8c652797dc3 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/4880 Commit-Queue: Julie Hockett <juliehockett@google.com> Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc index f1e4ea4..1f568b4 100644 --- a/tools/gn/binary_target_generator.cc +++ b/tools/gn/binary_target_generator.cc
@@ -9,6 +9,7 @@ #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/scope.h" #include "tools/gn/settings.h" #include "tools/gn/value_extractors.h" @@ -60,6 +61,9 @@ if (!FillCompleteStaticLib()) return; + if (!ValidateSources()) + return; + // Config values (compiler flags, etc.) set directly on this target. ConfigValuesGenerator gen(&target_->config_values(), scope_, scope_->GetSourceDir(), err_); @@ -82,7 +86,6 @@ case SourceFile::SOURCE_ASM: case SourceFile::SOURCE_O: case SourceFile::SOURCE_DEF: - case SourceFile::SOURCE_RS: case SourceFile::SOURCE_GO: case SourceFile::SOURCE_RC: // These are allowed. @@ -96,6 +99,8 @@ Target::GetStringForOutputType(target_->output_type()) + ". " + source.value() + " is not one of the valid types."); } + + target_->source_types_used().Set(source.type()); } return ret; } @@ -211,3 +216,14 @@ target_->allow_circular_includes_from().insert(cur); return true; } + +bool BinaryTargetGenerator::ValidateSources() { + 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; +}
diff --git a/tools/gn/binary_target_generator.h b/tools/gn/binary_target_generator.h index 6cbd11e..e0700dd 100644 --- a/tools/gn/binary_target_generator.h +++ b/tools/gn/binary_target_generator.h
@@ -32,6 +32,7 @@ bool FillOutputDir(); bool FillOutputExtension(); bool FillAllowCircularIncludesFrom(); + bool ValidateSources(); Target::OutputType output_type_;
diff --git a/tools/gn/functions_target_unittest.cc b/tools/gn/functions_target_unittest.cc index 642b8ce..40c6fde 100644 --- a/tools/gn/functions_target_unittest.cc +++ b/tools/gn/functions_target_unittest.cc
@@ -174,3 +174,23 @@ good_input.parsed()->Execute(setup.scope(), &err); ASSERT_FALSE(err.has_error()) << err.message(); } + +// Checks that we find unused identifiers in targets. +TEST_F(FunctionsTarget, MixedSourceError) { + TestWithScope setup; + + // The target generator needs a place to put the targets or it will fail. + Scope::ItemVector item_collector; + setup.scope()->set_item_collector(&item_collector); + + // Test a good one first. + TestParseInput good_input( + "source_set(\"foo\") {\n" + " sources = [ \"cpp.cc\", \"rust.rs\" ]" + "}\n"); + ASSERT_FALSE(good_input.has_error()); + Err err; + good_input.parsed()->Execute(setup.scope(), &err); + ASSERT_TRUE(err.has_error()); + ASSERT_EQ(err.message(), "More than one language used in target sources."); +} \ No newline at end of file
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc index bf3ee35..c1209ed 100644 --- a/tools/gn/ninja_binary_target_writer.cc +++ b/tools/gn/ninja_binary_target_writer.cc
@@ -27,21 +27,6 @@ #include "tools/gn/substitution_writer.h" #include "tools/gn/target.h" -bool NinjaBinaryTargetWriter::SourceFileTypeSet::CSourceUsed() { - return Get(SourceFile::SOURCE_CPP) || Get(SourceFile::SOURCE_H) || - Get(SourceFile::SOURCE_C) || Get(SourceFile::SOURCE_M) || - Get(SourceFile::SOURCE_MM) || Get(SourceFile::SOURCE_RC) || - Get(SourceFile::SOURCE_S); -} - -bool NinjaBinaryTargetWriter::SourceFileTypeSet::RustSourceUsed() { - return Get(SourceFile::SOURCE_RS); -} - -bool NinjaBinaryTargetWriter::SourceFileTypeSet::GoSourceUsed() { - return Get(SourceFile::SOURCE_GO); -} - NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, std::ostream& out) : NinjaTargetWriter(target, out),
diff --git a/tools/gn/ninja_binary_target_writer.h b/tools/gn/ninja_binary_target_writer.h index 24d7ef1..f0611d7 100644 --- a/tools/gn/ninja_binary_target_writer.h +++ b/tools/gn/ninja_binary_target_writer.h
@@ -13,33 +13,11 @@ #include "tools/gn/unique_vector.h" struct EscapeOptions; -class SourceFileTypeSet; // Writes a .ninja file for a binary target type (an executable, a shared // library, or a static library). class NinjaBinaryTargetWriter : public NinjaTargetWriter { public: - // Represents a set of tool types. - class SourceFileTypeSet { - public: - SourceFileTypeSet() { - memset(flags_, 0, - sizeof(bool) * static_cast<int>(SourceFile::SOURCE_NUMTYPES)); - } - - void Set(SourceFile::Type type) { flags_[static_cast<int>(type)] = true; } - bool Get(SourceFile::Type type) const { - return flags_[static_cast<int>(type)]; - } - - bool CSourceUsed(); - bool RustSourceUsed(); - bool GoSourceUsed(); - - private: - bool flags_[static_cast<int>(SourceFile::SOURCE_NUMTYPES)]; - }; - NinjaBinaryTargetWriter(const Target* target, std::ostream& out); ~NinjaBinaryTargetWriter() override;
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc index bb059e1..7e92ad4 100644 --- a/tools/gn/ninja_binary_target_writer_unittest.cc +++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -23,6 +23,8 @@ // dependents to link. target.sources().push_back(SourceFile("//foo/input3.o")); target.sources().push_back(SourceFile("//foo/input4.obj")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); + target.source_types_used().Set(SourceFile::SOURCE_O); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err));
diff --git a/tools/gn/ninja_c_binary_target_writer.cc b/tools/gn/ninja_c_binary_target_writer.cc index 4e8217b..041c0a1 100644 --- a/tools/gn/ninja_c_binary_target_writer.cc +++ b/tools/gn/ninja_c_binary_target_writer.cc
@@ -57,7 +57,6 @@ void AddSourceSetObjectFiles(const Target* source_set, UniqueVector<OutputFile>* obj_files) { std::vector<OutputFile> tool_outputs; // Prevent allocation in loop. - NinjaBinaryTargetWriter::SourceFileTypeSet used_types; // Compute object files for all sources. Only link the first output from // the tool if there are more than one. @@ -65,28 +64,26 @@ const char* tool_name = Tool::kToolNone; if (source_set->GetOutputFilesForSource(source, &tool_name, &tool_outputs)) obj_files->push_back(tool_outputs[0]); - - used_types.Set(source.type()); } // Add MSVC precompiled header object files. GCC .gch files are not object // files so they are omitted. if (source_set->config_values().has_precompiled_headers()) { - if (used_types.Get(SourceFile::SOURCE_C)) { + if (source_set->source_types_used().Get(SourceFile::SOURCE_C)) { const CTool* tool = source_set->toolchain()->GetToolAsC(CTool::kCToolCc); if (tool && tool->precompiled_header_type() == CTool::PCH_MSVC) { GetPCHOutputFiles(source_set, CTool::kCToolCc, &tool_outputs); obj_files->Append(tool_outputs.begin(), tool_outputs.end()); } } - if (used_types.Get(SourceFile::SOURCE_CPP)) { + if (source_set->source_types_used().Get(SourceFile::SOURCE_CPP)) { const CTool* tool = source_set->toolchain()->GetToolAsC(CTool::kCToolCxx); if (tool && tool->precompiled_header_type() == CTool::PCH_MSVC) { GetPCHOutputFiles(source_set, CTool::kCToolCxx, &tool_outputs); obj_files->Append(tool_outputs.begin(), tool_outputs.end()); } } - if (used_types.Get(SourceFile::SOURCE_M)) { + if (source_set->source_types_used().Get(SourceFile::SOURCE_M)) { const CTool* tool = source_set->toolchain()->GetToolAsC(CTool::kCToolObjC); if (tool && tool->precompiled_header_type() == CTool::PCH_MSVC) { @@ -94,7 +91,7 @@ obj_files->Append(tool_outputs.begin(), tool_outputs.end()); } } - if (used_types.Get(SourceFile::SOURCE_MM)) { + if (source_set->source_types_used().Get(SourceFile::SOURCE_MM)) { const CTool* tool = source_set->toolchain()->GetToolAsC(CTool::kCToolObjCxx); if (tool && tool->precompiled_header_type() == CTool::PCH_MSVC) { @@ -115,12 +112,7 @@ NinjaCBinaryTargetWriter::~NinjaCBinaryTargetWriter() = default; void NinjaCBinaryTargetWriter::Run() { - // Figure out what source types are needed. - SourceFileTypeSet used_types; - for (const auto& source : target_->sources()) - used_types.Set(source.type()); - - WriteCompilerVars(used_types); + WriteCompilerVars(); OutputFile input_dep = WriteInputsStampAndGetDep(); @@ -163,7 +155,7 @@ // |pch_other_files|. This is to prevent linking against them. std::vector<OutputFile> pch_obj_files; std::vector<OutputFile> pch_other_files; - WritePCHCommands(used_types, input_dep, order_only_deps, &pch_obj_files, + WritePCHCommands(input_dep, order_only_deps, &pch_obj_files, &pch_other_files); std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ? &pch_obj_files : &pch_other_files; @@ -206,8 +198,7 @@ } } -void NinjaCBinaryTargetWriter::WriteCompilerVars( - const SourceFileTypeSet& used_types) { +void NinjaCBinaryTargetWriter::WriteCompilerVars() { const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); // Defines. @@ -234,34 +225,34 @@ target_->config_values().has_precompiled_headers(); EscapeOptions opts = GetFlagOptions(); - if (used_types.Get(SourceFile::SOURCE_S) || - used_types.Get(SourceFile::SOURCE_ASM)) { + if (target_->source_types_used().Get(SourceFile::SOURCE_S) || + target_->source_types_used().Get(SourceFile::SOURCE_ASM)) { WriteOneFlag(target_, &CSubstitutionAsmFlags, false, Tool::kToolNone, &ConfigValues::asmflags, opts, path_output_, out_); } - if (used_types.Get(SourceFile::SOURCE_C) || - used_types.Get(SourceFile::SOURCE_CPP) || - used_types.Get(SourceFile::SOURCE_M) || - used_types.Get(SourceFile::SOURCE_MM)) { + if (target_->source_types_used().Get(SourceFile::SOURCE_C) || + target_->source_types_used().Get(SourceFile::SOURCE_CPP) || + target_->source_types_used().Get(SourceFile::SOURCE_M) || + target_->source_types_used().Get(SourceFile::SOURCE_MM)) { WriteOneFlag(target_, &CSubstitutionCFlags, false, Tool::kToolNone, &ConfigValues::cflags, opts, path_output_, out_); } - if (used_types.Get(SourceFile::SOURCE_C)) { + if (target_->source_types_used().Get(SourceFile::SOURCE_C)) { WriteOneFlag(target_, &CSubstitutionCFlagsC, has_precompiled_headers, CTool::kCToolCc, &ConfigValues::cflags_c, opts, path_output_, out_); } - if (used_types.Get(SourceFile::SOURCE_CPP)) { + if (target_->source_types_used().Get(SourceFile::SOURCE_CPP)) { WriteOneFlag(target_, &CSubstitutionCFlagsCc, has_precompiled_headers, CTool::kCToolCxx, &ConfigValues::cflags_cc, opts, path_output_, out_); } - if (used_types.Get(SourceFile::SOURCE_M)) { + if (target_->source_types_used().Get(SourceFile::SOURCE_M)) { WriteOneFlag(target_, &CSubstitutionCFlagsObjC, has_precompiled_headers, CTool::kCToolObjC, &ConfigValues::cflags_objc, opts, path_output_, out_); } - if (used_types.Get(SourceFile::SOURCE_MM)) { + if (target_->source_types_used().Get(SourceFile::SOURCE_MM)) { WriteOneFlag(target_, &CSubstitutionCFlagsObjCc, has_precompiled_headers, CTool::kCToolObjCxx, &ConfigValues::cflags_objcc, opts, path_output_, out_); @@ -311,7 +302,6 @@ } void NinjaCBinaryTargetWriter::WritePCHCommands( - const SourceFileTypeSet& used_types, const OutputFile& input_dep, const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, @@ -321,14 +311,14 @@ const CTool* tool_c = target_->toolchain()->GetToolAsC(CTool::kCToolCc); if (tool_c && tool_c->precompiled_header_type() != CTool::PCH_NONE && - used_types.Get(SourceFile::SOURCE_C)) { + target_->source_types_used().Get(SourceFile::SOURCE_C)) { WritePCHCommand(&CSubstitutionCFlagsC, CTool::kCToolCc, tool_c->precompiled_header_type(), input_dep, order_only_deps, object_files, other_files); } const CTool* tool_cxx = target_->toolchain()->GetToolAsC(CTool::kCToolCxx); if (tool_cxx && tool_cxx->precompiled_header_type() != CTool::PCH_NONE && - used_types.Get(SourceFile::SOURCE_CPP)) { + target_->source_types_used().Get(SourceFile::SOURCE_CPP)) { WritePCHCommand(&CSubstitutionCFlagsCc, CTool::kCToolCxx, tool_cxx->precompiled_header_type(), input_dep, order_only_deps, object_files, other_files); @@ -336,7 +326,7 @@ const CTool* tool_objc = target_->toolchain()->GetToolAsC(CTool::kCToolObjC); if (tool_objc && tool_objc->precompiled_header_type() == CTool::PCH_GCC && - used_types.Get(SourceFile::SOURCE_M)) { + target_->source_types_used().Get(SourceFile::SOURCE_M)) { WritePCHCommand(&CSubstitutionCFlagsObjC, CTool::kCToolObjC, tool_objc->precompiled_header_type(), input_dep, order_only_deps, object_files, other_files); @@ -345,7 +335,7 @@ const CTool* tool_objcxx = target_->toolchain()->GetToolAsC(CTool::kCToolObjCxx); if (tool_objcxx && tool_objcxx->precompiled_header_type() == CTool::PCH_GCC && - used_types.Get(SourceFile::SOURCE_MM)) { + target_->source_types_used().Get(SourceFile::SOURCE_MM)) { WritePCHCommand(&CSubstitutionCFlagsObjCc, CTool::kCToolObjCxx, tool_objcxx->precompiled_header_type(), input_dep, order_only_deps, object_files, other_files);
diff --git a/tools/gn/ninja_c_binary_target_writer.h b/tools/gn/ninja_c_binary_target_writer.h index 4d1bdfa..d236dd9 100644 --- a/tools/gn/ninja_c_binary_target_writer.h +++ b/tools/gn/ninja_c_binary_target_writer.h
@@ -26,7 +26,7 @@ typedef std::set<OutputFile> OutputFileSet; // Writes all flags for the compiler: includes, defines, cflags, etc. - void WriteCompilerVars(const SourceFileTypeSet& used_types); + void WriteCompilerVars(); // Writes to the output stream a stamp rule for inputs, and // returns the file to be appended to source rules that encodes the @@ -41,8 +41,7 @@ // // input_dep is the stamp file collecting the dependencies required before // compiling this target. It will be empty if there are no input deps. - void WritePCHCommands(const SourceFileTypeSet& used_types, - const OutputFile& input_dep, + void WritePCHCommands(const OutputFile& input_dep, const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* object_files, std::vector<OutputFile>* other_files);
diff --git a/tools/gn/ninja_c_binary_target_writer_unittest.cc b/tools/gn/ninja_c_binary_target_writer_unittest.cc index 829114a..3281176 100644 --- a/tools/gn/ninja_c_binary_target_writer_unittest.cc +++ b/tools/gn/ninja_c_binary_target_writer_unittest.cc
@@ -32,6 +32,8 @@ // dependents to link. target.sources().push_back(SourceFile("//foo/input3.o")); target.sources().push_back(SourceFile("//foo/input4.obj")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); + target.source_types_used().Set(SourceFile::SOURCE_O); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -182,6 +184,7 @@ TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY); target.sources().push_back(SourceFile("//foo/input1.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.config_values().arflags().push_back("--asdf"); ASSERT_TRUE(target.OnResolved(&err)); @@ -214,11 +217,13 @@ TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY); target.sources().push_back(SourceFile("//foo/input1.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.config_values().arflags().push_back("--asdf"); target.set_complete_static_lib(true); TestTarget baz(setup, "//foo:baz", Target::STATIC_LIBRARY); baz.sources().push_back(SourceFile("//foo/input2.cc")); + baz.source_types_used().Set(SourceFile::SOURCE_CPP); target.public_deps().push_back(LabelTargetPair(&baz)); @@ -303,6 +308,7 @@ target.set_output_dir(SourceDir("//out/Debug/foo/")); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.public_deps().push_back(LabelTargetPair(&action)); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -361,6 +367,7 @@ gen_obj.set_output_type(Target::SOURCE_SET); gen_obj.set_output_dir(SourceDir("//out/Debug/foo/")); gen_obj.sources().push_back(generated_file); + gen_obj.source_types_used().Set(SourceFile::SOURCE_CPP); gen_obj.visibility().SetPublic(); gen_obj.private_deps().push_back(LabelTargetPair(&action)); gen_obj.set_all_headers_public(false); @@ -397,6 +404,7 @@ gen_lib.set_output_type(Target::SHARED_LIBRARY); gen_lib.set_output_dir(SourceDir("//out/Debug/foo/")); gen_lib.sources().push_back(SourceFile("//foor/generated.h")); + gen_lib.source_types_used().Set(SourceFile::SOURCE_H); gen_lib.visibility().SetPublic(); gen_lib.private_deps().push_back(LabelTargetPair(&gen_obj)); gen_lib.SetToolchain(setup.toolchain()); @@ -433,6 +441,7 @@ executable.set_output_type(Target::EXECUTABLE); executable.set_output_dir(SourceDir("//out/Debug/foo/")); executable.sources().push_back(SourceFile("//foo/main.cc")); + executable.source_types_used().Set(SourceFile::SOURCE_CPP); executable.private_deps().push_back(LabelTargetPair(&gen_lib)); executable.SetToolchain(setup.toolchain()); ASSERT_TRUE(executable.OnResolved(&err)) << err.message(); @@ -513,6 +522,7 @@ target.set_output_extension(std::string()); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -562,6 +572,7 @@ inter.data_deps().push_back(LabelTargetPair(&data)); inter.SetToolchain(setup.toolchain()); inter.sources().push_back(SourceFile("//foo/inter.cc")); + inter.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(inter.OnResolved(&err)) << err.message(); // Write out the intermediate target. @@ -593,6 +604,7 @@ exe.public_deps().push_back(LabelTargetPair(&inter)); exe.SetToolchain(setup.toolchain()); exe.sources().push_back(SourceFile("//foo/final.cc")); + exe.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(exe.OnResolved(&err)); std::ostringstream final_out; @@ -633,6 +645,8 @@ shared_lib.SetToolchain(setup.toolchain()); shared_lib.sources().push_back(SourceFile("//foo/sources.cc")); shared_lib.sources().push_back(SourceFile("//foo/bar.def")); + shared_lib.source_types_used().Set(SourceFile::SOURCE_CPP); + shared_lib.source_types_used().Set(SourceFile::SOURCE_DEF); ASSERT_TRUE(shared_lib.OnResolved(&err)); std::ostringstream out; @@ -667,6 +681,7 @@ loadable_module.visibility().SetPublic(); loadable_module.SetToolchain(setup.toolchain()); loadable_module.sources().push_back(SourceFile("//foo/sources.cc")); + loadable_module.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(loadable_module.OnResolved(&err)) << err.message(); std::ostringstream out; @@ -697,6 +712,7 @@ exe.public_deps().push_back(LabelTargetPair(&loadable_module)); exe.SetToolchain(setup.toolchain()); exe.sources().push_back(SourceFile("//foo/final.cc")); + exe.source_types_used().Set(SourceFile::SOURCE_CPP); ASSERT_TRUE(exe.OnResolved(&err)) << err.message(); std::ostringstream final_out; @@ -770,6 +786,8 @@ no_pch_target.visibility().SetPublic(); no_pch_target.sources().push_back(SourceFile("//foo/input1.cc")); no_pch_target.sources().push_back(SourceFile("//foo/input2.c")); + no_pch_target.source_types_used().Set(SourceFile::SOURCE_CPP); + no_pch_target.source_types_used().Set(SourceFile::SOURCE_C); no_pch_target.config_values().cflags_c().push_back("-std=c99"); no_pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(no_pch_target.OnResolved(&err)); @@ -807,6 +825,8 @@ pch_target.visibility().SetPublic(); pch_target.sources().push_back(SourceFile("//foo/input1.cc")); pch_target.sources().push_back(SourceFile("//foo/input2.c")); + pch_target.source_types_used().Set(SourceFile::SOURCE_CPP); + pch_target.source_types_used().Set(SourceFile::SOURCE_C); pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(pch_target.OnResolved(&err)); @@ -900,6 +920,8 @@ no_pch_target.visibility().SetPublic(); no_pch_target.sources().push_back(SourceFile("//foo/input1.cc")); no_pch_target.sources().push_back(SourceFile("//foo/input2.c")); + no_pch_target.source_types_used().Set(SourceFile::SOURCE_CPP); + no_pch_target.source_types_used().Set(SourceFile::SOURCE_C); no_pch_target.config_values().cflags_c().push_back("-std=c99"); no_pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(no_pch_target.OnResolved(&err)); @@ -937,6 +959,8 @@ pch_target.visibility().SetPublic(); pch_target.sources().push_back(SourceFile("//foo/input1.cc")); pch_target.sources().push_back(SourceFile("//foo/input2.c")); + pch_target.source_types_used().Set(SourceFile::SOURCE_CPP); + pch_target.source_types_used().Set(SourceFile::SOURCE_C); pch_target.SetToolchain(&pch_toolchain); ASSERT_TRUE(pch_target.OnResolved(&err)); @@ -985,6 +1009,7 @@ TestTarget target(setup, "//foo:bar", Target::EXECUTABLE); target.sources().push_back(SourceFile("//a.cc")); target.sources().push_back(SourceFile("//a.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); EXPECT_FALSE(scheduler().is_failed()); @@ -1013,6 +1038,7 @@ target.visibility().SetPublic(); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.config_values().inputs().push_back(SourceFile("//foo/input.data")); target.SetToolchain(setup.toolchain()); ASSERT_TRUE(target.OnResolved(&err)); @@ -1078,6 +1104,7 @@ target.visibility().SetPublic(); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.config_values().inputs().push_back(SourceFile("//foo/input1.data")); target.config_values().inputs().push_back(SourceFile("//foo/input2.data")); target.SetToolchain(setup.toolchain()); @@ -1126,6 +1153,7 @@ target.visibility().SetPublic(); target.sources().push_back(SourceFile("//foo/input1.cc")); target.sources().push_back(SourceFile("//foo/input2.cc")); + target.source_types_used().Set(SourceFile::SOURCE_CPP); target.config_values().inputs().push_back(SourceFile("//foo/input1.data")); target.configs().push_back(LabelConfigPair(&config)); target.SetToolchain(setup.toolchain());
diff --git a/tools/gn/source_file.cc b/tools/gn/source_file.cc index 266a072..f925546 100644 --- a/tools/gn/source_file.cc +++ b/tools/gn/source_file.cc
@@ -99,3 +99,30 @@ value_ = value; type_ = GetSourceFileType(value_); } + +SourceFileTypeSet::SourceFileTypeSet() : empty_(true) { + memset(flags_, 0, + sizeof(bool) * static_cast<int>(SourceFile::SOURCE_NUMTYPES)); +} + +bool SourceFileTypeSet::CSourceUsed() const { + return empty_ || Get(SourceFile::SOURCE_CPP) || Get(SourceFile::SOURCE_H) || + Get(SourceFile::SOURCE_C) || Get(SourceFile::SOURCE_M) || + Get(SourceFile::SOURCE_MM) || Get(SourceFile::SOURCE_RC) || + Get(SourceFile::SOURCE_S) || Get(SourceFile::SOURCE_O) || + Get(SourceFile::SOURCE_DEF); +} + +bool SourceFileTypeSet::RustSourceUsed() const { + return Get(SourceFile::SOURCE_RS); +} + +bool SourceFileTypeSet::GoSourceUsed() const { + return Get(SourceFile::SOURCE_GO); +} + +bool SourceFileTypeSet::MixedSourceUsed() const { + return (1 << static_cast<int>(CSourceUsed()) + << static_cast<int>(RustSourceUsed()) + << static_cast<int>(GoSourceUsed())) > 2; +}
diff --git a/tools/gn/source_file.h b/tools/gn/source_file.h index d42063d..ed814c8 100644 --- a/tools/gn/source_file.h +++ b/tools/gn/source_file.h
@@ -129,4 +129,30 @@ lhs.swap(rhs); } +// Represents a set of tool types. +class SourceFileTypeSet { + public: + SourceFileTypeSet(); + + void Set(SourceFile::Type type) { + flags_[static_cast<int>(type)] = true; + empty_ = false; + } + bool Get(SourceFile::Type type) const { + return flags_[static_cast<int>(type)]; + } + + bool empty() const { return empty_; } + + bool CSourceUsed() const; + bool RustSourceUsed() const; + bool GoSourceUsed() const; + + bool MixedSourceUsed() const; + + private: + bool empty_; + bool flags_[static_cast<int>(SourceFile::SOURCE_NUMTYPES)]; +}; + #endif // TOOLS_GN_SOURCE_FILE_H_
diff --git a/tools/gn/target.h b/tools/gn/target.h index e99d813..1256818 100644 --- a/tools/gn/target.h +++ b/tools/gn/target.h
@@ -125,6 +125,11 @@ const FileList& sources() const { return sources_; } FileList& sources() { return sources_; } + const SourceFileTypeSet& source_types_used() const { + return source_types_used_; + } + SourceFileTypeSet& source_types_used() { return source_types_used_; } + // Set to true when all sources are public. This is the default. In this case // the public headers list should be empty. bool all_headers_public() const { return all_headers_public_; } @@ -367,6 +372,7 @@ bool output_extension_set_; FileList sources_; + SourceFileTypeSet source_types_used_; bool all_headers_public_; FileList public_headers_; bool check_includes_;