diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 49e917a6a0786..40486e3b169aa 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3281,7 +3281,8 @@ defm declspec : BoolOption<"f", "declspec", def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group, Flags<[]>, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, - HelpText<"Specify the module cache path">; + HelpText<"Specify the module cache path">, + MarshallingInfoString>; def fmodules_user_build_path : Separate<["-"], "fmodules-user-build-path">, Group, Flags<[]>, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 64ebb70a6a24c..4744de9c8de0a 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -699,6 +699,8 @@ class CompilerInstance : public ModuleLoader { GetDependencyDirectives = std::move(Getter); } + static void normalizeModuleCachePath(FileManager &FileMgr, StringRef Path, + SmallVectorImpl &NormalizedPath); std::string getSpecificModuleCachePath(StringRef ModuleHash); std::string getSpecificModuleCachePath() { return getSpecificModuleCachePath(getInvocation().getModuleHash()); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index b2c566f44c27f..9646587f63cc5 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -547,10 +547,25 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { PP->setDependencyDirectivesGetter(*GetDependencyDirectives); } +void CompilerInstance::normalizeModuleCachePath( + FileManager &FileMgr, StringRef Path, + SmallVectorImpl &NormalizedPath) { + NormalizedPath.assign(Path.begin(), Path.end()); + FileMgr.makeAbsolutePath(NormalizedPath); + llvm::sys::path::remove_dots(NormalizedPath); +} + std::string CompilerInstance::getSpecificModuleCachePath(StringRef ModuleHash) { + assert(FileMgr && "Specific module cache path requires a FileManager"); + + if (getHeaderSearchOpts().ModuleCachePath.empty()) + return ""; + // Set up the module path, including the hash for the module-creation options. - SmallString<256> SpecificModuleCache(getHeaderSearchOpts().ModuleCachePath); - if (!SpecificModuleCache.empty() && !getHeaderSearchOpts().DisableModuleHash) + SmallString<256> SpecificModuleCache; + normalizeModuleCachePath(*FileMgr, getHeaderSearchOpts().ModuleCachePath, + SpecificModuleCache); + if (!getHeaderSearchOpts().DisableModuleHash) llvm::sys::path::append(SpecificModuleCache, ModuleHash); return std::string(SpecificModuleCache); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 8411d00cc7812..931766db4b0c8 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3315,9 +3315,6 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, if (Opts.UseLibcxx) GenerateArg(Consumer, OPT_stdlib_EQ, "libc++"); - if (!Opts.ModuleCachePath.empty()) - GenerateArg(Consumer, OPT_fmodules_cache_path, Opts.ModuleCachePath); - for (const auto &File : Opts.PrebuiltModuleFiles) GenerateArg(Consumer, OPT_fmodule_file, File.first + "=" + File.second); @@ -3420,8 +3417,7 @@ static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, } static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, - DiagnosticsEngine &Diags, - const std::string &WorkingDir) { + DiagnosticsEngine &Diags) { unsigned NumErrorsBefore = Diags.getNumErrors(); HeaderSearchOptions *HeaderSearchOpts = &Opts; @@ -3434,17 +3430,6 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); - // Canonicalize -fmodules-cache-path before storing it. - SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path)); - if (!(P.empty() || llvm::sys::path::is_absolute(P))) { - if (WorkingDir.empty()) - llvm::sys::fs::make_absolute(P); - else - llvm::sys::fs::make_absolute(WorkingDir, P); - } - llvm::sys::path::remove_dots(P); - Opts.ModuleCachePath = std::string(P); - // Only the -fmodule-file== form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); @@ -5021,8 +5006,7 @@ bool CompilerInvocation::CreateFromArgsImpl( InputKind DashX = Res.getFrontendOpts().DashX; ParseTargetArgs(Res.getTargetOpts(), Args, Diags); llvm::Triple T(Res.getTargetOpts().Triple); - ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags, - Res.getFileSystemOpts().WorkingDir); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags); if (Res.getFrontendOpts().GenReducedBMI || Res.getFrontendOpts().ProgramAction == frontend::GenerateReducedModuleInterface || diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 293b67aac0219..989e0f448dac3 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -57,6 +57,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/MacroInfo.h" @@ -1710,9 +1711,13 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, StringRef isysroot) { const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + SmallString<256> HSOpts_ModuleCachePath; + CompilerInstance::normalizeModuleCachePath( + PP.getFileManager(), HSOpts.ModuleCachePath, HSOpts_ModuleCachePath); + AddString(HSOpts.Sysroot, Record); AddString(HSOpts.ResourceDir, Record); - AddString(HSOpts.ModuleCachePath, Record); + AddString(HSOpts_ModuleCachePath, Record); AddString(HSOpts.ModuleUserBuildPath, Record); Record.push_back(HSOpts.DisableModuleHash); Record.push_back(HSOpts.ImplicitModuleMaps); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index b2b61de790e8f..8d6fbc8373ac3 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -448,9 +448,10 @@ class DependencyScanningAction { // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { - StringRef ModulesCachePath = - ScanInstance.getHeaderSearchOpts().ModuleCachePath; - + SmallString<256> ModulesCachePath; + CompilerInstance::normalizeModuleCachePath( + *FileMgr, ScanInstance.getHeaderSearchOpts().ModuleCachePath, + ModulesCachePath); DepFS->resetBypassedPathPrefix(); if (!ModulesCachePath.empty()) DepFS->setBypassedPathPrefix(ModulesCachePath); diff --git a/clang/test/Modules/modules-cache-path-canonicalization-output.c b/clang/test/Modules/modules-cache-path-canonicalization-output.c new file mode 100644 index 0000000000000..ad71b69e5299e --- /dev/null +++ b/clang/test/Modules/modules-cache-path-canonicalization-output.c @@ -0,0 +1,18 @@ +// This checks that implicitly-built modules produce identical PCM +// files regardless of the spelling of the same module cache path. + +// RUN: rm -rf %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fsyntax-only %t/tu.c \ +// RUN: -fmodules-cache-path=%t/cache -fdisable-module-hash +// RUN: mv %t/cache/M.pcm %t/M.pcm +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fsyntax-only %t/tu.c \ +// RUN: -fmodules-cache-path=%t/./cache -fdisable-module-hash +// RUN: diff %t/./cache/M.pcm %t/M.pcm + +//--- tu.c +#include "M.h" +//--- M.h +//--- module.modulemap +module M { header "M.h" }