diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5619,6 +5619,10 @@ HelpText<"Use the current working directory as the home directory of " "module maps specified by -fmodule-map-file=">, MarshallingInfoFlag>; +def fmodule_file_home_is_cwd : Flag<["-"], "fmodule-file-home-is-cwd">, + HelpText<"Use the current working directory as the base directory of " + "compiled module files.">, + MarshallingInfoFlag>; def fmodule_feature : Separate<["-"], "fmodule-feature">, MetaVarName<"">, HelpText<"Enable in module map requires declarations">, diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -143,6 +143,12 @@ /// file. unsigned ModuleMapFileHomeIsCwd : 1; + /// Set the base path of a built module file to be the current working + /// directory. This is useful for sharing module files across machines + /// that build with different paths without having to rewrite all + /// modulemap files to have working directory relative paths. + unsigned ModuleFileHomeIsCwd : 1; + /// Also search for prebuilt implicit modules in the prebuilt module cache /// path. unsigned EnablePrebuiltImplicitModules : 1; @@ -222,9 +228,9 @@ HeaderSearchOptions(StringRef _Sysroot = "/") : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false), ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false), - EnablePrebuiltImplicitModules(false), UseBuiltinIncludes(true), - UseStandardSystemIncludes(true), UseStandardCXXIncludes(true), - UseLibcxx(false), Verbose(false), + ModuleFileHomeIsCwd(false), EnablePrebuiltImplicitModules(false), + UseBuiltinIncludes(true), UseStandardSystemIncludes(true), + UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), ModulesValidateOncePerBuildSession(false), ModulesValidateSystemHeaders(false), ValidateASTInputFilesContent(false), UseDebugInfo(false), diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1224,15 +1224,24 @@ } if (WritingModule && WritingModule->Directory) { - SmallString<128> BaseDir(WritingModule->Directory->getName()); + SmallString<128> BaseDir; + if (PP.getHeaderSearchInfo().getHeaderSearchOpts().ModuleFileHomeIsCwd) { + // Use the current working directory as the base path for all inputs. + auto *CWD = + Context.getSourceManager().getFileManager().getDirectory(".").get(); + BaseDir.assign(CWD->getName()); + } else { + BaseDir.assign(WritingModule->Directory->getName()); + } cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); // If the home of the module is the current working directory, then we // want to pick up the cwd of the build process loading the module, not // our cwd, when we load this module. - if (!PP.getHeaderSearchInfo() - .getHeaderSearchOpts() - .ModuleMapFileHomeIsCwd || + if (!(PP.getHeaderSearchInfo() + .getHeaderSearchOpts() + .ModuleMapFileHomeIsCwd || + PP.getHeaderSearchInfo().getHeaderSearchOpts().ModuleFileHomeIsCwd) || WritingModule->Directory->getName() != StringRef(".")) { // Module directory. auto Abbrev = std::make_shared(); diff --git a/clang/test/Modules/module-file-home-is-cwd.m b/clang/test/Modules/module-file-home-is-cwd.m new file mode 100644 --- /dev/null +++ b/clang/test/Modules/module-file-home-is-cwd.m @@ -0,0 +1,8 @@ +// RUN: cd %S +// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-file-home-is-cwd -fmodule-name=libA -emit-module Inputs/normal-module-map/module.map -o %t/mod.pcm +// RUN: llvm-bcanalyzer --dump --disable-histogram %t/mod.pcm | FileCheck %s + +// CHECK: blob data = 'Inputs{{/|\\}}normal-module-map{{/|\\}}a1.h' +// CHECK: blob data = 'Inputs{{/|\\}}normal-module-map{{/|\\}}a2.h' +// CHECK: blob data = 'Inputs{{/|\\}}normal-module-map{{/|\\}}module.map' +// CHECK-NOT: MODULE_DIRECTORY