diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -36,6 +36,9 @@ namespace vfs { class FileSystem; } +namespace cl { +class ExpansionContext; +} } // namespace llvm namespace clang { @@ -677,13 +680,14 @@ /// executable filename). /// /// \returns true if error occurred. - bool loadDefaultConfigFiles(ArrayRef CfgFileSearchDirs); + bool loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx); /// Read options from the specified file. /// /// \param [in] FileName File to read. + /// \param [in] Search and expansion options. /// \returns true, if error occurred while reading. - bool readConfigFile(StringRef FileName); + bool readConfigFile(StringRef FileName, llvm::cl::ExpansionContext &ExpCtx); /// Set the driver mode (cl, gcc, etc) from the value of the `--driver-mode` /// option. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -922,35 +922,6 @@ // } -/// Looks the given directories for the specified file. -/// -/// \param[out] FilePath File path, if the file was found. -/// \param[in] Dirs Directories used for the search. -/// \param[in] FileName Name of the file to search for. -/// \return True if file was found. -/// -/// Looks for file specified by FileName sequentially in directories specified -/// by Dirs. -/// -static bool searchForFile(SmallVectorImpl &FilePath, - ArrayRef Dirs, StringRef FileName, - llvm::vfs::FileSystem &FS) { - SmallString<128> WPath; - for (const StringRef &Dir : Dirs) { - if (Dir.empty()) - continue; - WPath.clear(); - llvm::sys::path::append(WPath, Dir, FileName); - llvm::sys::path::native(WPath); - auto Status = FS.status(WPath); - if (Status && Status->getType() == llvm::sys::fs::file_type::regular_file) { - FilePath = std::move(WPath); - return true; - } - } - return false; -} - static void appendOneArg(InputArgList &Args, const Arg *Opt, const Arg *BaseArg) { // The args for config files or /clang: flags belong to different InputArgList @@ -967,11 +938,10 @@ Args.append(Copy); } -bool Driver::readConfigFile(StringRef FileName) { +bool Driver::readConfigFile(StringRef FileName, + llvm::cl::ExpansionContext &ExpCtx) { // Try reading the given file. SmallVector NewCfgArgs; - llvm::cl::ExpansionContext ExpCtx(Alloc, llvm::cl::tokenizeConfigFile); - ExpCtx.setVFS(&getVFS()); if (!ExpCtx.readConfigFile(FileName, NewCfgArgs)) { Diag(diag::err_drv_cannot_read_config_file) << FileName; return true; @@ -1012,6 +982,10 @@ } bool Driver::loadConfigFiles() { + llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(), + llvm::cl::tokenizeConfigFile); + ExpCtx.setVFS(&getVFS()); + // Process options that change search path for config files. if (CLOptions) { if (CLOptions->hasArg(options::OPT_config_system_dir_EQ)) { @@ -1036,19 +1010,20 @@ // Prepare list of directories where config file is searched for. StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir}; + ExpCtx.setSearchDirs(CfgFileSearchDirs); // First try to load configuration from the default files, return on error. - if (loadDefaultConfigFiles(CfgFileSearchDirs)) + if (loadDefaultConfigFiles(ExpCtx)) return true; // Then load configuration files specified explicitly. - llvm::SmallString<128> CfgFilePath; + SmallString<128> CfgFilePath; if (CLOptions) { for (auto CfgFileName : CLOptions->getAllArgValues(options::OPT_config)) { // If argument contains directory separator, treat it as a path to // configuration file. if (llvm::sys::path::has_parent_path(CfgFileName)) { - CfgFilePath = CfgFileName; + CfgFilePath.assign(CfgFileName); if (llvm::sys::path::is_relative(CfgFilePath)) { if (getVFS().makeAbsolute(CfgFilePath)) return true; @@ -1059,8 +1034,7 @@ return true; } } - } else if (!searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, - getVFS())) { + } else if (!ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) { // Report an error that the config file could not be found. Diag(diag::err_drv_config_file_not_found) << CfgFileName; for (const StringRef &SearchDir : CfgFileSearchDirs) @@ -1070,7 +1044,7 @@ } // Try to read the config file, return on error. - if (readConfigFile(CfgFilePath)) + if (readConfigFile(CfgFilePath, ExpCtx)) return true; } } @@ -1079,7 +1053,7 @@ return false; } -bool Driver::loadDefaultConfigFiles(ArrayRef CfgFileSearchDirs) { +bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) { // Disable default config if CLANG_NO_DEFAULT_CONFIG is set to a non-empty // value. if (const char *NoConfigEnv = ::getenv("CLANG_NO_DEFAULT_CONFIG")) { @@ -1123,36 +1097,36 @@ // (e.g. i386-pc-linux-gnu.cfg + clang-g++.cfg for *clang-g++). // Try loading -.cfg, and return if we find a match. - llvm::SmallString<128> CfgFilePath; + SmallString<128> CfgFilePath; std::string CfgFileName = Triple + '-' + RealMode + ".cfg"; - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) - return readConfigFile(CfgFilePath); + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + return readConfigFile(CfgFilePath, ExpCtx); bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() && ClangNameParts.ModeSuffix != RealMode; if (TryModeSuffix) { CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg"; - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) - return readConfigFile(CfgFilePath); + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + return readConfigFile(CfgFilePath, ExpCtx); } // Try loading .cfg, and return if loading failed. If a matching file // was not found, still proceed on to try .cfg. CfgFileName = RealMode + ".cfg"; - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) { - if (readConfigFile(CfgFilePath)) + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) { + if (readConfigFile(CfgFilePath, ExpCtx)) return true; } else if (TryModeSuffix) { CfgFileName = ClangNameParts.ModeSuffix + ".cfg"; - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()) && - readConfigFile(CfgFilePath)) + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath) && + readConfigFile(CfgFilePath, ExpCtx)) return true; } // Try loading .cfg and return if we find a match. CfgFileName = Triple + ".cfg"; - if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) - return readConfigFile(CfgFilePath); + if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) + return readConfigFile(CfgFilePath, ExpCtx); // If we were unable to find a config file deduced from executable name, // that is not an error. diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -2140,6 +2140,9 @@ /// current directory is used instead. StringRef CurrentDir; + /// Directories used for search of config files. + ArrayRef SearchDirs; + /// True if names of nested response files must be resolved relative to /// including file. bool RelativeNames = false; @@ -2172,11 +2175,27 @@ return *this; } + ExpansionContext &setSearchDirs(ArrayRef X) { + SearchDirs = X; + return *this; + } + ExpansionContext &setVFS(vfs::FileSystem *X) { FS = X; return *this; } + /// Looks for the specified configuration file. + /// + /// \param[in] FileName Name of the file to search for. + /// \param[out] FilePath File absolute path, if it was found. + /// \return True if file was found. + /// + /// If the specified file name contains a directory separator, it is searched + /// for by its absolute path. Otherwise looks for file sequentially in + /// directories specified by SearchDirs field. + bool findConfigFile(StringRef FileName, SmallVectorImpl &FilePath); + /// Reads command line options from the given configuration file. /// /// \param [in] CfgFile Path to configuration file. diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1350,6 +1350,43 @@ ExpansionContext::ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T) : Saver(A), Tokenizer(T), FS(vfs::getRealFileSystem().get()) {} +bool ExpansionContext::findConfigFile(StringRef FileName, + SmallVectorImpl &FilePath) { + SmallString<128> CfgFilePath; + const auto FileExists = [this](SmallString<128> Path) -> bool { + auto Status = FS->status(Path); + return Status && + Status->getType() == llvm::sys::fs::file_type::regular_file; + }; + + // If file name contains directory separator, treat it as a path to + // configuration file. + if (llvm::sys::path::has_parent_path(FileName)) { + CfgFilePath = FileName; + if (llvm::sys::path::is_relative(FileName) && FS->makeAbsolute(CfgFilePath)) + return false; + if (!FileExists(CfgFilePath)) + return false; + FilePath.assign(CfgFilePath.begin(), CfgFilePath.end()); + return true; + } + + // Look for the file in search directories. + for (const StringRef &Dir : SearchDirs) { + if (Dir.empty()) + continue; + CfgFilePath.assign(Dir); + llvm::sys::path::append(CfgFilePath, FileName); + llvm::sys::path::native(CfgFilePath); + if (FileExists(CfgFilePath)) { + FilePath.assign(CfgFilePath.begin(), CfgFilePath.end()); + return true; + } + } + + return false; +} + bool ExpansionContext::readConfigFile(StringRef CfgFile, SmallVectorImpl &Argv) { SmallString<128> AbsPath;