Fix Rust dependency propagation
Rust -L flags are now the transitive closure of their dependencies
but only use --extern on direct dependencies
Change-Id: I76a46dfb5040bec817c7be299e7acc78785f9a7d
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/7500
Commit-Queue: Petr Hosek <phosek@google.com>
Reviewed-by: Petr Hosek <phosek@google.com>
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index 0f3895a..5ca0750 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -162,12 +162,20 @@
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()));
+ 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);
@@ -178,7 +186,7 @@
std::copy(non_linkable_deps.begin(), non_linkable_deps.end(),
std::back_inserter(extern_deps));
WriteExterns(extern_deps);
- WriteRustdeps(rustdeps, nonrustdeps);
+ WriteRustdeps(transitive_rustlibs, rustdeps, nonrustdeps);
}
}
@@ -235,12 +243,14 @@
}
void NinjaRustBinaryTargetWriter::WriteRustdeps(
+ const std::vector<OutputFile>& transitive_rustdeps,
const std::vector<OutputFile>& rustdeps,
const std::vector<OutputFile>& nonrustdeps) {
out_ << " rustdeps =";
// Rust dependencies.
- for (const auto& rustdep : rustdeps) {
+ for (const auto& rustdep : transitive_rustdeps) {
+ // TODO switch to using --extern priv: after stabilization
out_ << " -Ldependency=";
path_output_.WriteDir(
out_, rustdep.AsSourceFile(settings_->build_settings()).GetDir(),
diff --git a/src/gn/ninja_rust_binary_target_writer.h b/src/gn/ninja_rust_binary_target_writer.h
index 180bd1f..cd845d5 100644
--- a/src/gn/ninja_rust_binary_target_writer.h
+++ b/src/gn/ninja_rust_binary_target_writer.h
@@ -25,8 +25,9 @@
void WriteSources(const OutputFile& input_dep,
const std::vector<OutputFile>& order_only_deps);
void WriteExterns(const std::vector<const Target*>& deps);
- void WriteRustdeps(const std::vector<OutputFile>& rustdeps,
- const std::vector<OutputFile>& nonrustdeps);
+ void WriteRustdeps(const std::vector<OutputFile>& transitive_rustdeps,
+ const std::vector<OutputFile>& rustdeps,
+ const std::vector<OutputFile>& nonrustdeps);
void WriteEdition();
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 44ff61c..b9c2215 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -181,15 +181,138 @@
"target_output_name = bar\n"
"\n"
"build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
- "../../foo/main.rs obj/foo/libdirect.rlib obj/bar/libmylib.rlib\n"
- " externs = --extern direct=obj/foo/libdirect.rlib --extern "
- "mylib=obj/bar/libmylib.rlib\n"
+ "../../foo/main.rs obj/foo/libdirect.rlib\n"
+ " externs = --extern direct=obj/foo/libdirect.rlib\n"
" rustdeps = -Ldependency=obj/foo -Ldependency=obj/bar\n";
std::string out_str = out.str();
EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
}
+TEST_F(NinjaRustBinaryTargetWriterTest, RlibDepsAcrossGroups) {
+ Err err;
+ TestWithScope setup;
+
+ Target procmacro(setup.settings(), Label(SourceDir("//bar/"), "mymacro"));
+ procmacro.set_output_type(Target::RUST_PROC_MACRO);
+ procmacro.visibility().SetPublic();
+ SourceFile barproc("//bar/lib.rs");
+ procmacro.sources().push_back(SourceFile("//bar/mylib.rs"));
+ procmacro.sources().push_back(barproc);
+ procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
+ procmacro.rust_values().set_crate_root(barproc);
+ procmacro.rust_values().crate_name() = "mymacro";
+ procmacro.rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
+ procmacro.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(procmacro.OnResolved(&err));
+
+ {
+ std::ostringstream out;
+ NinjaRustBinaryTargetWriter writer(&procmacro, out);
+ writer.Run();
+
+ const char expected[] =
+ "crate_name = mymacro\n"
+ "crate_type = proc-macro\n"
+ "output_extension = .so\n"
+ "output_dir = \n"
+ "rustflags =\n"
+ "rustenv =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/bar\n"
+ "target_output_name = libmymacro\n"
+ "\n"
+ "build obj/bar/libmymacro.so: rust_macro ../../bar/lib.rs | "
+ "../../bar/mylib.rs ../../bar/lib.rs\n"
+ " externs =\n"
+ " rustdeps =\n";
+ std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+
+ Target group(setup.settings(), Label(SourceDir("//baz/"), "group"));
+ group.set_output_type(Target::GROUP);
+ group.visibility().SetPublic();
+ group.public_deps().push_back(LabelTargetPair(&procmacro));
+ group.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(group.OnResolved(&err));
+
+ Target rlib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
+ rlib.set_output_type(Target::RUST_LIBRARY);
+ rlib.visibility().SetPublic();
+ SourceFile barlib("//bar/lib.rs");
+ rlib.sources().push_back(SourceFile("//bar/mylib.rs"));
+ rlib.sources().push_back(barlib);
+ rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+ rlib.rust_values().set_crate_root(barlib);
+ rlib.rust_values().crate_name() = "mylib";
+ rlib.SetToolchain(setup.toolchain());
+ rlib.public_deps().push_back(LabelTargetPair(&group));
+ ASSERT_TRUE(rlib.OnResolved(&err));
+
+ {
+ std::ostringstream out;
+ NinjaRustBinaryTargetWriter writer(&rlib, out);
+ writer.Run();
+
+ const char expected[] =
+ "crate_name = mylib\n"
+ "crate_type = rlib\n"
+ "output_extension = .rlib\n"
+ "output_dir = \n"
+ "rustflags =\n"
+ "rustenv =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/bar\n"
+ "target_output_name = libmylib\n"
+ "\n"
+ "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | "
+ "../../bar/mylib.rs ../../bar/lib.rs obj/bar/libmymacro.so || "
+ "obj/baz/group.stamp\n"
+ " externs = --extern mymacro=obj/bar/libmymacro.so\n"
+ " rustdeps = -Ldependency=obj/bar\n";
+ std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+
+ Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+ target.set_output_type(Target::EXECUTABLE);
+ target.visibility().SetPublic();
+ SourceFile main("//foo/main.rs");
+ target.sources().push_back(SourceFile("//foo/source.rs"));
+ target.sources().push_back(main);
+ 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(&rlib));
+ target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(target.OnResolved(&err));
+
+ {
+ std::ostringstream out;
+ NinjaRustBinaryTargetWriter writer(&target, out);
+ writer.Run();
+
+ const char expected[] =
+ "crate_name = foo_bar\n"
+ "crate_type = bin\n"
+ "output_extension = \n"
+ "output_dir = \n"
+ "rustflags =\n"
+ "rustenv =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/foo\n"
+ "target_output_name = bar\n"
+ "\n"
+ "build ./foo_bar: rust_bin ../../foo/main.rs | "
+ "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib\n"
+ " externs = --extern mylib=obj/bar/libmylib.rlib\n"
+ " rustdeps = -Ldependency=obj/bar -Ldependency=obj/bar\n";
+ std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+}
+
TEST_F(NinjaRustBinaryTargetWriterTest, RenamedDeps) {
Err err;
TestWithScope setup;
@@ -644,9 +767,9 @@
target.rust_values().set_crate_root(main);
target.rust_values().crate_name() = "foo_bar";
target.config_values().externs().push_back(
- std::pair("lib1", LibFile(SourceFile("//foo/lib1.rlib"))));
+ std::pair("lib1", LibFile(SourceFile("//foo/lib1.rlib"))));
target.config_values().externs().push_back(
- std::pair("lib2", LibFile("lib2.rlib")));
+ std::pair("lib2", LibFile("lib2.rlib")));
target.SetToolchain(setup.toolchain());
ASSERT_TRUE(target.OnResolved(&err));
@@ -668,7 +791,8 @@
"\n"
"build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
"../../foo/main.rs ../../foo/lib1.rlib\n"
- " externs = --extern lib1=../../foo/lib1.rlib --extern lib2=lib2.rlib\n"
+ " externs = --extern lib1=../../foo/lib1.rlib --extern "
+ "lib2=lib2.rlib\n"
" rustdeps =\n";
std::string out_str = out.str();
EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
diff --git a/src/gn/rust_tool.cc b/src/gn/rust_tool.cc
index cd57428..6fcb697 100644
--- a/src/gn/rust_tool.cc
+++ b/src/gn/rust_tool.cc
@@ -33,9 +33,9 @@
}
bool RustTool::ValidateName(const char* name) const {
- return name == kRsToolBin || name == kRsToolCDylib ||
- name == kRsToolDylib || name == kRsToolMacro ||
- name == kRsToolRlib || name == kRsToolStaticlib;
+ return name == kRsToolBin || name == kRsToolCDylib || name == kRsToolDylib ||
+ name == kRsToolMacro || name == kRsToolRlib ||
+ name == kRsToolStaticlib;
}
void RustTool::SetComplete() {
@@ -105,9 +105,9 @@
}
bool RustTool::ValidateSubstitution(const Substitution* sub_type) const {
- if (name_ == kRsToolBin || name_ == kRsToolCDylib ||
- name_ == kRsToolDylib || name_ == kRsToolMacro ||
- name_ == kRsToolRlib || name_ == kRsToolStaticlib)
+ if (name_ == kRsToolBin || name_ == kRsToolCDylib || name_ == kRsToolDylib ||
+ name_ == kRsToolMacro || name_ == kRsToolRlib ||
+ name_ == kRsToolStaticlib)
return IsValidRustSubstitution(sub_type);
NOTREACHED();
return false;
diff --git a/src/gn/rust_values.h b/src/gn/rust_values.h
index 9770e34..8f7fff6 100644
--- a/src/gn/rust_values.h
+++ b/src/gn/rust_values.h
@@ -8,6 +8,7 @@
#include <map>
#include "base/containers/flat_map.h"
+#include "gn/inherited_libraries.h"
#include "gn/label.h"
#include "gn/source_file.h"
@@ -50,11 +51,16 @@
}
std::map<Label, std::string>& aliased_deps() { return aliased_deps_; }
+ // Transitive closure of libraries that are depended on by this target
+ InheritedLibraries& transitive_libs() { return rust_libs_; }
+ const InheritedLibraries& transitive_libs() const { return rust_libs_; }
+
private:
std::string crate_name_;
SourceFile crate_root_;
CrateType crate_type_ = CRATE_AUTO;
std::map<Label, std::string> aliased_deps_;
+ InheritedLibraries rust_libs_;
DISALLOW_COPY_AND_ASSIGN(RustValues);
};
diff --git a/src/gn/target.cc b/src/gn/target.cc
index fdf473e..2469fba 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -536,17 +536,36 @@
void Target::PullDependentTargetLibsFrom(const Target* dep, bool is_public) {
// Direct dependent libraries.
if (dep->output_type() == STATIC_LIBRARY ||
- dep->output_type() == SHARED_LIBRARY ||
- dep->output_type() == SOURCE_SET || dep->output_type() == RUST_LIBRARY ||
- dep->output_type() == RUST_PROC_MACRO)
+ dep->output_type() == SHARED_LIBRARY) {
inherited_libraries_.Append(dep, is_public);
+ rust_values().transitive_libs().Append(dep, is_public);
+ }
- if (dep->output_type() == CREATE_BUNDLE &&
- dep->bundle_data().is_framework()) {
+ if (dep->output_type() == RUST_LIBRARY ||
+ dep->output_type() == RUST_PROC_MACRO ||
+ dep->output_type() == SOURCE_SET ||
+ (dep->output_type() == CREATE_BUNDLE &&
+ dep->bundle_data().is_framework())) {
inherited_libraries_.Append(dep, is_public);
}
- if (dep->output_type() == SHARED_LIBRARY) {
+ if (dep->output_type() == RUST_LIBRARY ||
+ dep->output_type() == RUST_PROC_MACRO) {
+ rust_values().transitive_libs().Append(dep, is_public);
+ rust_values().transitive_libs().AppendInherited(
+ dep->rust_values().transitive_libs(), is_public);
+
+ // If there is a transitive dependency that is not a rust library, place it
+ // in the normal location
+ for (const auto& inherited :
+ rust_values().transitive_libs().GetOrderedAndPublicFlag()) {
+ if (!(inherited.first->output_type() == RUST_LIBRARY ||
+ inherited.first->output_type() == RUST_PROC_MACRO)) {
+ inherited_libraries_.Append(inherited.first,
+ is_public && inherited.second);
+ }
+ }
+ } else if (dep->output_type() == SHARED_LIBRARY) {
// Shared library dependendencies are inherited across public shared
// library boundaries.
//
@@ -572,6 +591,8 @@
// The current target isn't linked, so propogate linked deps and
// libraries up the dependency tree.
inherited_libraries_.AppendInherited(dep->inherited_libraries(), is_public);
+ rust_values().transitive_libs().AppendInherited(
+ dep->rust_values().transitive_libs(), is_public);
} else if (dep->complete_static_lib()) {
// Inherit only final targets through _complete_ static libraries.
//