Include library search paths when compiling rlibs in the command line. Bug: 340 Change-Id: I5ae0ad38b5ac26ae8474ae2ba47334491a0d304a Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15640 Reviewed-by: David Turner <digit@google.com> Reviewed-by: Dana Jansens <danakj@google.com> Reviewed-by: Brett Wilson <brettw@chromium.org> Commit-Queue: danakj <danakj@chromium.org>
diff --git a/docs/reference.md b/docs/reference.md index 310d7e8..02295b7 100644 --- a/docs/reference.md +++ b/docs/reference.md
@@ -5650,6 +5650,10 @@ of targets, and public_configs are always propagated across public deps of all types of targets. + For Rust targets, deps ensures that Rust code can refer to the dependency + target. If the dependency is a C/C++ target, the path to that target will + be made available to Rust for `#[link]` directives. + Data dependencies are propagated differently. See "gn help data_deps" and "gn help runtime_deps".
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc index 554f88c..21ae6d0 100644 --- a/src/gn/ninja_rust_binary_target_writer.cc +++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -349,20 +349,23 @@ path_output_.WriteDir(out_, dir, PathOutput::DIR_NO_LAST_SLASH); } + UniqueVector<SourceDir> nonrustdep_dirs; + + // Non-Rust native dependencies. A dependency from Rust implies the ability + // to specify it in #[link], and GN will ensure that rustc can find it by + // adding it to the native library search paths. + for (const auto& nonrustdep : nonrustdeps) { + nonrustdep_dirs.push_back( + nonrustdep.AsSourceFile(settings_->build_settings()).GetDir()); + } + for (const auto& nonrustdep_dir : nonrustdep_dirs) { + out_ << " -Lnative="; + path_output_.WriteDir(out_, nonrustdep_dir, PathOutput::DIR_NO_LAST_SLASH); + } + + // If rustc will invoke a linker, then pass linker arguments to include those + // non-Rust native dependencies in the linking step. 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. @@ -373,11 +376,22 @@ out_ << " -Clink-arg="; path_output_.WriteFile(out_, nonrustdep); } - WriteLibrarySearchPath(out_, tool_); + } + + // Library search paths are required to find system libraries named in #[link] + // directives, which will not be specified in non-Rust native dependencies. + WriteLibrarySearchPath(out_, tool_); + // If rustc will invoke a linker, all libraries need the passed through to the + // linker. + if (target_is_final) { WriteLibs(out_, tool_); } out_ << std::endl; out_ << " ldflags ="; - WriteCustomLinkerFlags(out_, tool_); + // If rustc will invoke a linker, linker flags need to be forwarded through to + // the linker. + if (target_is_final) { + WriteCustomLinkerFlags(out_, tool_); + } out_ << std::endl; }
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc index 5eda4a7..deb2bb6 100644 --- a/src/gn/ninja_rust_binary_target_writer_unittest.cc +++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -896,7 +896,7 @@ " source_file_part = lib.rs\n" " source_name_part = lib\n" " externs =\n" - " rustdeps =\n" + " rustdeps = -Lnative=obj/foo\n" " ldflags =\n" " sources = ../../baz/lib.rs\n"; std::string out_str = out.str(); @@ -1227,6 +1227,14 @@ public_rlib.SetToolchain(setup.toolchain()); ASSERT_TRUE(public_rlib.OnResolved(&err)); + Target staticlib(setup.settings(), Label(SourceDir("//clib/"), "static")); + staticlib.set_output_type(Target::STATIC_LIBRARY); + staticlib.visibility().SetPublic(); + staticlib.sources().push_back(SourceFile("//foo/clib.cpp")); + staticlib.source_types_used().Set(SourceFile::SOURCE_CPP); + staticlib.SetToolchain(setup.toolchain()); + ASSERT_TRUE(staticlib.OnResolved(&err)); + Target rlib(setup.settings(), Label(SourceDir("//foo/"), "rlibcrate")); rlib.set_output_type(Target::RUST_LIBRARY); rlib.visibility().SetPublic(); @@ -1243,18 +1251,31 @@ // `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. + // 1. A dependency on an archive file directly as happens with a `libs` rule, + // requesting a system library. The path to that library must be specified + // separately with `-L` in ldflags, the library does not appear in the + // rustc compilation of an rlib. rlib.config_values().libs().push_back( LibFile(SourceFile("//dir1/ar.a"))); - // 2. A dependency on a library name as happens with a `libs` rule. + // 2. A dependency on a library name as happens with a `libs` rule. Libraries + // need only be named when linking, they do not need to appear in an rlib + // compilation. 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. + // separate from the dependency paths for finding Rust crates. But it may + // be needed to resolve the path to a native library in a #[link] + // directive. 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. + // is also separate from finding Rust crates. Again a #[link] directive can + // point to a framework, so these paths need to be present during + // compilation rlib.config_values().framework_dirs().push_back(SourceDir("//fwdir/")); + // 5. A dependency on a C library through a `deps` rule, which points to a + // `static_library` target. GN guarantees that Rust can refer to that + // library through #[link] without having to specify the path in ldflags + // as well. + rlib.private_deps().push_back(LabelTargetPair(&staticlib)); ASSERT_TRUE(rlib.OnResolved(&err)); @@ -1274,11 +1295,12 @@ "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" + "build obj/foo/librlibcrate.rlib: rust_rlib ../../foo/input.rs | ../../foo/input.rs obj/bar/libpubliclib.rlib obj/clib/libstatic.a\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" + " rustdeps = -Ldependency=obj/bar -Lnative=obj/clib " +"-Lnative=../../baz -Lframework=../../fwdir\n" " ldflags =\n" " sources = ../../foo/input.rs\n"; std::string out_str = out.str();