[clang] f89327e - [Driver] [Modules] Support -fmodule-output (1/2)

Chuanqi Xu via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 15 19:08:05 PST 2023


Author: Chuanqi Xu
Date: 2023-01-16T11:05:33+08:00
New Revision: f89327e28bc17a1d80fd5523520e62d8dd53c1cb

URL: https://github.com/llvm/llvm-project/commit/f89327e28bc17a1d80fd5523520e62d8dd53c1cb
DIFF: https://github.com/llvm/llvm-project/commit/f89327e28bc17a1d80fd5523520e62d8dd53c1cb.diff

LOG: [Driver] [Modules] Support -fmodule-output (1/2)

Patches to support the one-phase compilation model for modules.

The behavior:
(1) If -o and -c is specified , the module file is in the same path
within the same directory as the output the -o specified and with a new
suffix .pcm.
(2) Otherwise, the module file is in the same path within the working
directory directory with the name of the input file with a new suffix
.pcm

For example,

```
Hello.cppm Use.cpp
```

A trivial one and the contents are ignored. When we run:

```
clang++ -std=c++20 -fmodule-output Hello.cppm -c
```

The directory would look like:

```
Hello.cppm  Hello.o  Hello.pcm Use.cpp
```

And if we run:

```
clang++ -std=c++20 -fmodule-output Hello.cppm -c -o output/Hello.o
```

Then the `output` directory may look like:

```
Hello.o  Hello.pcm
```

Reviewed By: dblaikie, iains, tahonermann

Differential Revision: https://reviews.llvm.org/D137058

Added: 
    clang/test/Driver/module-output.cppm

Modified: 
    clang/include/clang/Basic/DiagnosticDriverKinds.td
    clang/include/clang/Driver/Options.td
    clang/lib/Driver/Driver.cpp
    clang/test/Driver/lit.local.cfg

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 61b7a161da36e..08be6966f6864 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -489,6 +489,9 @@ def err_test_module_file_extension_format : Error<
   "-ftest-module-file-extension argument '%0' is not of the required form "
   "'blockname:major:minor:hashed:user info'">;
 
+def err_drv_module_output_with_multiple_arch : Error<
+  "option '-fmodule-output' can't be used with multiple arch options">;
+
 def err_drv_extract_api_wrong_kind : Error<
   "header file '%0' input '%1' does not match the type of prior input "
   "in api extraction; use '-x %2' to override">;

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6cee51f72702f..eaaaebf8702ea 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2306,6 +2306,9 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
   PosFlag<SetTrue, [], "Look up implicit modules in the prebuilt module path">,
   NegFlag<SetFalse>, BothFlags<[NoXarchOption, CC1Option]>>;
 
+def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption, CC1Option]>,
+  HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;
+
 def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
   Flags<[CC1Option]>, MetaVarName<"<seconds>">,
   HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">,

diff  --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index fe9e9bb7055f3..bc70a92551811 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -5553,6 +5553,30 @@ const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix,
   return C.addTempFile(C.getArgs().MakeArgString(TmpName));
 }
 
+// Calculate the output path of the module file when compiling a module unit
+// with the `-fmodule-output` option specified. The behavior is:
+// - If the output object file of the module unit is specified, the output path
+//   of the module file should be the same with the output object file except
+//   the corresponding suffix. This requires both `-o` and `-c` are specified.
+// - Otherwise, the output path of the module file will be the same with the
+//   input with the corresponding suffix.
+static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA,
+                                       const char *BaseInput) {
+  assert(isa<PrecompileJobAction>(JA) && JA.getType() == types::TY_ModuleFile &&
+         C.getArgs().hasArg(options::OPT_fmodule_output));
+
+  SmallString<64> OutputPath;
+  Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+  if (FinalOutput && C.getArgs().hasArg(options::OPT_c))
+    OutputPath = FinalOutput->getValue();
+  else
+    OutputPath = BaseInput;
+
+  const char *Extension = types::getTypeTempSuffix(JA.getType());
+  llvm::sys::path::replace_extension(OutputPath, Extension);
+  return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA);
+}
+
 const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
                                        const char *BaseInput,
                                        StringRef OrigBoundArch, bool AtTopLevel,
@@ -5609,6 +5633,16 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
         &JA);
   }
 
