clang: Add support for C++ modulemap files This is a first step to support Clang modules in C++ compilation. This change adds .modulemap as a source file extension which will be compiled by cxx_module to a .pcm. The subsequent patch then uses a new "module_deps" entry to refer to these modules. Additional test reference here: https://fuchsia-review.googlesource.com/c/fuchsia/+/412605 Change-Id: Ic42af141b11212249dc55911a42f89268537d59a Reviewed-on: https://gn-review.googlesource.com/c/gn/+/9601 Reviewed-by: Petr Hosek <phosek@google.com> Reviewed-by: Brett Wilson <brettw@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org>
diff --git a/src/gn/binary_target_generator.cc b/src/gn/binary_target_generator.cc index 9811a73..6c085e6 100644 --- a/src/gn/binary_target_generator.cc +++ b/src/gn/binary_target_generator.cc
@@ -87,6 +87,7 @@ const auto& source = target_->sources()[i]; switch (source.type()) { case SourceFile::SOURCE_CPP: + case SourceFile::SOURCE_MODULEMAP: case SourceFile::SOURCE_H: case SourceFile::SOURCE_C: case SourceFile::SOURCE_M:
diff --git a/src/gn/c_tool.cc b/src/gn/c_tool.cc index 7c06364..dc391d1 100644 --- a/src/gn/c_tool.cc +++ b/src/gn/c_tool.cc
@@ -8,6 +8,7 @@ const char* CTool::kCToolCc = "cc"; const char* CTool::kCToolCxx = "cxx"; +const char* CTool::kCToolCxxModule = "cxx_module"; const char* CTool::kCToolObjC = "objc"; const char* CTool::kCToolObjCxx = "objcxx"; const char* CTool::kCToolRc = "rc"; @@ -38,9 +39,9 @@ } bool CTool::ValidateName(const char* name) const { - return name == kCToolCc || name == kCToolCxx || name == kCToolObjC || - name == kCToolObjCxx || name == kCToolRc || name == kCToolAsm || - name == kCToolAlink || name == kCToolSolink || + return name == kCToolCc || name == kCToolCxx || name == kCToolCxxModule || + name == kCToolObjC || name == kCToolObjCxx || name == kCToolRc || + name == kCToolAsm || name == kCToolAlink || name == kCToolSolink || name == kCToolSolinkModule || name == kCToolLink; } @@ -217,8 +218,9 @@ } bool CTool::ValidateSubstitution(const Substitution* sub_type) const { - if (name_ == kCToolCc || name_ == kCToolCxx || name_ == kCToolObjC || - name_ == kCToolObjCxx || name_ == kCToolRc || name_ == kCToolAsm) + if (name_ == kCToolCc || name_ == kCToolCxx || name_ == kCToolCxxModule || + name_ == kCToolObjC || name_ == kCToolObjCxx || name_ == kCToolRc || + name_ == kCToolAsm) return IsValidCompilerSubstitution(sub_type); else if (name_ == kCToolAlink) return IsValidALinkSubstitution(sub_type); @@ -230,8 +232,9 @@ } bool CTool::ValidateOutputSubstitution(const Substitution* sub_type) const { - if (name_ == kCToolCc || name_ == kCToolCxx || name_ == kCToolObjC || - name_ == kCToolObjCxx || name_ == kCToolRc || name_ == kCToolAsm) + if (name_ == kCToolCc || name_ == kCToolCxx || name_ == kCToolCxxModule || + name_ == kCToolObjC || name_ == kCToolObjCxx || name_ == kCToolRc || + name_ == kCToolAsm) return IsValidCompilerOutputsSubstitution(sub_type); // ALink uses the standard output file patterns as other linker tools. else if (name_ == kCToolAlink || name_ == kCToolSolink ||
diff --git a/src/gn/c_tool.h b/src/gn/c_tool.h index 8c5282d..01b2431 100644 --- a/src/gn/c_tool.h +++ b/src/gn/c_tool.h
@@ -22,6 +22,7 @@ // C compiler tools static const char* kCToolCc; static const char* kCToolCxx; + static const char* kCToolCxxModule; static const char* kCToolObjC; static const char* kCToolObjCxx; static const char* kCToolRc;
diff --git a/src/gn/function_toolchain.cc b/src/gn/function_toolchain.cc index ac63c2e..a6642d1 100644 --- a/src/gn/function_toolchain.cc +++ b/src/gn/function_toolchain.cc
@@ -284,6 +284,7 @@ Compiler tools: "cc": C compiler "cxx": C++ compiler + "cxx_module": C++ compiler used for Clang .modulemap files "objc": Objective C compiler "objcxx": Objective C++ compiler "rc": Resource compiler (Windows .rc files)
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc index bc9907a..fbd6ff4 100644 --- a/src/gn/ninja_c_binary_target_writer_unittest.cc +++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -1477,3 +1477,39 @@ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str; } } + +TEST_F(NinjaCBinaryTargetWriterTest, ModuleMapInStaticLibrary) { + TestWithScope setup; + Err err; + + std::unique_ptr<Tool> cxx_module_tool = + Tool::CreateTool(CTool::kCToolCxxModule); + cxx_module_tool->set_outputs(SubstitutionList::MakeForTest( + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.pcm")); + setup.toolchain()->SetTool(std::move(cxx_module_tool)); + + TestTarget target(setup, "//foo:bar", Target::STATIC_LIBRARY); + target.sources().push_back(SourceFile("//foo/bar.modulemap")); + target.source_types_used().Set(SourceFile::SOURCE_MODULEMAP); + ASSERT_TRUE(target.OnResolved(&err)); + + std::ostringstream out; + NinjaCBinaryTargetWriter writer(&target, out); + writer.Run(); + + const char expected[] = + "defines =\n" + "include_dirs =\n" + "root_out_dir = .\n" + "target_out_dir = obj/foo\n" + "target_output_name = libbar\n" + "\n" + "build obj/foo/libbar.bar.pcm: cxx_module ../../foo/bar.modulemap\n" + "\n" + "build obj/foo/libbar.a: alink obj/foo/libbar.bar.pcm\n" + " arflags =\n" + " output_extension = \n" + " output_dir = \n"; + std::string out_str = out.str(); + EXPECT_EQ(expected, out_str); +}
diff --git a/src/gn/source_file.cc b/src/gn/source_file.cc index 1dacbfa..0b0e8e5 100644 --- a/src/gn/source_file.cc +++ b/src/gn/source_file.cc
@@ -35,6 +35,8 @@ return SourceFile::SOURCE_M; if (extension == "mm") return SourceFile::SOURCE_MM; + if (extension == "modulemap") + return SourceFile::SOURCE_MODULEMAP; if (extension == "rc") return SourceFile::SOURCE_RC; if (extension == "S" || extension == "s" || extension == "asm") @@ -105,7 +107,8 @@ } bool SourceFileTypeSet::CSourceUsed() const { - return empty_ || Get(SourceFile::SOURCE_CPP) || Get(SourceFile::SOURCE_H) || + return empty_ || Get(SourceFile::SOURCE_CPP) || + Get(SourceFile::SOURCE_MODULEMAP) || Get(SourceFile::SOURCE_H) || Get(SourceFile::SOURCE_C) || Get(SourceFile::SOURCE_M) || Get(SourceFile::SOURCE_MM) || Get(SourceFile::SOURCE_RC) || Get(SourceFile::SOURCE_S) || Get(SourceFile::SOURCE_O) ||
diff --git a/src/gn/source_file.h b/src/gn/source_file.h index d7ed06e..1e156fe 100644 --- a/src/gn/source_file.h +++ b/src/gn/source_file.h
@@ -33,6 +33,7 @@ SOURCE_H, SOURCE_M, SOURCE_MM, + SOURCE_MODULEMAP, SOURCE_S, SOURCE_RC, SOURCE_O, // Object files can be inputs, too. Also counts .obj.
diff --git a/src/gn/target_unittest.cc b/src/gn/target_unittest.cc index 09d7a1a..99ce6b0 100644 --- a/src/gn/target_unittest.cc +++ b/src/gn/target_unittest.cc
@@ -1492,3 +1492,33 @@ EXPECT_TRUE(data_dep_present.OnResolved(&err)); EXPECT_TRUE(scheduler().GetUnknownGeneratedInputs().empty()); } + +// Tests that modulemap files use the cxx_module tool. +TEST_F(TargetTest, ModuleMap) { + TestWithScope setup; + + Toolchain toolchain(setup.settings(), Label(SourceDir("//tc/"), "tc")); + + std::unique_ptr<Tool> tool = Tool::CreateTool(CTool::kCToolCxxModule); + CTool* cxx_module = tool->AsC(); + cxx_module->set_outputs( + SubstitutionList::MakeForTest("{{source_file_part}}.pcm")); + toolchain.SetTool(std::move(tool)); + + Target target(setup.settings(), Label(SourceDir("//a/"), "a")); + target.set_output_type(Target::SOURCE_SET); + target.SetToolchain(&toolchain); + Err err; + ASSERT_TRUE(target.OnResolved(&err)); + + const char* computed_tool_type = nullptr; + std::vector<OutputFile> output; + bool result = target.GetOutputFilesForSource( + SourceFile("//source/input.modulemap"), &computed_tool_type, &output); + ASSERT_TRUE(result); + EXPECT_EQ(std::string("cxx_module"), std::string(computed_tool_type)); + + // Outputs are relative to the build directory "//out/Debug/". + ASSERT_EQ(1u, output.size()); + EXPECT_EQ("input.modulemap.pcm", output[0].value()) << output[0].value(); +}
diff --git a/src/gn/tool.cc b/src/gn/tool.cc index 99b7525..9fc10ce 100644 --- a/src/gn/tool.cc +++ b/src/gn/tool.cc
@@ -253,6 +253,8 @@ return std::make_unique<CTool>(CTool::kCToolCc); else if (name == CTool::kCToolCxx) return std::make_unique<CTool>(CTool::kCToolCxx); + else if (name == CTool::kCToolCxxModule) + return std::make_unique<CTool>(CTool::kCToolCxxModule); else if (name == CTool::kCToolObjC) return std::make_unique<CTool>(CTool::kCToolObjC); else if (name == CTool::kCToolObjCxx) @@ -308,6 +310,8 @@ return CTool::kCToolCc; case SourceFile::SOURCE_CPP: return CTool::kCToolCxx; + case SourceFile::SOURCE_MODULEMAP: + return CTool::kCToolCxxModule; case SourceFile::SOURCE_M: return CTool::kCToolObjC; case SourceFile::SOURCE_MM: