Support linking frameworks and swiftmodules in Rust targets

Frameworks are straightforward and just need to be added to the rustdeps
line using the RustTool's framework switch. However we note that
weak_frameworks is not somethinng rustc has support for, so we just use
-framework for now to avoid dumping the framework file name into the
commandline and causing more confusing compiler errors.

Swiftmodules require a flag that is passed through to the Rust linker,
but the Rust linker can be a regular linker (link.exe, lld, etc) or can
be a C compiler (clang). If it's the latter, then the C tool's
swiftmodule_switch will work (prefixed with `-Clink-arg=`). However in
the former case, we can not reuse the C tool's switch. So we add
rust_swiftmodule_switch to be specified as a switch that is passed to
the Rust compiler (not its linker).

Bug: 369
Change-Id: I44147172bda2f80ee4f3d89bf32867aaa617adb8
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/17320
Commit-Queue: danakj <danakj@chromium.org>
Reviewed-by: Dana Jansens <danakj@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/docs/reference.md b/docs/reference.md
index 81f58e8..a9fad5b 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -3826,6 +3826,20 @@
         would be
           "-Wl,-add_ast_path,obj/foo/Foo.swiftmodule"
 
+    rust_swiftmodule_switch [string, optional, link tools only]
+        Valid for: Linker tools except "alink"
+
+        Like swiftmodule_switch, but for targets built/linked with the Rust
+        compiler. The string will be prependend to the path to the
+        .swiftmodule files that are embedded in the linker output.
+
+        If you specified:
+          rust_swiftmodule_swift = "-Clink-arg=-Wl,-add_ast_path,"
+        then the "{{swiftmodules}}" expansion for
+          [ "obj/foo/Foo.swiftmodule" ]
+        would be
+          "-Clink-arg=-Wl,-add_ast_path,obj/foo/Foo.swiftmodule"
+
     outputs  [list of strings with substitutions]
         Valid for: Linker and compiler tools (required)
 