+  if (MultipleArchs && C.getArgs().hasArg(options::OPT_fmodule_output))
+    Diag(clang::diag::err_drv_module_output_with_multiple_arch);
+
+  // If we're emitting a module output with the specified option
+  // `-fmodule-output`.
+  if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
+      JA.getType() == types::TY_ModuleFile &&
+      C.getArgs().hasArg(options::OPT_fmodule_output))
+    return GetModuleOutputPath(C, JA, BaseInput);
+
   // Output to a temporary file?
   if ((!AtTopLevel && !isSaveTempsEnabled() &&
        !C.getArgs().hasArg(options::OPT__SLASH_Fo)) ||
@@ -5771,9 +5805,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
     else
       llvm::sys::path::append(BasePath, NamedOutput);
     return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA);
-  } else {
-    return C.addResultFile(NamedOutput, &JA);
   }
+
+  return C.addResultFile(NamedOutput, &JA);
 }
 
 std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {

diff  --git a/clang/test/Driver/lit.local.cfg b/clang/test/Driver/lit.local.cfg
index d29c7987e38c9..21d23ff0a271e 100644
--- a/clang/test/Driver/lit.local.cfg
+++ b/clang/test/Driver/lit.local.cfg
@@ -1,6 +1,6 @@
 from lit.llvm import llvm_config
 
-config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95',
+config.suffixes = ['.c', '.cpp', '.cppm', '.h', '.m', '.mm', '.S', '.s', '.f90', '.F90', '.f95',
                    '.cu', '.rs', '.cl', '.clcpp', '.hip', '.hipi', '.hlsl']
 config.substitutions = list(config.substitutions)
 config.substitutions.insert(0,

diff  --git a/clang/test/Driver/module-output.cppm b/clang/test/Driver/module-output.cppm
new file mode 100644
index 0000000000000..2a9fb55f4b668
--- /dev/null
+++ b/clang/test/Driver/module-output.cppm
@@ -0,0 +1,33 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+//
+// Tests that the .pcm file will be generated in the same directory with the specified
+// output and the name of the .pcm file should be the same with the input file.
+// RUN: %clang -std=c++20 %t/Hello.cppm -fmodule-output -c -o %t/output/Hello.o \
+// RUN:   -### 2>&1 | FileCheck %t/Hello.cppm
+//
+// Tests that the output file will be generated in the input directory if the output
+// file is not the corresponding object file.
+// RUN: %clang -std=c++20 %t/Hello.cppm %t/AnotherModule.cppm -fmodule-output -o \
+// RUN:   %t/output/a.out -### 2>&1 | FileCheck  %t/AnotherModule.cppm
+//
+// Tests that clang will reject the command line if it specifies -fmodule-output with
+// multiple archs.
+// RUN: %clang %t/Hello.cppm -fmodule-output -arch i386 -arch x86_64 -### -target \
+// RUN:   x86_64-apple-darwin 2>&1 | FileCheck %t/Hello.cppm -check-prefix=MULTIPLE-ARCH
+
+//--- Hello.cppm
+export module Hello;
+
+// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/output/Hello.pcm" "-x" "c++" "{{.*}}/Hello.cppm"
+// CHECK: "-emit-obj" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/output/Hello.o" "-x" "pcm" "{{.*}}/output/Hello.pcm"
+
+// MULTIPLE-ARCH: option '-fmodule-output' can't be used with multiple arch options
+
+//--- AnotherModule.cppm
+export module AnotherModule;
+// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/Hello.pcm" "-x" "c++" "{{.*}}/Hello.cppm"
+// CHECK: "-emit-obj" {{.*}}"-main-file-name" "Hello.cppm" {{.*}}"-o" "{{.*}}/Hello-{{.*}}.o" "-x" "pcm" "{{.*}}/Hello.pcm"
+// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "AnotherModule.cppm" {{.*}}"-o" "{{.*}}/AnotherModule.pcm" "-x" "c++" "{{.*}}/AnotherModule.cppm"
+// CHECK: "-emit-obj" {{.*}}"-main-file-name" "AnotherModule.cppm" {{.*}}"-o" "{{.*}}/AnotherModule-{{.*}}.o" "-x" "pcm" "{{.*}}/AnotherModule.pcm"


        


More information about the cfe-commits mailing list