Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -751,6 +751,9 @@ HelpText<"Disable the module hash">; def fmodules_hash_content : Flag<["-"], "fmodules-hash-content">, HelpText<"Enable hashing the content of a module file">; +def fdisable_module_directory : Flag<["-"], "fdisable-module-directory">, + HelpText<"Do not relativize paths to the module home directory or absolutify " + "paths that are not relative to the module home directory.">; def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"">, HelpText<"Add directory to the C SYSTEM include search path">; def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">, Index: include/clang/Lex/HeaderSearchOptions.h =================================================================== --- include/clang/Lex/HeaderSearchOptions.h +++ include/clang/Lex/HeaderSearchOptions.h @@ -203,6 +203,10 @@ unsigned ModulesHashContent : 1; + /// Do not relativize paths to the module directory or absolutify non-module- + /// directory-relative paths. + unsigned DisableModuleDirectory : 1; + HeaderSearchOptions(StringRef _Sysroot = "/") : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false), ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false), @@ -210,7 +214,8 @@ UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), ModulesValidateOncePerBuildSession(false), ModulesValidateSystemHeaders(false), UseDebugInfo(false), - ModulesValidateDiagnosticOptions(true), ModulesHashContent(false) {} + ModulesValidateDiagnosticOptions(true), ModulesHashContent(false), + DisableModuleDirectory(true) {} /// AddPath - Add the \p Path path to the specified \p Group list. void AddPath(StringRef Path, frontend::IncludeDirGroup Group, Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1746,6 +1746,7 @@ Opts.AddPrebuiltModulePath(A->getValue()); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content); + Opts.DisableModuleDirectory = Args.hasArg(OPT_fdisable_module_directory); Opts.ModulesValidateDiagnosticOptions = !Args.hasArg(OPT_fmodules_disable_diagnostic_validation); Opts.ImplicitModuleMaps = Args.hasArg(OPT_fimplicit_module_maps); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -1339,9 +1339,14 @@ /// /// \return \c true if the path was changed. static bool cleanPathForOutput(FileManager &FileMgr, - SmallVectorImpl &Path) { - bool Changed = FileMgr.makeAbsolutePath(Path); - return Changed | llvm::sys::path::remove_dots(Path); + SmallVectorImpl &Path, + bool MakeAbsolute = true) { + bool Changed = false; + if (MakeAbsolute) { + Changed |= FileMgr.makeAbsolutePath(Path); + } + Changed |= llvm::sys::path::remove_dots(Path); + return Changed; } /// Adjusts the given filename to only write out the portion of the @@ -1503,7 +1508,11 @@ Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name); } - if (WritingModule && WritingModule->Directory) { + if (WritingModule && + WritingModule->Directory && + !PP.getHeaderSearchInfo() + .getHeaderSearchOpts() + .DisableModuleDirectory) { SmallString<128> BaseDir(WritingModule->Directory->getName()); cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); @@ -2952,12 +2961,20 @@ // Emit the umbrella header, if there is one. if (auto UmbrellaHeader = Mod->getUmbrellaHeader()) { RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_HEADER}; - Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, - UmbrellaHeader.NameAsWritten); + SmallString<128> Buffer; + llvm::sys::path::append(Buffer, + Mod->Directory->getName(), + UmbrellaHeader.NameAsWritten); + llvm::sys::path::remove_dots(Buffer); + Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, Buffer); } else if (auto UmbrellaDir = Mod->getUmbrellaDir()) { RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_DIR}; - Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, - UmbrellaDir.NameAsWritten); + SmallString<128> Buffer; + llvm::sys::path::append(Buffer, + Mod->Directory->getName(), + UmbrellaDir.NameAsWritten); + llvm::sys::path::remove_dots(Buffer); + Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, Buffer); } // Emit the headers. @@ -4515,7 +4532,11 @@ assert(Context && "should have context when outputting path"); bool Changed = - cleanPathForOutput(Context->getSourceManager().getFileManager(), Path); + cleanPathForOutput(Context->getSourceManager().getFileManager(), + Path, + !PP->getHeaderSearchInfo() + .getHeaderSearchOpts() + .DisableModuleDirectory); // Remove a prefix to make the path relative, if relevant. const char *PathBegin = Path.data(); Index: test/Modules/relocatable-modules.modulemap =================================================================== --- /dev/null +++ test/Modules/relocatable-modules.modulemap @@ -0,0 +1,29 @@ +// Build two otherwise identical modules in two different directories and +// verify that using `-fdisable-module-directory` makes them identical. +// +// RUN: rm -rf %t +// +// RUN: mkdir -p %t/p1 +// RUN: cd %t/p1 +// RUN: mkdir -p main other +// RUN: grep "" %s > main/a.modulemap +// RUN: grep "" %s > main/a.h +// RUN: grep "" %s > other/b.h +// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fdisable-module-directory \ +// RUN: -fmodule-name="a" -Imain -I. -o - main/a.modulemap > a.pcm +// +// RUN: mkdir -p %t/p2 +// RUN: cd %t/p2 +// RUN: mkdir -p main other +// RUN: grep "" %s > main/a.modulemap +// RUN: grep "" %s > main/a.h +// RUN: grep "" %s > other/b.h +// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fdisable-module-directory \ +// RUN: -fmodule-name="a" -Imain -I. -o - main/a.modulemap > a.pcm +// +// RUN: diff %t/p1/a.pcm %t/p2/a.pcm + +module "a" { // +} // + +#include "b.h" //