diff --git a/src/gn/json_project_writer_unittest.cc b/src/gn/json_project_writer_unittest.cc
index b581051..a026b40 100644
--- a/src/gn/json_project_writer_unittest.cc
+++ b/src/gn/json_project_writer_unittest.cc
@@ -163,7 +163,8 @@
             "lib_dir_switch": "-Lnative=",
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
-            "outputs": [ "{{root_out_dir}}/{{crate_name}}{{output_extension}}" ]
+            "outputs": [ "{{root_out_dir}}/{{crate_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_cdylib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -174,7 +175,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_dylib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -185,7 +187,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_macro": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -196,7 +199,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_rlib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -207,7 +211,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_staticlib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -218,7 +223,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "solink": {
             "command": "ld -shared -o {{target_output_name}}.so {{inputs}} {{ldflags}} {{libs}}",
@@ -388,7 +394,8 @@
             "lib_dir_switch": "-Lnative=",
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
-            "outputs": [ "{{root_out_dir}}/{{crate_name}}{{output_extension}}" ]
+            "outputs": [ "{{root_out_dir}}/{{crate_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_cdylib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -399,7 +406,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_dylib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -410,7 +418,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_macro": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -421,7 +430,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_rlib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -432,7 +442,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_staticlib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -443,7 +454,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "solink": {
             "command": "ld -shared -o {{target_output_name}}.so {{inputs}} {{ldflags}} {{libs}}",
@@ -637,7 +649,8 @@
             "lib_dir_switch": "-Lnative=",
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
-            "outputs": [ "{{root_out_dir}}/{{crate_name}}{{output_extension}}" ]
+            "outputs": [ "{{root_out_dir}}/{{crate_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_cdylib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -648,7 +661,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_dylib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -659,7 +673,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_macro": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -670,7 +685,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_rlib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -681,7 +697,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "rust_staticlib": {
             "command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -692,7 +709,8 @@
             "lib_switch": "-l",
             "linker_arg": "-Clink-arg=",
             "output_prefix": "lib",
-            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+            "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ],
+            "weak_framework_switch": "-lframework="
          },
          "solink": {
             "command": "ld -shared -o {{target_output_name}}.so {{inputs}} {{ldflags}} {{libs}}",
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index a400cf7..879e70d 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -141,12 +141,19 @@
 
   std::vector<OutputFile> rustdeps;
   std::vector<OutputFile> nonrustdeps;
+  std::vector<OutputFile> swiftmodules;
   nonrustdeps.insert(nonrustdeps.end(),
                      classified_deps.extra_object_files.begin(),
                      classified_deps.extra_object_files.end());
   for (const auto* framework_dep : classified_deps.framework_deps) {
     order_only_deps.push_back(framework_dep->dependency_output_file());
   }
+  if (target_->IsFinal()) {
+    for (const Target* dep : classified_deps.swiftmodule_deps) {
+      swiftmodules.push_back(dep->swift_values().module_output_file());
+      order_only_deps.push_back(dep->swift_values().module_output_file());
+    }
+  }
   for (const auto* non_linkable_dep : classified_deps.non_linkable_deps) {
     if (non_linkable_dep->source_types_used().RustSourceUsed() &&
         non_linkable_dep->output_type() != Target::SOURCE_SET) {
@@ -210,7 +217,8 @@
             classified_deps.non_linkable_deps.end(),
             std::back_inserter(extern_deps));
 
-  WriteExternsAndDeps(extern_deps, transitive_crates, rustdeps, nonrustdeps);
+  WriteExternsAndDeps(extern_deps, transitive_crates, rustdeps, nonrustdeps,
+                      swiftmodules);
   WriteSourcesAndInputs();
   WritePool(out_);
 }
@@ -259,7 +267,8 @@
     const std::vector<const Target*>& deps,
     const std::vector<ExternCrate>& transitive_rust_deps,
     const std::vector<OutputFile>& rustdeps,
-    const std::vector<OutputFile>& nonrustdeps) {
+    const std::vector<OutputFile>& nonrustdeps,
+    const std::vector<OutputFile>& swiftmodules) {
   // Writes a external LibFile which comes from user-specified externs, and may
   // be either a string or a SourceFile.
   auto write_extern_lib_file = [this](std::string_view crate_name,
@@ -382,6 +391,8 @@
   // If rustc will invoke a linker, all libraries need the passed through to the
   // linker.
   WriteLibs(out_, tool_);
+  WriteFrameworks(out_, tool_);
+  WriteSwiftModules(out_, tool_, swiftmodules);
 
   out_ << std::endl;
   out_ << "  ldflags =";
diff --git a/src/gn/ninja_rust_binary_target_writer.h b/src/gn/ninja_rust_binary_target_writer.h
index 69ec916..83e1203 100644
--- a/src/gn/ninja_rust_binary_target_writer.h
+++ b/src/gn/ninja_rust_binary_target_writer.h
@@ -31,7 +31,8 @@
   void WriteExternsAndDeps(const std::vector<const Target*>& deps,
                            const std::vector<ExternCrate>& transitive_rust_deps,
                            const std::vector<OutputFile>& rustdeps,
-                           const std::vector<OutputFile>& nonrustdeps);
+                           const std::vector<OutputFile>& nonrustdeps,
+                           const std::vector<OutputFile>& swiftmodules);
   // Unlike C/C++, Rust compiles all sources of a crate in one command.
   // Write a ninja variable `sources` that contains all sources and input files.
   void WriteSourcesAndInputs();
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index e3468a9..8ef944f 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -1963,3 +1963,130 @@
   std::string out_str = out.str();
   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
 }
+
+// Tests frameworks are applied.
+TEST_F(NinjaRustBinaryTargetWriterTest, FrameworksAndFrameworkDirs) {
+  Err err;
+  TestWithScope setup;
+
+  // A config that force linking with the framework.
+  Config framework_config(setup.settings(),
+                          Label(SourceDir("//bar"), "framework_config"));
+  framework_config.visibility().SetPublic();
+  framework_config.own_values().frameworks().push_back("Bar.framework");
+  framework_config.own_values().framework_dirs().push_back(
+      SourceDir("//out/Debug/"));
+  ASSERT_TRUE(framework_config.OnResolved(&err));
+
+  // A target creating a framework bundle.
+  Target framework(setup.settings(), Label(SourceDir("//bar"), "framework"));
+  framework.set_output_type(Target::CREATE_BUNDLE);
+  framework.bundle_data().product_type() = "com.apple.product-type.framework";
+  framework.public_configs().push_back(LabelConfigPair(&framework_config));
+  framework.SetToolchain(setup.toolchain());
+  framework.visibility().SetPublic();
+  ASSERT_TRUE(framework.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//linked/"), "exe"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  SourceFile main("//linked/exe.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() = "exe";
+  target.private_deps().push_back(LabelTargetPair(&framework));
+  target.config_values().frameworks().push_back("System.framework");
+  target.config_values().weak_frameworks().push_back("Whizbang.framework");
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaRustBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "crate_name = exe\n"
+      "crate_type = bin\n"
+      "output_extension = \n"
+      "output_dir = \n"
+      "rustflags =\n"
+      "rustenv =\n"
+      "root_out_dir = .\n"
+      "target_gen_dir = gen/linked\n"
+      "target_out_dir = obj/linked\n"
+      "target_output_name = exe\n"
+      "\n"
+      "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs || "
+      "obj/bar/framework.stamp obj/bar/framework.stamp\n"
+      "  source_file_part = exe.rs\n"
+      "  source_name_part = exe\n"
+      "  externs =\n"
+      "  rustdeps = -Lframework=. -lframework=System -lframework=Bar "
+      "-lframework=Whizbang\n"
+      "  ldflags =\n"
+      "  sources = ../../linked/exe.rs\n";
+  const std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
+// Test linking of targets containing Swift modules.
+TEST_F(NinjaRustBinaryTargetWriterTest, SwiftModule) {
+  Err err;
+  TestWithScope setup;
+
+  // A single Swift module.
+  Target foo_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
+  foo_target.set_output_type(Target::SOURCE_SET);
+  foo_target.visibility().SetPublic();
+  foo_target.sources().push_back(SourceFile("//foo/file1.swift"));
+  foo_target.sources().push_back(SourceFile("//foo/file2.swift"));
+  foo_target.source_types_used().Set(SourceFile::SOURCE_SWIFT);
+  foo_target.swift_values().module_name() = "Foo";
+  foo_target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(foo_target.OnResolved(&err));
+
+  // Rust target links with module.
+  Target target(setup.settings(), Label(SourceDir("//linked/"), "exe"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  SourceFile main("//linked/exe.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() = "exe";
+  target.private_deps().push_back(LabelTargetPair(&foo_target));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaRustBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "crate_name = exe\n"
+      "crate_type = bin\n"
+      "output_extension = \n"
+      "output_dir = \n"
+      "rustflags =\n"
+      "rustenv =\n"
+      "root_out_dir = .\n"
+      "target_gen_dir = gen/linked\n"
+      "target_out_dir = obj/linked\n"
+      "target_output_name = exe\n"
+      "\n"
+      "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs "
+      "obj/foo/file1.o obj/foo/file2.o || "
+      "obj/foo/foo.stamp obj/foo/Foo.swiftmodule obj/foo/foo.stamp\n"
+      "  source_file_part = exe.rs\n"
+      "  source_name_part = exe\n"
+      "  externs =\n"
+      "  rustdeps = -Lnative=obj/foo -Clink-arg=-Bdynamic "
+      "-Clink-arg=obj/foo/file1.o -Clink-arg=obj/foo/file2.o "
+      "-Clink-arg=-swiftmodule=obj/foo/Foo.swiftmodule\n"
+      "  ldflags =\n"
+      "  sources = ../../linked/exe.rs\n";
+
+  const 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 5b5cc62..f799d73 100644
--- a/src/gn/rust_tool.cc
+++ b/src/gn/rust_tool.cc
@@ -16,8 +16,15 @@
 
 RustTool::RustTool(const char* n) : Tool(n) {
   CHECK(ValidateName(n));
-  // TODO: should these be settable in toolchain definition?
+  // TODO: should these be settable in toolchain definition? They would collide
+  // with the same switch names for C tools, however. So reading them from the
+  // toolchain definition would produce the incorrect switch unless we separate
+  // their names somehow.
   set_framework_switch("-lframework=");
+  // NOTE: No support for weak_framework in rustc, so we just use `-lframework`
+  // for now, to avoid more cryptic compiler errors.
+  // https://doc.rust-lang.org/rustc/command-line-arguments.html#-l-link-the-generated-crate-to-a-native-library
+  set_weak_framework_switch("-lframework=");
   set_framework_dir_switch("-Lframework=");
   set_lib_dir_switch("-Lnative=");
   set_lib_switch("-l");
@@ -119,7 +126,9 @@
   }
 
   if (MayLink()) {
-    if (!ReadString(scope, "dynamic_link_switch", &dynamic_link_switch_, err)) {
+    if (!ReadString(scope, "rust_swiftmodule_switch", &swiftmodule_switch_,
+                    err) ||
+        !ReadString(scope, "dynamic_link_switch", &dynamic_link_switch_, err)) {
       return false;
     }
   }
diff --git a/src/gn/test_with_scope.cc b/src/gn/test_with_scope.cc
index 4f33a59..1fae377 100644
--- a/src/gn/test_with_scope.cc
+++ b/src/gn/test_with_scope.cc
@@ -229,6 +229,7 @@
       rustc_tool.get());
   rustc_tool->set_outputs(SubstitutionList::MakeForTest(
       "{{root_out_dir}}/{{crate_name}}{{output_extension}}"));
+  rustc_tool->set_swiftmodule_switch("-Clink-arg=-swiftmodule=");
   toolchain->SetTool(std::move(rustc_tool));
 
   // SWIFT
@@ -254,6 +255,7 @@
   cdylib_tool->set_default_output_extension(".so");
   cdylib_tool->set_outputs(SubstitutionList::MakeForTest(
       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
+  cdylib_tool->set_swiftmodule_switch("-Clink-arg=-swiftmodule=");
   toolchain->SetTool(std::move(cdylib_tool));
 
   // RUST DYLIB
@@ -267,6 +269,7 @@
   dylib_tool->set_default_output_extension(".so");
   dylib_tool->set_outputs(SubstitutionList::MakeForTest(
       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
+  dylib_tool->set_swiftmodule_switch("-Clink-arg=-swiftmodule=");
   toolchain->SetTool(std::move(dylib_tool));
 
   // RUST_PROC_MACRO
@@ -281,6 +284,7 @@
   rust_proc_macro_tool->set_default_output_extension(".so");
   rust_proc_macro_tool->set_outputs(SubstitutionList::MakeForTest(
       "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
+  rust_proc_macro_tool->set_swiftmodule_switch("-Clink-arg=-swiftmodule=");
   toolchain->SetTool(std::move(rust_proc_macro_tool));
 
   // RLIB