Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2285,6 +2285,9 @@ PosFlag, NegFlag, 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, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">, Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -5529,6 +5529,25 @@ return "-"; } + // If `-fmodule-output` is specfied, then: + // - If `-o` is specified, the module file is writing to the same path + // with the output file in module file's suffix. + // - If `-o` is not specified, the module file is writing to the same path + // with the input file in module file's suffix. + if (!AtTopLevel && isa(JA) && + JA.getType() == types::TY_ModuleFile && + C.getArgs().hasArg(options::OPT_fmodule_output)) { + SmallString<128> TempPath; + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) + TempPath = FinalOutput->getValue(); + else + TempPath = BaseInput; + + const char *Extension = types::getTypeTempSuffix(JA.getType()); + llvm::sys::path::replace_extension(TempPath, Extension); + return C.addResultFile(C.getArgs().MakeArgString(TempPath.c_str()), &JA); + } + if (IsDXCMode() && !C.getArgs().hasArg(options::OPT_o)) return "-"; Index: clang/test/Driver/lit.local.cfg =================================================================== --- clang/test/Driver/lit.local.cfg +++ 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', '.hlsl'] config.substitutions = list(config.substitutions) config.substitutions.insert(0, Index: clang/test/Driver/module-output.cppm =================================================================== --- /dev/null +++ clang/test/Driver/module-output.cppm @@ -0,0 +1,16 @@ +// Tests that the .pcm file will be generated in the same directory with the input +// and the name of the .pcm file should be the same with the input file. +// RUN: %clang -std=c++20 %s -fmodule-output -c -### 2>&1 | \ +// RUN: FileCheck %s -DSOURCE_PATH=%S +// +// Tests that the .pcm file will be generated in the same direcotry with the specified +// output and the name of the .pcm file should be the same with the output file. +// RUN: %clang -std=c++20 %s -fmodule-output -c -o %t/output/Hello.o \ +// RUN: -### 2>&1 | FileCheck %s -DOUTPUT_PATH=%t/output --check-prefix=CHECK-WITH-OUTPUT + +export module Hello; + +// CHECK: "-emit-module-interface" {{.*}}"-main-file-name" "module-output.cppm" {{.*}}"-o" "[[SOURCE_PATH]]/module-output.pcm" "-x" "c++" "[[SOURCE_PATH]]/module-output.cppm" +// CHECK: "-emit-obj" {{.*}}"-main-file-name" "module-output.cppm" {{.*}}"-o" "module-output.o" "-x" "pcm" "[[SOURCE_PATH]]/module-output.pcm" +// CHECK-WITH-OUTPUT: "-emit-module-interface" {{.*}}"-main-file-name" "module-output.cppm" {{.*}}"-o" "[[OUTPUT_PATH]]/Hello.pcm" "-x" "c++" "{{.*}}/module-output.cppm" +// CHECK-WITH-OUTPUT: "-emit-obj" {{.*}}"-main-file-name" "module-output.cppm" {{.*}}"-o" "[[OUTPUT_PATH]]/Hello.o" "-x" "pcm" "[[OUTPUT_PATH]]/Hello.pcm"