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_;