Forbid Rust source_sets.
These are not currently used by either Fuchsia or Chromium,
as current best practice is to use groups instead. It's not clear
what the purpose of a Rust source_set would be, since only the
crate_root is fed to rustc anyway; any other sources just act
as implicit dependencies.
A subsequent commit will allow Rust targets to depend upon C++
source sets, and that change is much less invasive if Rust
source sets are not possible.
Change-Id: I28f5c931c793aa80fbf7116519cc22ae3631efc2
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/8240
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/functions_target.cc b/src/gn/functions_target.cc
index 5ce0901..0864db5 100644
--- a/src/gn/functions_target.cc
+++ b/src/gn/functions_target.cc
@@ -740,8 +740,7 @@
const char kSourceSet_Help[] =
R"(source_set: Declare a source set target.
- The language of a source_set target is determined by the extensions present
- in its sources.
+ Only C-language source sets are supported at the moment.
C-language source_sets
@@ -766,13 +765,6 @@
not from the intermediate targets." There is no way to express this concept
when linking multiple static libraries into a shared library.
-Rust-language source_sets
-
- A Rust source set is a collection of sources that get passed along to the
- final target that depends on it. No compilation is performed, and the source
- files are simply added as dependencies on the eventual rustc invocation that
- would produce a binary.
-
Variables
)" CONFIG_VALUES_VARS_HELP DEPS_VARS DEPENDENT_CONFIG_VARS GENERAL_TARGET_VARS;
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc
index 1a3e9b9..cde6be6 100644
--- a/src/gn/ninja_binary_target_writer.cc
+++ b/src/gn/ninja_binary_target_writer.cc
@@ -196,9 +196,49 @@
void NinjaBinaryTargetWriter::AddSourceSetFiles(
const Target* source_set,
UniqueVector<OutputFile>* obj_files) const {
- // Just add all sources to the list.
+ std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
+
+ // Compute object files for all sources. Only link the first output from
+ // the tool if there are more than one.
for (const auto& source : source_set->sources()) {
- obj_files->push_back(OutputFile(settings_->build_settings(), source));
+ const char* tool_name = Tool::kToolNone;
+ if (source_set->GetOutputFilesForSource(source, &tool_name, &tool_outputs))
+ obj_files->push_back(tool_outputs[0]);
+ }
+
+ // 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 (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 (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 (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) {
+ GetPCHOutputFiles(source_set, CTool::kCToolObjC, &tool_outputs);
+ obj_files->Append(tool_outputs.begin(), tool_outputs.end());
+ }
+ }
+ 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) {
+ GetPCHOutputFiles(source_set, CTool::kCToolObjCxx, &tool_outputs);
+ obj_files->Append(tool_outputs.begin(), tool_outputs.end());
+ }
+ }
}
}
diff --git a/src/gn/ninja_binary_target_writer.h b/src/gn/ninja_binary_target_writer.h
index 7539ebb..69f5b50 100644
--- a/src/gn/ninja_binary_target_writer.h
+++ b/src/gn/ninja_binary_target_writer.h
@@ -65,8 +65,8 @@
void WriteLibs(std::ostream& out, const Tool* tool);
void WriteFrameworks(std::ostream& out, const Tool* tool);
- virtual void AddSourceSetFiles(const Target* source_set,
- UniqueVector<OutputFile>* obj_files) const;
+ void AddSourceSetFiles(const Target* source_set,
+ UniqueVector<OutputFile>* obj_files) const;
// Cached version of the prefix used for rule types for this toolchain.
std::string rule_prefix_;
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index ebc2d17..5fa646f 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -639,54 +639,3 @@
}
return true;
}
-
-// Appends the object files generated by the given source set to the given
-// output vector.
-void NinjaCBinaryTargetWriter::AddSourceSetFiles(
- const Target* source_set,
- UniqueVector<OutputFile>* obj_files) const {
- std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
-
- // Compute object files for all sources. Only link the first output from
- // the tool if there are more than one.
- for (const auto& source : source_set->sources()) {
- const char* tool_name = Tool::kToolNone;
- if (source_set->GetOutputFilesForSource(source, &tool_name, &tool_outputs))
- obj_files->push_back(tool_outputs[0]);
- }
-
- // 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 (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 (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 (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) {
- GetPCHOutputFiles(source_set, CTool::kCToolObjC, &tool_outputs);
- obj_files->Append(tool_outputs.begin(), tool_outputs.end());
- }
- }
- 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) {
- GetPCHOutputFiles(source_set, CTool::kCToolObjCxx, &tool_outputs);
- obj_files->Append(tool_outputs.begin(), tool_outputs.end());
- }
- }
- }
-}
diff --git a/src/gn/ninja_c_binary_target_writer.h b/src/gn/ninja_c_binary_target_writer.h
index 55cc0fc..ee6b6ac 100644
--- a/src/gn/ninja_c_binary_target_writer.h
+++ b/src/gn/ninja_c_binary_target_writer.h
@@ -22,11 +22,6 @@
void Run() override;
- protected:
- // Adds source_set files to the list of object files.
- void AddSourceSetFiles(const Target* source_set,
- UniqueVector<OutputFile>* obj_files) const override;
-
private:
using OutputFileSet = std::set<OutputFile>;
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index 8a907bb..abe903f 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -122,72 +122,68 @@
// -Ldependency rustdeps, and non-public source_sets get passed in as normal
// source files
UniqueVector<OutputFile> deps;
- AddSourceSetFiles(target_, &deps);
- if (target_->output_type() == Target::SOURCE_SET) {
- WriteSharedVars(target_->toolchain()->substitution_bits());
- WriteSourceSetStamp(deps.vector());
- } else {
- WriteCompilerVars();
- UniqueVector<const Target*> linkable_deps;
- UniqueVector<const Target*> non_linkable_deps;
- UniqueVector<const Target*> framework_deps;
- GetDeps(&deps, &linkable_deps, &non_linkable_deps, &framework_deps);
+ DCHECK(target_->output_type() != Target::SOURCE_SET);
+ WriteCompilerVars();
+ UniqueVector<const Target*> linkable_deps;
+ UniqueVector<const Target*> non_linkable_deps;
+ UniqueVector<const Target*> framework_deps;
+ GetDeps(&deps, &linkable_deps, &non_linkable_deps, &framework_deps);
+ AppendSourcesToImplicitDeps(&deps);
- if (!input_dep.value().empty())
- order_only_deps.push_back(input_dep);
+ if (!input_dep.value().empty())
+ order_only_deps.push_back(input_dep);
- std::vector<OutputFile> rustdeps;
- std::vector<OutputFile> nonrustdeps;
- for (const auto* framework_dep : framework_deps) {
- order_only_deps.push_back(framework_dep->dependency_output_file());
- }
- for (const auto* non_linkable_dep : non_linkable_deps) {
- if (non_linkable_dep->source_types_used().RustSourceUsed() &&
- non_linkable_dep->output_type() != Target::SOURCE_SET) {
- rustdeps.push_back(non_linkable_dep->dependency_output_file());
- }
- order_only_deps.push_back(non_linkable_dep->dependency_output_file());
- }
- for (const auto* linkable_dep : linkable_deps) {
- if (linkable_dep->source_types_used().RustSourceUsed()) {
- rustdeps.push_back(linkable_dep->link_output_file());
- } else {
- nonrustdeps.push_back(linkable_dep->link_output_file());
- }
- deps.push_back(linkable_dep->dependency_output_file());
- }
-
- // Rust libraries specified by paths.
- for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
- const ConfigValues& cur = iter.cur();
- for (const auto& e : cur.externs()) {
- if (e.second.is_source_file()) {
- deps.push_back(
- OutputFile(settings_->build_settings(), e.second.source_file()));
- }
- }
- }
-
- std::vector<OutputFile> transitive_rustlibs;
- for (const auto* dep :
- target_->rust_values().transitive_libs().GetOrdered()) {
- if (dep->source_types_used().RustSourceUsed()) {
- transitive_rustlibs.push_back(dep->dependency_output_file());
- }
- }
-
- std::vector<OutputFile> tool_outputs;
- SubstitutionWriter::ApplyListToLinkerAsOutputFile(
- target_, tool_, tool_->outputs(), &tool_outputs);
- WriteCompilerBuildLine(target_->rust_values().crate_root(), deps.vector(),
- order_only_deps, tool_->name(), tool_outputs);
-
- std::vector<const Target*> extern_deps(linkable_deps.vector());
- std::copy(non_linkable_deps.begin(), non_linkable_deps.end(),
- std::back_inserter(extern_deps));
- WriteExterns(extern_deps);
- WriteRustdeps(transitive_rustlibs, rustdeps, nonrustdeps);
+ std::vector<OutputFile> rustdeps;
+ std::vector<OutputFile> nonrustdeps;
+ for (const auto* framework_dep : framework_deps) {
+ order_only_deps.push_back(framework_dep->dependency_output_file());
}
+ for (const auto* non_linkable_dep : non_linkable_deps) {
+ if (non_linkable_dep->source_types_used().RustSourceUsed() &&
+ non_linkable_dep->output_type() != Target::SOURCE_SET) {
+ rustdeps.push_back(non_linkable_dep->dependency_output_file());
+ }
+ order_only_deps.push_back(non_linkable_dep->dependency_output_file());
+ }
+ for (const auto* linkable_dep : linkable_deps) {
+ if (linkable_dep->source_types_used().RustSourceUsed()) {
+ rustdeps.push_back(linkable_dep->link_output_file());
+ } else {
+ nonrustdeps.push_back(linkable_dep->link_output_file());
+ }
+ deps.push_back(linkable_dep->dependency_output_file());
+ }
+
+ // Rust libraries specified by paths.
+ for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
+ const ConfigValues& cur = iter.cur();
+ for (const auto& e : cur.externs()) {
+ if (e.second.is_source_file()) {
+ deps.push_back(
+ OutputFile(settings_->build_settings(), e.second.source_file()));
+ }
+ }
+ }
+
+ std::vector<OutputFile> transitive_rustlibs;
+ for (const auto* dep :
+ target_->rust_values().transitive_libs().GetOrdered()) {
+ if (dep->source_types_used().RustSourceUsed()) {
+ transitive_rustlibs.push_back(dep->dependency_output_file());
+ }
+ }
+
+ std::vector<OutputFile> tool_outputs;
+ SubstitutionWriter::ApplyListToLinkerAsOutputFile(
+ target_, tool_, tool_->outputs(), &tool_outputs);
+ WriteCompilerBuildLine(target_->rust_values().crate_root(), deps.vector(),
+ order_only_deps, tool_->name(), tool_outputs);
+
+ std::vector<const Target*> extern_deps(linkable_deps.vector());
+ std::copy(non_linkable_deps.begin(), non_linkable_deps.end(),
+ std::back_inserter(extern_deps));
+ WriteExterns(extern_deps);
+ WriteRustdeps(transitive_rustlibs, rustdeps, nonrustdeps);
}
void NinjaRustBinaryTargetWriter::WriteCompilerVars() {
@@ -205,6 +201,18 @@
WriteSharedVars(subst);
}
+void NinjaRustBinaryTargetWriter::AppendSourcesToImplicitDeps(
+ UniqueVector<OutputFile>* deps) const {
+ // Only the crate_root file needs to be given to rustc as input.
+ // Any other 'sources' are just implicit deps.
+ // Most Rust targets won't bother specifying the "sources =" line
+ // because it is handled sufficiently by crate_root and the generation
+ // of depfiles by rustc. But for those which do...
+ for (const auto& source : target_->sources()) {
+ deps->push_back(OutputFile(settings_->build_settings(), source));
+ }
+}
+
void NinjaRustBinaryTargetWriter::WriteExterns(
const std::vector<const Target*>& deps) {
out_ << " externs =";
diff --git a/src/gn/ninja_rust_binary_target_writer.h b/src/gn/ninja_rust_binary_target_writer.h
index cd845d5..4d6e146 100644
--- a/src/gn/ninja_rust_binary_target_writer.h
+++ b/src/gn/ninja_rust_binary_target_writer.h
@@ -26,9 +26,10 @@
const std::vector<OutputFile>& order_only_deps);
void WriteExterns(const std::vector<const Target*>& deps);
void WriteRustdeps(const std::vector<OutputFile>& transitive_rustdeps,
- const std::vector<OutputFile>& rustdeps,
- const std::vector<OutputFile>& nonrustdeps);
+ const std::vector<OutputFile>& rustdeps,
+ const std::vector<OutputFile>& nonrustdeps);
void WriteEdition();
+ void AppendSourcesToImplicitDeps(UniqueVector<OutputFile>* deps) const;
const RustTool* tool_;
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index ded290a..70a7d00 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -26,39 +26,13 @@
target.sources().push_back(SourceFile("//foo/main.rs"));
target.source_types_used().Set(SourceFile::SOURCE_RS);
target.SetToolchain(setup.toolchain());
- ASSERT_TRUE(target.OnResolved(&err));
-
- // Source set itself.
- {
- std::ostringstream out;
- NinjaRustBinaryTargetWriter writer(&target, out);
- writer.Run();
-
- const char expected[] =
- "root_out_dir = .\n"
- "target_out_dir = obj/foo\n"
- "target_output_name = bar\n"
- "\n"
- "build obj/foo/bar.stamp: stamp ../../foo/input1.rs "
- "../../foo/main.rs\n";
- std::string out_str = out.str();
- EXPECT_EQ(expected, out_str) << out_str;
- }
+ ASSERT_FALSE(target.OnResolved(&err));
}
TEST_F(NinjaRustBinaryTargetWriterTest, RustExecutable) {
Err err;
TestWithScope setup;
- Target source_set(setup.settings(), Label(SourceDir("//foo/"), "sources"));
- source_set.set_output_type(Target::SOURCE_SET);
- source_set.visibility().SetPublic();
- source_set.sources().push_back(SourceFile("//foo/input1.rs"));
- source_set.sources().push_back(SourceFile("//foo/input2.rs"));
- source_set.source_types_used().Set(SourceFile::SOURCE_RS);
- source_set.SetToolchain(setup.toolchain());
- ASSERT_TRUE(source_set.OnResolved(&err));
-
Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
target.set_output_type(Target::EXECUTABLE);
target.visibility().SetPublic();
@@ -68,7 +42,6 @@
target.source_types_used().Set(SourceFile::SOURCE_RS);
target.rust_values().set_crate_root(main);
target.rust_values().crate_name() = "foo_bar";
- target.private_deps().push_back(LabelTargetPair(&source_set));
target.SetToolchain(setup.toolchain());
ASSERT_TRUE(target.OnResolved(&err));
@@ -89,8 +62,7 @@
"target_output_name = bar\n"
"\n"
"build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/input3.rs "
- "../../foo/main.rs ../../foo/input1.rs ../../foo/input2.rs || "
- "obj/foo/sources.stamp\n"
+ "../../foo/main.rs\n"
" externs =\n"
" rustdeps =\n";
std::string out_str = out.str();
@@ -495,15 +467,6 @@
Err err;
TestWithScope setup;
- Target source_set(setup.settings(), Label(SourceDir("//foo/"), "sources"));
- source_set.set_output_type(Target::SOURCE_SET);
- source_set.visibility().SetPublic();
- source_set.sources().push_back(SourceFile("//foo/input1.rs"));
- source_set.sources().push_back(SourceFile("//foo/input2.rs"));
- source_set.source_types_used().Set(SourceFile::SOURCE_RS);
- source_set.SetToolchain(setup.toolchain());
- ASSERT_TRUE(source_set.OnResolved(&err));
-
Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
target.set_output_type(Target::EXECUTABLE);
target.visibility().SetPublic();
@@ -515,7 +478,6 @@
target.set_output_dir(SourceDir("//out/Debug/foo/"));
target.rust_values().set_crate_root(main);
target.rust_values().crate_name() = "foo_bar";
- target.private_deps().push_back(LabelTargetPair(&source_set));
target.SetToolchain(setup.toolchain());
ASSERT_TRUE(target.OnResolved(&err));
@@ -536,8 +498,7 @@
"target_output_name = bar\n"
"\n"
"build ./foo_bar.exe: rust_bin ../../foo/main.rs | ../../foo/input3.rs "
- "../../foo/main.rs ../../foo/input1.rs ../../foo/input2.rs || "
- "obj/foo/sources.stamp\n"
+ "../../foo/main.rs\n"
" externs =\n"
" rustdeps =\n";
std::string out_str = out.str();
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 93ad7c0..ef91167 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -383,6 +383,8 @@
if (!FillOutputFiles(err))
return false;
+ if (!CheckSourceSetLanguages(err))
+ return false;
if (!CheckVisibility(err))
return false;
if (!CheckTestonly(err))
@@ -934,6 +936,17 @@
return true;
}
+bool Target::CheckSourceSetLanguages(Err* err) const {
+ if (output_type() == Target::SOURCE_SET &&
+ source_types_used().RustSourceUsed()) {
+ *err = Err(defined_from(), "source_set contained Rust code.",
+ label().GetUserVisibleName(false) +
+ " has Rust code. Only C/C++ source_sets are supported.");
+ return false;
+ }
+ return true;
+}
+
bool Target::CheckTestonly(Err* err) const {
// If the current target is marked testonly, it can include both testonly
// and non-testonly targets, so there's nothing to check.
diff --git a/src/gn/target.h b/src/gn/target.h
index 700859c..44f7e17 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -407,6 +407,7 @@
bool CheckAssertNoDeps(Err* err) const;
void CheckSourcesGenerated() const;
void CheckSourceGenerated(const SourceFile& source) const;
+ bool CheckSourceSetLanguages(Err* err) const;
OutputType output_type_ = UNKNOWN;
std::string output_name_;