Avoid unused and incorrect linker args in {{rustdeps}}
For non-final Rust targets, libraries and library search paths do not
need to appear in the {{rustdeps}} at all, since there is no linker
step that will take place to consume them.
For framework search paths, pass `-Lframework=$dir` to `rustc` instead
of just `$dir` which then is incorrectly seen as being an input source
file.
The -Lframework flag is listed here:
https://doc.rust-lang.org/rustc/command-line-arguments.html#-l-add-a-directory-to-the-library-search-path
Bug: 340
Change-Id: Idb1e4e7cc72f465084f3cf9464bdc605b1535c13
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15580
Reviewed-by: Tyler Mandry <tmandry@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/json_project_writer_unittest.cc b/src/gn/json_project_writer_unittest.cc
index 1915c30..cab6dd7 100644
--- a/src/gn/json_project_writer_unittest.cc
+++ b/src/gn/json_project_writer_unittest.cc
@@ -158,6 +158,7 @@
},
"rust_bin": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -167,6 +168,7 @@
"rust_cdylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -177,6 +179,7 @@
"rust_dylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -187,6 +190,7 @@
"rust_macro": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -197,6 +201,7 @@
"rust_rlib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".rlib",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -207,6 +212,7 @@
"rust_staticlib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".a",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -377,6 +383,7 @@
},
"rust_bin": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -386,6 +393,7 @@
"rust_cdylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -396,6 +404,7 @@
"rust_dylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -406,6 +415,7 @@
"rust_macro": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -416,6 +426,7 @@
"rust_rlib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".rlib",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -426,6 +437,7 @@
"rust_staticlib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".a",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -620,6 +632,7 @@
},
"rust_bin": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -629,6 +642,7 @@
"rust_cdylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -639,6 +653,7 @@
"rust_dylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -649,6 +664,7 @@
"rust_macro": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".so",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -659,6 +675,7 @@
"rust_rlib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".rlib",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
@@ -669,6 +686,7 @@
"rust_staticlib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
"default_output_extension": ".a",
+ "framework_dir_switch": "-Lframework=",
"framework_switch": "-lframework=",
"lib_dir_switch": "-Lnative=",
"lib_switch": "-l",
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index 694f332..554f88c 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -209,7 +209,8 @@
std::copy(classified_deps.non_linkable_deps.begin(),
classified_deps.non_linkable_deps.end(),
std::back_inserter(extern_deps));
- WriteExternsAndDeps(extern_deps, transitive_crates, rustdeps, nonrustdeps);
+ WriteExternsAndDeps(target_->IsFinal(), extern_deps, transitive_crates,
+ rustdeps, nonrustdeps);
WriteSourcesAndInputs();
WritePool(out_);
}
@@ -255,6 +256,7 @@
}
void NinjaRustBinaryTargetWriter::WriteExternsAndDeps(
+ bool target_is_final,
const std::vector<const Target*>& deps,
const std::vector<ExternCrate>& transitive_rust_deps,
const std::vector<OutputFile>& rustdeps,
@@ -347,30 +349,33 @@
path_output_.WriteDir(out_, dir, PathOutput::DIR_NO_LAST_SLASH);
}
- // Non-Rust native dependencies.
- UniqueVector<SourceDir> nonrustdep_dirs;
- for (const auto& nonrustdep : nonrustdeps) {
- nonrustdep_dirs.push_back(
- nonrustdep.AsSourceFile(settings_->build_settings()).GetDir());
+ if (target_is_final) {
+ // Non-Rust native dependencies.
+ UniqueVector<SourceDir> nonrustdep_dirs;
+ for (const auto& nonrustdep : nonrustdeps) {
+ nonrustdep_dirs.push_back(
+ nonrustdep.AsSourceFile(settings_->build_settings()).GetDir());
+ }
+ // First -Lnative to specify the search directories.
+ // This is necessary for #[link(...)] directives to work properly.
+ for (const auto& nonrustdep_dir : nonrustdep_dirs) {
+ out_ << " -Lnative=";
+ path_output_.WriteDir(out_, nonrustdep_dir,
+ PathOutput::DIR_NO_LAST_SLASH);
+ }
+ // Before outputting any libraries to link, ensure the linker is in a mode
+ // that allows dynamic linking, as rustc may have previously put it into
+ // static-only mode.
+ if (nonrustdeps.size() > 0) {
+ out_ << " " << tool_->dynamic_link_switch();
+ }
+ for (const auto& nonrustdep : nonrustdeps) {
+ out_ << " -Clink-arg=";
+ path_output_.WriteFile(out_, nonrustdep);
+ }
+ WriteLibrarySearchPath(out_, tool_);
+ WriteLibs(out_, tool_);
}
- // First -Lnative to specify the search directories.
- // This is necessary for #[link(...)] directives to work properly.
- for (const auto& nonrustdep_dir : nonrustdep_dirs) {
- out_ << " -Lnative=";
- path_output_.WriteDir(out_, nonrustdep_dir, PathOutput::DIR_NO_LAST_SLASH);
- }
- // Before outputting any libraries to link, ensure the linker is in a mode
- // that allows dynamic linking, as rustc may have previously put it into
- // static-only mode.
- if (nonrustdeps.size() > 0) {
- out_ << " " << tool_->dynamic_link_switch();
- }
- for (const auto& nonrustdep : nonrustdeps) {
- out_ << " -Clink-arg=";
- path_output_.WriteFile(out_, nonrustdep);
- }
- WriteLibrarySearchPath(out_, tool_);
- WriteLibs(out_, tool_);
out_ << std::endl;
out_ << " ldflags =";
WriteCustomLinkerFlags(out_, tool_);
diff --git a/src/gn/ninja_rust_binary_target_writer.h b/src/gn/ninja_rust_binary_target_writer.h
index 69ec916..470a899 100644
--- a/src/gn/ninja_rust_binary_target_writer.h
+++ b/src/gn/ninja_rust_binary_target_writer.h
@@ -28,7 +28,8 @@
void WriteCompilerVars();
void WriteSources(const OutputFile& input_dep,
const std::vector<OutputFile>& order_only_deps);
- void WriteExternsAndDeps(const std::vector<const Target*>& deps,
+ void WriteExternsAndDeps(bool target_is_final,
+ const std::vector<const Target*>& deps,
const std::vector<ExternCrate>& transitive_rust_deps,
const std::vector<OutputFile>& rustdeps,
const std::vector<OutputFile>& nonrustdeps);
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index 21b104f..5eda4a7 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -896,8 +896,7 @@
" source_file_part = lib.rs\n"
" source_name_part = lib\n"
" externs =\n"
- " rustdeps = -Lnative=obj/foo -Clink-arg=-Balternative-dynamic "
- "-Clink-arg=obj/foo/libstatic.a\n"
+ " rustdeps =\n"
" ldflags =\n"
" sources = ../../baz/lib.rs\n";
std::string out_str = out.str();
@@ -1146,6 +1145,21 @@
Err err;
TestWithScope setup;
+ Target rlib(setup.settings(), Label(SourceDir("//bar/"), "rlib"));
+ rlib.set_output_type(Target::RUST_LIBRARY);
+ rlib.visibility().SetPublic();
+ SourceFile barlib("//bar/lib.rs");
+ rlib.sources().push_back(SourceFile("//bar/rlib.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() = "rlibcrate";
+ rlib.config_values().libs().push_back(LibFile("rliblib"));
+ rlib.config_values().lib_dirs().push_back(SourceDir("//rliblibdir/"));
+ rlib.config_values().framework_dirs().push_back(SourceDir("//rlibfwdir/"));
+ rlib.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(rlib.OnResolved(&err));
+
Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
target.set_output_type(Target::EXECUTABLE);
target.visibility().SetPublic();
@@ -1154,8 +1168,12 @@
target.sources().push_back(main);
target.source_types_used().Set(SourceFile::SOURCE_RS);
target.set_output_dir(SourceDir("//out/Debug/foo/"));
- target.config_values().libs().push_back(LibFile("quux"));
- target.config_values().lib_dirs().push_back(SourceDir("//baz/"));
+ target.config_values().libs().push_back(
+ LibFile(SourceFile("//dir1/ar.a")));
+ target.config_values().libs().push_back(LibFile("binlib"));
+ target.config_values().lib_dirs().push_back(SourceDir("//binlibdir/"));
+ target.config_values().framework_dirs().push_back(SourceDir("//binfwdir/"));
+ target.public_deps().push_back(LabelTargetPair(&rlib));
target.rust_values().set_crate_root(main);
target.rust_values().crate_name() = "foo_bar";
target.SetToolchain(setup.toolchain());
@@ -1178,11 +1196,14 @@
"target_output_name = bar\n"
"\n"
"build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/input.rs "
- "../../foo/main.rs\n"
+ "../../foo/main.rs obj/bar/librlib.rlib\n"
" source_file_part = main.rs\n"
" source_name_part = main\n"
- " externs =\n"
- " rustdeps = -Lnative=../../baz -lquux\n"
+ " externs = --extern rlibcrate=obj/bar/librlib.rlib\n"
+ " rustdeps = -Ldependency=obj/bar -Lnative=../../binlibdir "
+ "-Lnative=../../rliblibdir -Lframework=../../binfwdir "
+ "-Lframework=../../rlibfwdir -Clink-arg=../../dir1/ar.a -lbinlib "
+ "-lrliblib\n"
" ldflags =\n"
" sources = ../../foo/input.rs ../../foo/main.rs\n";
std::string out_str = out.str();
@@ -1190,6 +1211,81 @@
}
}
+TEST_F(NinjaRustBinaryTargetWriterTest, RlibWithLibDeps) {
+ Err err;
+ TestWithScope setup;
+
+ Target public_rlib(setup.settings(), Label(SourceDir("//bar/"), "publiclib"));
+ public_rlib.set_output_type(Target::RUST_LIBRARY);
+ public_rlib.visibility().SetPublic();
+ SourceFile barlib("//bar/lib.rs");
+ public_rlib.sources().push_back(SourceFile("//bar/publiclib.rs"));
+ public_rlib.sources().push_back(barlib);
+ public_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+ public_rlib.rust_values().set_crate_root(barlib);
+ public_rlib.rust_values().crate_name() = "publiccrate";
+ public_rlib.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(public_rlib.OnResolved(&err));
+
+ Target rlib(setup.settings(), Label(SourceDir("//foo/"), "rlibcrate"));
+ rlib.set_output_type(Target::RUST_LIBRARY);
+ rlib.visibility().SetPublic();
+ SourceFile lib("//foo/input.rs");
+ rlib.sources().push_back(lib);
+ rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+ rlib.rust_values().set_crate_root(lib);
+ rlib.rust_values().crate_name() = "rlibcrate";
+ rlib.SetToolchain(setup.toolchain());
+ rlib.public_deps().push_back(LabelTargetPair(&public_rlib));
+
+ // This adds dependencies on static libraries, which are not consumed by an
+ // rlib since it does not get linked. None of these should appear in
+ // `rustdeps` for a `rust_rlib`, though they would for a `rust_bin` (as tested
+ // for above).
+ //
+ // 1. A dependency on an archive file directly as happens with a `deps` rule
+ // pointing to a `static_library` target.
+ rlib.config_values().libs().push_back(
+ LibFile(SourceFile("//dir1/ar.a")));
+ // 2. A dependency on a library name as happens with a `libs` rule.
+ rlib.config_values().libs().push_back(LibFile("quux"));
+ // 3. A dependency on a library path which will be used for linking, which is
+ // separate from the dependency paths for finding Rust crates.
+ rlib.config_values().lib_dirs().push_back(SourceDir("//baz/"));
+ // 4. A framework search directory will be used for linking frameworks, which
+ // is also separate from finding Rust crates.
+ rlib.config_values().framework_dirs().push_back(SourceDir("//fwdir/"));
+
+ ASSERT_TRUE(rlib.OnResolved(&err));
+
+ {
+ std::ostringstream out;
+ NinjaRustBinaryTargetWriter writer(&rlib, out);
+ writer.Run();
+
+ const char expected[] =
+ "crate_name = rlibcrate\n"
+ "crate_type = rlib\n"
+ "output_extension = .rlib\n"
+ "output_dir = \n"
+ "rustflags =\n"
+ "rustenv =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/foo\n"
+ "target_output_name = librlibcrate\n"
+ "\n"
+ "build obj/foo/librlibcrate.rlib: rust_rlib ../../foo/input.rs | ../../foo/input.rs obj/bar/libpubliclib.rlib\n"
+ " source_file_part = input.rs\n"
+ " source_name_part = input\n"
+ " externs = --extern publiccrate=obj/bar/libpubliclib.rlib\n"
+ " rustdeps = -Ldependency=obj/bar\n"
+ " ldflags =\n"
+ " sources = ../../foo/input.rs\n";
+ std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+}
+
// Test that neither public nor private rust dependencies of a proc-macro are
// transitively acquired as accessible dependencies by users of the macro. But
// the macro itself is listed as an accessible dependency (via --extern).
diff --git a/src/gn/rust_tool.cc b/src/gn/rust_tool.cc
index 5f2c2de..65ed27a 100644
--- a/src/gn/rust_tool.cc
+++ b/src/gn/rust_tool.cc
@@ -18,6 +18,7 @@
CHECK(ValidateName(n));
// TODO: should these be settable in toolchain definition?
set_framework_switch("-lframework=");
+ set_framework_dir_switch("-Lframework=");
set_lib_dir_switch("-Lnative=");
set_lib_switch("-l");
set_linker_arg("-Clink-arg=");