summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/UsersManual.rst71
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td12
-rw-r--r--include/clang/Config/config.h.cmake4
-rw-r--r--include/clang/Driver/Driver.h45
-rw-r--r--include/clang/Driver/Options.td6
-rw-r--r--lib/Driver/Driver.cpp264
-rw-r--r--test/Driver/Inputs/config-1.cfg6
-rw-r--r--test/Driver/Inputs/config-2.cfg2
-rw-r--r--test/Driver/Inputs/config-2a.cfg2
-rw-r--r--test/Driver/Inputs/config-3.cfg1
-rw-r--r--test/Driver/Inputs/config-4.cfg2
-rw-r--r--test/Driver/Inputs/config-5.cfg2
-rw-r--r--test/Driver/Inputs/config-6.cfg1
-rw-r--r--test/Driver/Inputs/config/config-4.cfg1
-rw-r--r--test/Driver/Inputs/config/i386-qqq.cfg0
-rw-r--r--test/Driver/Inputs/config/i386-qqq3.cfg1
-rw-r--r--test/Driver/Inputs/config/x86_64-qqq.cfg1
-rw-r--r--test/Driver/Inputs/config/x86_64-qqq2.cfg1
-rw-r--r--test/Driver/Inputs/config/x86_64.cfg0
-rw-r--r--test/Driver/Inputs/config2/config-4.cfg1
-rw-r--r--test/Driver/Inputs/config2/i386.cfg0
-rw-r--r--test/Driver/config-file-errs.c54
-rw-r--r--test/Driver/config-file.c72
-rw-r--r--test/Driver/config-file2.c51
-rw-r--r--test/Driver/config-file3.c98
25 files changed, 686 insertions, 12 deletions
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 9596fb1cbd..fda887ac50 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -694,6 +694,77 @@ a special character, which is the convention used by GNU Make. The -MV
option tells Clang to put double-quotes around the entire filename, which
is the convention used by NMake and Jom.
+Configuration files
+-------------------
+
+Configuration files group command-line options and allow all of them to be
+specified just by referencing the configuration file. They may be used, for
+example, to collect options required to tune compilation for particular
+target, such as -L, -I, -l, --sysroot, codegen options, etc.
+
+The command line option `--config` can be used to specify configuration
+file in a Clang invocation. For example:
+
+::
+
+ clang --config /home/user/cfgs/testing.txt
+ clang --config debug.cfg
+
+If the provided argument contains a directory separator, it is considered as
+a file path, and options are read from that file. Otherwise the argument is
+treated as a file name and is searched for sequentially in the directories:
+ - user directory,
+ - system directory,
+ - the directory where Clang executable resides.
+Both user and system directories for configuration files are specified during
+clang build using CMake parameters, CLANG_CONFIG_FILE_USER_DIR and
+CLANG_CONFIG_FILE_SYSTEM_DIR respectively. The first file found is used. It is
+an error if the required file cannot be found.
+
+Another way to specify a configuration file is to encode it in executable name.
+For example, if the Clang executable is named `armv7l-clang` (it may be a
+symbolic link to `clang`), then Clang will search for file `armv7l.cfg` in the
+directory where Clang resides.
+
+If a driver mode is specified in invocation, Clang tries to find a file specific
+for the specified mode. For example, if the executable file is named
+`x86_64-clang-cl`, Clang first looks for `x86_64-cl.cfg` and if it is not found,
+looks for `x86_64.cfg'.
+
+If the command line contains options that effectively change target architecture
+(these are -m32, -EL, and some others) and the configuration file starts with an
+architecture name, Clang tries to load the configuration file for the effective
+architecture. For example, invocation:
+
+::
+
+ x86_64-clang -m32 abc.c
+
+causes Clang search for a file `i368.cfg` first, and if no such file is found,
+Clang looks for the file `x86_64.cfg`.
+
+The configuration file consists of command-line options specified on one or
+more lines. Lines composed of whitespace characters only are ignored as well as
+lines in which the first non-blank character is `#`. Long options may be split
+between several lines by a trailing backslash. Here is example of a
+configuration file:
+
+::
+
+ # Several options on line
+ -c --target=x86_64-unknown-linux-gnu
+
+ # Long option split between lines
+ -I/usr/lib/gcc/x86_64-linux-gnu/5.4.0/../../../../\
+ include/c++/5.4.0
+
+ # other config files may be included
+ @linux.options
+
+Files included by `@file` directives in configuration files are resolved
+relative to the including file. For example, if a configuration file
+`~/.llvm/target.cfg` contains the directive `@os/linux.opts`, the file
+`linux.opts` is searched for in the directory `~/.llvm/os`.
Language and Target-Independent Features
========================================
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 41b5e42b44..45cdf82d36 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -112,6 +112,18 @@ def err_drv_invalid_argument_to_fdebug_prefix_map : Error<
"invalid argument '%0' to -fdebug-prefix-map">;
def err_drv_malformed_sanitizer_blacklist : Error<
"malformed sanitizer blacklist: '%0'">;
+def err_drv_duplicate_config : Error<
+ "no more than one option '--config' is allowed">;
+def err_drv_config_file_not_exist : Error<
+ "configuration file '%0' does not exist">;
+def err_drv_config_file_not_found : Error<
+ "configuration file '%0' cannot be found">;
+def note_drv_config_file_searched_in : Note<
+ "was searched for in the directory: %0">;
+def err_drv_cannot_read_config_file : Error<
+ "cannot read configuration file '%0'">;
+def err_drv_nested_config_file: Error<
+ "option '--config' is not allowed inside configuration file">;
def err_target_unsupported_arch
: Error<"the target architecture '%0' is not supported by the target '%1'">;
diff --git a/include/clang/Config/config.h.cmake b/include/clang/Config/config.h.cmake
index daac9b7b45..5f420195e8 100644
--- a/include/clang/Config/config.h.cmake
+++ b/include/clang/Config/config.h.cmake
@@ -35,6 +35,10 @@
/* Directories clang will search for headers */
#define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}"
+/* Directories clang will search for configuration files */
+#cmakedefine CLANG_CONFIG_FILE_SYSTEM_DIR "${CLANG_CONFIG_FILE_SYSTEM_DIR}"
+#cmakedefine CLANG_CONFIG_FILE_USER_DIR "${CLANG_CONFIG_FILE_USER_DIR}"
+
/* Default <path> to all compiler invocations for --sysroot=<path>. */
#define DEFAULT_SYSROOT "${DEFAULT_SYSROOT}"
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index a3662872a9..0713430983 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -19,6 +19,8 @@
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/StringSaver.h"
#include <list>
#include <map>
@@ -26,14 +28,6 @@
namespace llvm {
class Triple;
-
-namespace opt {
- class Arg;
- class ArgList;
- class DerivedArgList;
- class InputArgList;
- class OptTable;
-}
}
namespace clang {
@@ -138,6 +132,12 @@ public:
/// The path to the compiler resource directory.
std::string ResourceDir;
+ /// System directory for config files.
+ std::string SystemConfigDir;
+
+ /// User directory for config files.
+ std::string UserConfigDir;
+
/// A prefix directory used to emulate a limited subset of GCC's '-Bprefix'
/// functionality.
/// FIXME: This type of customization should be removed in favor of the
@@ -208,6 +208,21 @@ private:
/// Name to use when invoking gcc/g++.
std::string CCCGenericGCCName;
+ /// Name of configuration file if used.
+ std::string ConfigFile;
+
+ /// Allocator for string saver.
+ llvm::BumpPtrAllocator Alloc;
+
+ /// Object that stores strings read from configuration file.
+ llvm::StringSaver Saver;
+
+ /// Arguments originated from configuration file.
+ std::unique_ptr<llvm::opt::InputArgList> CfgOptions;
+
+ /// Arguments originated from command line.
+ std::unique_ptr<llvm::opt::InputArgList> CLOptions;
+
/// Whether to check that input files exist when constructing compilation
/// jobs.
unsigned CheckInputsExist : 1;
@@ -277,6 +292,8 @@ public:
/// Name to use when invoking gcc/g++.
const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; }
+ const std::string &getConfigFile() const { return ConfigFile; }
+
const llvm::opt::OptTable &getOpts() const { return *Opts; }
const DiagnosticsEngine &getDiags() const { return Diags; }
@@ -493,6 +510,18 @@ public:
LTOKind getLTOMode() const { return LTOMode; }
private:
+
+ /// Tries to load options from configuration file.
+ ///
+ /// \returns true if error occurred.
+ bool loadConfigFile();
+
+ /// Read options from the specified file.
+ ///
+ /// \param [in] FileName File to read.
+ /// \returns true, if error occurred while reading.
+ bool readConfigFile(StringRef FileName);
+
/// Set the driver mode (cl, gcc, etc) from an option string of the form
/// --driver-mode=<mode>.
void setDriverModeFromOption(StringRef Opt);
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 7dc6632e82..3ee834e685 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -519,6 +519,12 @@ def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-round
def client__name : JoinedOrSeparate<["-"], "client_name">;
def combine : Flag<["-", "--"], "combine">, Flags<[DriverOption, Unsupported]>;
def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">;
+def config : Separate<["--"], "config">, Flags<[DriverOption]>,
+ HelpText<"Specifies configuration file">;
+def config_system_dir_EQ : Joined<["--"], "config-system-dir=">, Flags<[DriverOption, HelpHidden]>,
+ HelpText<"System directory for configuration files">;
+def config_user_dir_EQ : Joined<["--"], "config-user-dir=">, Flags<[DriverOption, HelpHidden]>,
+ HelpText<"User directory for configuration files">;
def coverage : Flag<["-", "--"], "coverage">, Flags<[CoreOption]>;
def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>;
def current__version : JoinedOrSeparate<["-"], "current_version">;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 9ae33b80f8..e29aa267ae 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -62,6 +62,7 @@
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -70,6 +71,7 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/StringSaver.h"
#include <map>
#include <memory>
#include <utility>
@@ -92,7 +94,8 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr),
CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false),
CCGenDiagnostics(false), DefaultTargetTriple(DefaultTargetTriple),
- CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true),
+ CCCGenericGCCName(""), Saver(Alloc),
+ CheckInputsExist(true), CCCUsePCH(true),
GenReproducer(false), SuppressMissingInputWarning(false) {
// Provide a sane fallback if no VFS is specified.
@@ -103,6 +106,13 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
Dir = llvm::sys::path::parent_path(ClangExecutable);
InstalledDir = Dir; // Provide a sensible default installed dir.
+#if defined(CLANG_CONFIG_FILE_SYSTEM_DIR)
+ SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR;
+#endif
+#if defined(CLANG_CONFIG_FILE_USER_DIR)
+ UserConfigDir = CLANG_CONFIG_FILE_USER_DIR;
+#endif
+
// Compute the path to the resource directory.
StringRef ClangResourceDir(CLANG_RESOURCE_DIR);
SmallString<128> P(Dir);
@@ -600,6 +610,216 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
//
}
+/// 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<char> &FilePath,
+ ArrayRef<std::string> Dirs,
+ StringRef FileName) {
+ 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);
+ if (llvm::sys::fs::is_regular_file(WPath)) {
+ FilePath = std::move(WPath);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Driver::readConfigFile(StringRef FileName) {
+ // Try reading the given file.
+ SmallVector<const char *, 32> NewCfgArgs;
+ if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) {
+ Diag(diag::err_drv_cannot_read_config_file) << FileName;
+ return true;
+ }
+
+ // Read options from config file.
+ llvm::SmallString<128> CfgFileName(FileName);
+ llvm::sys::path::native(CfgFileName);
+ ConfigFile = CfgFileName.str();
+ bool ContainErrors;
+ CfgOptions = llvm::make_unique<InputArgList>(
+ ParseArgStrings(NewCfgArgs, ContainErrors));
+ if (ContainErrors) {
+ CfgOptions.reset();
+ return true;
+ }
+
+ if (CfgOptions->hasArg(options::OPT_config)) {
+ CfgOptions.reset();
+ Diag(diag::err_drv_nested_config_file);
+ return true;
+ }
+
+ // Claim all arguments that come from a configuration file so that the driver
+ // does not warn on any that is unused.
+ for (Arg *A : *CfgOptions)
+ A->claim();
+ return false;
+}
+
+bool Driver::loadConfigFile() {
+ std::string CfgFileName;
+ bool FileSpecifiedExplicitly = false;
+
+ // Process options that change search path for config files.
+ if (CLOptions) {
+ if (CLOptions->hasArg(options::OPT_config_system_dir_EQ)) {
+ SmallString<128> CfgDir;
+ CfgDir.append(
+ CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ));
+ if (!CfgDir.empty()) {
+ if (std::error_code EC = llvm::sys::fs::make_absolute(CfgDir))
+ SystemConfigDir.clear();
+ else
+ SystemConfigDir = std::string(CfgDir.begin(), CfgDir.end());
+ }
+ }
+ if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) {
+ SmallString<128> CfgDir;
+ CfgDir.append(
+ CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ));
+ if (!CfgDir.empty()) {
+ if (std::error_code EC = llvm::sys::fs::make_absolute(CfgDir))
+ UserConfigDir.clear();
+ else
+ UserConfigDir = std::string(CfgDir.begin(), CfgDir.end());
+ }
+ }
+ }
+
+ // First try to find config file specified in command line.
+ if (CLOptions) {
+ std::vector<std::string> ConfigFiles =
+ CLOptions->getAllArgValues(options::OPT_config);
+ if (ConfigFiles.size() > 1) {
+ Diag(diag::err_drv_duplicate_config);
+ return true;
+ }
+
+ if (!ConfigFiles.empty()) {
+ CfgFileName = ConfigFiles.front();
+ assert(!CfgFileName.empty());
+
+ // If argument contains directory separator, treat it as a path to
+ // configuration file.
+ if (llvm::sys::path::has_parent_path(CfgFileName)) {
+ SmallString<128> CfgFilePath;
+ if (llvm::sys::path::is_relative(CfgFileName))
+ llvm::sys::fs::current_path(CfgFilePath);
+ llvm::sys::path::append(CfgFilePath, CfgFileName);
+ if (!llvm::sys::fs::is_regular_file(CfgFilePath)) {
+ Diag(diag::err_drv_config_file_not_exist) << CfgFilePath;
+ return true;
+ }
+ return readConfigFile(CfgFilePath);
+ }
+
+ FileSpecifiedExplicitly = true;
+ }
+ }
+
+ // If config file is not specified explicitly, try to deduce configuration
+ // from executable name. For instance, an executable 'armv7l-clang' will
+ // search for config file 'armv7l-clang.cfg'.
+ if (CfgFileName.empty() && !ClangNameParts.TargetPrefix.empty())
+ CfgFileName = ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix;
+
+ if (CfgFileName.empty())
+ return false;
+
+ // Determine architecture part of the file name, if it is present.
+ StringRef CfgFileArch = CfgFileName;
+ size_t ArchPrefixLen = CfgFileArch.find('-');
+ if (ArchPrefixLen == StringRef::npos)
+ ArchPrefixLen = CfgFileArch.size();
+ llvm::Triple CfgTriple;
+ CfgFileArch.take_front(ArchPrefixLen);
+ CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch));
+ if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch)
+ ArchPrefixLen = 0;
+
+ if (!StringRef(CfgFileName).endswith(".cfg"))
+ CfgFileName += ".cfg";
+
+ // If config file starts with architecture name and command line options
+ // redefine architecture (with options like -m32 -LE etc), try finding new
+ // config file with that architecture.
+ SmallString<128> FixedConfigFile;
+ size_t FixedArchPrefixLen = 0;
+ if (ArchPrefixLen) {
+ // Get architecture name from config file name like 'i386.cfg' or
+ // 'armv7l-clang.cfg'.
+ // Check if command line options changes effective triple.
+ llvm::Triple EffectiveTriple = computeTargetTriple(*this,
+ CfgTriple.getTriple(), *CLOptions);
+ if (CfgTriple.getArch() != EffectiveTriple.getArch()) {
+ FixedConfigFile = EffectiveTriple.getArchName();
+ FixedArchPrefixLen = FixedConfigFile.size();
+ // Append the rest of original file name so that file name transforms
+ // like: i386-clang.cfg -> x86_64-clang.cfg.
+ if (ArchPrefixLen < CfgFileName.size())
+ FixedConfigFile += CfgFileName.substr(ArchPrefixLen);
+ }
+ }
+
+ // Prepare list of directories where config file is searched for.
+ SmallVector<std::string, 3> CfgFileSearchDirs;
+ CfgFileSearchDirs.push_back(UserConfigDir);
+ CfgFileSearchDirs.push_back(SystemConfigDir);
+ CfgFileSearchDirs.push_back(Dir);
+
+ // Try to find config file. First try file with corrected architecture.
+ llvm::SmallString<128> CfgFilePath;
+ if (!FixedConfigFile.empty()) {
+ if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
+ return readConfigFile(CfgFilePath);
+ // If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'.
+ FixedConfigFile.resize(FixedArchPrefixLen);
+ FixedConfigFile.append(".cfg");
+ if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
+ return readConfigFile(CfgFilePath);
+ }
+
+ // Then try original file name.
+ if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
+ return readConfigFile(CfgFilePath);
+
+ // Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'.
+ if (!ClangNameParts.ModeSuffix.empty() &&
+ !ClangNameParts.TargetPrefix.empty()) {
+ CfgFileName.assign(ClangNameParts.TargetPrefix);
+ CfgFileName.append(".cfg");
+ if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
+ return readConfigFile(CfgFilePath);
+ }
+
+ // Report error but only if config file was specified explicitly, by option
+ // --config. If it was deduced from executable name, it is not an error.
+ if (FileSpecifiedExplicitly) {
+ Diag(diag::err_drv_config_file_not_found) << CfgFileName;
+ for (const std::string &SearchDir : CfgFileSearchDirs)
+ if (!SearchDir.empty())
+ Diag(diag::note_drv_config_file_searched_in) << SearchDir;
+ return true;
+ }
+
+ return false;
+}
+
Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
@@ -623,12 +843,35 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: What are we going to do with -V and -b?
+ // Arguments specified in command line.
+ bool ContainsError;
+ CLOptions = llvm::make_unique<InputArgList>(
+ ParseArgStrings(ArgList.slice(1), ContainsError));
+
+ // Try parsing configuration file.
+ if (!ContainsError)
+ ContainsError = loadConfigFile();
+ bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr);
+
+ // All arguments, from both config file and command line.
+ InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions)
+ : std::move(*CLOptions));
+ if (HasConfigFile)
+ for (auto *Opt : *CLOptions) {
+ const Arg *BaseArg = &Opt->getBaseArg();
+ if (BaseArg == Opt)
+ BaseArg = nullptr;
+ Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(),
+ Args.size(), BaseArg);
+ Copy->getValues() = Opt->getValues();
+ if (Opt->isClaimed())
+ Copy->claim();
+ Args.append(Copy);
+ }
+
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
- bool ContainsError;
- InputArgList Args = ParseArgStrings(ArgList.slice(1), ContainsError);
-
// Silence driver warnings if requested
Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
@@ -1144,6 +1387,10 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
// Print out the install directory.
OS << "InstalledDir: " << InstalledDir << '\n';
+
+ // If configuration file was used, print its path.
+ if (!ConfigFile.empty())
+ OS << "Configuration file: " << ConfigFile << '\n';
}
/// PrintDiagnosticCategories - Implement the --print-diagnostic-categories
@@ -1250,6 +1497,15 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
SuppressMissingInputWarning = true;
}
+ if (C.getArgs().hasArg(options::OPT_v)) {
+ if (!SystemConfigDir.empty())
+ llvm::errs() << "System configuration file directory: "
+ << SystemConfigDir << "\n";
+ if (!UserConfigDir.empty())
+ llvm::errs() << "User configuration file directory: "
+ << UserConfigDir << "\n";
+ }
+
const ToolChain &TC = C.getDefaultToolChain();
if (C.getArgs().hasArg(options::OPT_v))
diff --git a/test/Driver/Inputs/config-1.cfg b/test/Driver/Inputs/config-1.cfg
new file mode 100644
index 0000000000..7d1326fe8b
--- /dev/null
+++ b/test/Driver/Inputs/config-1.cfg
@@ -0,0 +1,6 @@
+
+# Empty lines and line started with # are ignored
+-Werror
+
+ # Language
+ -std=c99
diff --git a/test/Driver/Inputs/config-2.cfg b/test/Driver/Inputs/config-2.cfg
new file mode 100644
index 0000000000..c803bd2a78
--- /dev/null
+++ b/test/Driver/Inputs/config-2.cfg
@@ -0,0 +1,2 @@
+# nested inclusion
+@config-3.cfg
diff --git a/test/Driver/Inputs/config-2a.cfg b/test/Driver/Inputs/config-2a.cfg
new file mode 100644
index 0000000000..ecdc555156
--- /dev/null
+++ b/test/Driver/Inputs/config-2a.cfg
@@ -0,0 +1,2 @@
+# nested inclusion
+@config/config-4.cfg
diff --git a/test/Driver/Inputs/config-3.cfg b/test/Driver/Inputs/config-3.cfg
new file mode 100644
index 0000000000..d5086a8e4e
--- /dev/null
+++ b/test/Driver/Inputs/config-3.cfg
@@ -0,0 +1 @@
+-Wundefined-func-template
diff --git a/test/Driver/Inputs/config-4.cfg b/test/Driver/Inputs/config-4.cfg
new file mode 100644
index 0000000000..d8a022ae75
--- /dev/null
+++ b/test/Driver/Inputs/config-4.cfg
@@ -0,0 +1,2 @@
+-L/usr/local/lib
+-stdlib=libc++ \ No newline at end of file
diff --git a/test/Driver/Inputs/config-5.cfg b/test/Driver/Inputs/config-5.cfg
new file mode 100644
index 0000000000..09787ae6c4
--- /dev/null
+++ b/test/Driver/Inputs/config-5.cfg
@@ -0,0 +1,2 @@
+--serialize-diagnostics diag.ser
+-target
diff --git a/test/Driver/Inputs/config-6.cfg b/test/Driver/Inputs/config-6.cfg
new file mode 100644
index 0000000000..24d93cf8ec
--- /dev/null
+++ b/test/Driver/Inputs/config-6.cfg
@@ -0,0 +1 @@
+--config config-5
diff --git a/test/Driver/Inputs/config/config-4.cfg b/test/Driver/Inputs/config/config-4.cfg
new file mode 100644
index 0000000000..033e86a52a
--- /dev/null
+++ b/test/Driver/Inputs/config/config-4.cfg
@@ -0,0 +1 @@
+-isysroot /opt/data
diff --git a/test/Driver/Inputs/config/i386-qqq.cfg b/test/Driver/Inputs/config/i386-qqq.cfg
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/config/i386-qqq.cfg
diff --git a/test/Driver/Inputs/config/i386-qqq3.cfg b/test/Driver/Inputs/config/i386-qqq3.cfg
new file mode 100644
index 0000000000..9ae1735be3
--- /dev/null
+++ b/test/Driver/Inputs/config/i386-qqq3.cfg
@@ -0,0 +1 @@
+-target i383-unknown-linux \ No newline at end of file
diff --git a/test/Driver/Inputs/config/x86_64-qqq.cfg b/test/Driver/Inputs/config/x86_64-qqq.cfg
new file mode 100644
index 0000000000..c198278ec7
--- /dev/null
+++ b/test/Driver/Inputs/config/x86_64-qqq.cfg
@@ -0,0 +1 @@
+-target x86_64-unknown-linux
diff --git a/test/Driver/Inputs/config/x86_64-qqq2.cfg b/test/Driver/Inputs/config/x86_64-qqq2.cfg
new file mode 100644
index 0000000000..c198278ec7
--- /dev/null
+++ b/test/Driver/Inputs/config/x86_64-qqq2.cfg
@@ -0,0 +1 @@
+-target x86_64-unknown-linux
diff --git a/test/Driver/Inputs/config/x86_64.cfg b/test/Driver/Inputs/config/x86_64.cfg
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/config/x86_64.cfg
diff --git a/test/Driver/Inputs/config2/config-4.cfg b/test/Driver/Inputs/config2/config-4.cfg
new file mode 100644
index 0000000000..bd866b6966
--- /dev/null
+++ b/test/Driver/Inputs/config2/config-4.cfg
@@ -0,0 +1 @@
+-Wall
diff --git a/test/Driver/Inputs/config2/i386.cfg b/test/Driver/Inputs/config2/i386.cfg
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/config2/i386.cfg
diff --git a/test/Driver/config-file-errs.c b/test/Driver/config-file-errs.c
new file mode 100644
index 0000000000..8db2ea4392
--- /dev/null
+++ b/test/Driver/config-file-errs.c
@@ -0,0 +1,54 @@
+//--- No more than one '--config' may be specified.
+//
+// RUN: not %clang --config 1.cfg --config 2.cfg 2>&1 | FileCheck %s -check-prefix CHECK-DUPLICATE
+// CHECK-DUPLICATE: no more than one option '--config' is allowed
+
+
+//--- '--config' must be followed by config file name.
+//
+// RUN: not %clang --config 2>&1 | FileCheck %s -check-prefix CHECK-MISSING-FILE
+// CHECK-MISSING-FILE: argument to '--config' is missing (expected 1 value)
+
+
+//--- '--config' must not be found in config files.
+//
+// RUN: not %clang --config %S/Inputs/config-6.cfg 2>&1 | FileCheck %s -check-prefix CHECK-NESTED
+// CHECK-NESTED: option '--config' is not allowed inside configuration file
+
+
+//--- Argument of '--config' must be existing file, if it is specified by path.
+//
+// RUN: not %clang --config somewhere/nonexistent-config-file 2>&1 | FileCheck %s -check-prefix CHECK-NONEXISTENT
+// CHECK-NONEXISTENT: configuration file '{{.*}}somewhere/nonexistent-config-file' does not exist
+
+
+//--- Argument of '--config' must exist somewhere in well-known directories, if it is specified by bare name.
+//
+// RUN: not %clang --config-system-dir= --config-user-dir= --config nonexistent-config-file 2>&1 | FileCheck %s -check-prefix CHECK-NOTFOUND0
+// CHECK-NOTFOUND0: configuration file 'nonexistent-config-file.cfg' cannot be found
+// CHECK-NOTFOUND0-NEXT: was searched for in the directory:
+// CHECK-NOTFOUND0-NOT: was searched for in the directory:
+//
+// RUN: not %clang --config-system-dir= --config-user-dir=%S/Inputs/config2 --config nonexistent-config-file 2>&1 | FileCheck %s -check-prefix CHECK-NOTFOUND1
+// CHECK-NOTFOUND1: configuration file 'nonexistent-config-file.cfg' cannot be found
+// CHECK-NOTFOUND1-NEXT: was searched for in the directory: {{.*}}/Inputs/config2
+// CHECK-NOTFOUND1-NEXT: was searched for in the directory:
+// CHECK-NOTFOUND1-NOT: was searched for in the directory:
+//
+// RUN: not %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config nonexistent-config-file 2>&1 | FileCheck %s -check-prefix CHECK-NOTFOUND2
+// CHECK-NOTFOUND2: configuration file 'nonexistent-config-file.cfg' cannot be found
+// CHECK-NOTFOUND2-NEXT: was searched for in the directory: {{.*}}/Inputs/config
+// CHECK-NOTFOUND2-NEXT: was searched for in the directory:
+// CHECK-NOTFOUND2-NOT: was searched for in the directory:
+//
+// RUN: not %clang --config-system-dir=%S/Inputs/config --config-user-dir=%S/Inputs/config2 --config nonexistent-config-file 2>&1 | FileCheck %s -check-prefix CHECK-NOTFOUND3
+// CHECK-NOTFOUND3: configuration file 'nonexistent-config-file.cfg' cannot be found
+// CHECK-NOTFOUND3-NEXT: was searched for in the directory: {{.*}}/Inputs/config2
+// CHECK-NOTFOUND3-NEXT: was searched for in the directory: {{.*}}/Inputs/config
+// CHECK-NOTFOUND3-NEXT: was searched for in the directory:
+
+
+//--- Argument in config file cannot cross the file boundary
+//
+// RUN: not %clang --config %S/Inputs/config-5.cfg x86_64-unknown-linux-gnu -c %s 2>&1 | FileCheck %s -check-prefix CHECK-CROSS
+// CHECK-CROSS: error: argument to '-target' is missing
diff --git a/test/Driver/config-file.c b/test/Driver/config-file.c
new file mode 100644
index 0000000000..2d2d7a72b4
--- /dev/null
+++ b/test/Driver/config-file.c
@@ -0,0 +1,72 @@
+//--- Config file search directories
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir=%S/Inputs/config2 -v 2>&1 | FileCheck %s -check-prefix CHECK-DIRS
+// CHECK-DIRS: System configuration file directory: {{.*}}/Inputs/config
+// CHECK-DIRS: User configuration file directory: {{.*}}/Inputs/config2
+
+
+//--- Config file (full path) in output of -###
+//
+// RUN: %clang --config %S/Inputs/config-1.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-HHH
+// CHECK-HHH: Configuration file: {{.*}}Inputs{{.}}config-1.cfg
+// CHECK-HHH: -Werror
+// CHECK-HHH: -std=c99
+
+
+//--- Config file (full path) in output of -v
+//
+// RUN: %clang --config %S/Inputs/config-1.cfg -c %s -v 2>&1 | FileCheck %s -check-prefix CHECK-V
+// CHECK-V: Configuration file: {{.*}}Inputs{{.}}config-1.cfg
+// CHECK-V: -Werror
+// CHECK-V: -std=c99
+
+
+//--- Config file in output of -###
+//
+// RUN: %clang --config-system-dir=%S/Inputs --config-user-dir= --config config-1.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-HHH2
+// CHECK-HHH2: Configuration file: {{.*}}Inputs{{.}}config-1.cfg
+// CHECK-HHH2: -Werror
+// CHECK-HHH2: -std=c99
+
+
+//--- Config file in output of -v
+//
+// RUN: %clang --config-system-dir=%S/Inputs --config-user-dir= --config config-1.cfg -c %s -v 2>&1 | FileCheck %s -check-prefix CHECK-V2
+// CHECK-V2: Configuration file: {{.*}}Inputs{{.}}config-1.cfg
+// CHECK-V2: -Werror
+// CHECK-V2: -std=c99
+
+
+//--- Nested config files
+//
+// RUN: %clang --config-system-dir=%S/Inputs --config-user-dir= --config config-2.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NESTED
+// CHECK-NESTED: Configuration file: {{.*}}Inputs{{.}}config-2.cfg
+// CHECK-NESTED: -Wundefined-func-template
+
+// RUN: %clang --config-system-dir=%S/Inputs --config-user-dir= --config config-2.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NESTED2
+// CHECK-NESTED2: Configuration file: {{.*}}Inputs{{.}}config-2.cfg
+// CHECK-NESTED2: -Wundefined-func-template
+
+
+// RUN: %clang --config %S/Inputs/config-2a.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NESTEDa
+// CHECK-NESTEDa: Configuration file: {{.*}}Inputs{{.}}config-2a.cfg
+// CHECK-NESTEDa: -isysroot
+// CHECK-NESTEDa-SAME: /opt/data
+
+// RUN: %clang --config-system-dir=%S/Inputs --config-user-dir= --config config-2a.cfg -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-NESTED2a
+// CHECK-NESTED2a: Configuration file: {{.*}}Inputs{{.}}config-2a.cfg
+// CHECK-NESTED2a: -isysroot
+// CHECK-NESTED2a-SAME: /opt/data
+
+
+//--- Unused options in config file do not produce warnings
+//
+// RUN: %clang --config %S/Inputs/config-4.cfg -c %s -v 2>&1 | FileCheck %s -check-prefix CHECK-UNUSED
+// CHECK-UNUSED-NOT: argument unused during compilation:
+
+
+//--- User directory is searched first.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir=%S/Inputs/config2 --config config-4 -c %s -v 2>&1 | FileCheck %s -check-prefix CHECK-PRECEDENCE
+// CHECK-PRECEDENCE: Configuration file: {{.*}}Inputs{{.}}config2{{.}}config-4.cfg
+// CHECK-PRECEDENCE: -Wall
diff --git a/test/Driver/config-file2.c b/test/Driver/config-file2.c
new file mode 100644
index 0000000000..3a93b55eac
--- /dev/null
+++ b/test/Driver/config-file2.c
@@ -0,0 +1,51 @@
+// REQUIRES: x86-registered-target
+
+//--- Invocation `clang --config x86_64-qqq -m32` loads `i386-qqq.cfg` if the latter exists.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config x86_64-qqq -m32 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD
+// CHECK-RELOAD: Target: i386-unknown-linux
+// CHECK-RELOAD: Configuration file: {{.*}}Inputs{{.}}config{{.}}i386-qqq.cfg
+
+
+//--- Invocation `clang --config x86_64-qqq2 -m32` loads `i386.cfg` if the latter exists in another search directory.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir=%S/Inputs/config2 --config x86_64-qqq2 -m32 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1
+// CHECK-RELOAD1: Target: i386-unknown-linux
+// CHECK-RELOAD1: Configuration file: {{.*}}Inputs{{.}}config2{{.}}i386.cfg
+
+
+//--- Invocation `clang --config x86_64-qqq2 -m32` loads `x86_64-qqq2.cfg` if `i386-qqq2.cfg` and `i386.cfg` do not exist.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config x86_64-qqq2 -m32 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD2
+// note: target is overriden due to -m32
+// CHECK-RELOAD2: Target: i386-unknown-linux
+// CHECK-RELOAD2: Configuration file: {{.*}}Inputs{{.}}config{{.}}x86_64-qqq2.cfg
+
+
+//--- Invocation `clang --config i386-qqq3 -m64` loads `x86_64.cfg` if `x86_64-qqq3.cfg` does not exist.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config i386-qqq3 -m64 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD3
+// CHECK-RELOAD3: Target: x86_64-unknown-linux
+// CHECK-RELOAD3: Configuration file: {{.*}}Inputs{{.}}config{{.}}x86_64.cfg
+
+
+//--- Invocation `clang --config x86_64-qqq -target i386` loads `i386-qqq.cfg` if the latter exists.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config x86_64-qqq -target i386 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD4
+// CHECK-RELOAD4: Target: i386
+// CHECK-RELOAD4: Configuration file: {{.*}}Inputs{{.}}config{{.}}i386-qqq.cfg
+
+
+//--- Invocation `clang --config x86_64-qqq2 -target i386` loads `x86_64-qqq2.cfg` if `i386-qqq2.cfg` and `i386.cfg` do not exist.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config x86_64-qqq2 -target i386 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD5
+// note: target is overriden due to -target i386
+// CHECK-RELOAD5: Target: i386
+// CHECK-RELOAD5: Configuration file: {{.*}}Inputs{{.}}config{{.}}x86_64-qqq2.cfg
+
+
+//--- Invocation `clang --config x86_64-qqq -target i386 -m64` loads `x86_64-qqq.cfg`.
+//
+// RUN: %clang --config-system-dir=%S/Inputs/config --config-user-dir= --config x86_64-qqq -target i386 -m64 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD6
+// CHECK-RELOAD6: Target: x86_64
+// CHECK-RELOAD6: Configuration file: {{.*}}Inputs{{.}}config{{.}}x86_64-qqq.cfg
diff --git a/test/Driver/config-file3.c b/test/Driver/config-file3.c
new file mode 100644
index 0000000000..c1b523cbf9
--- /dev/null
+++ b/test/Driver/config-file3.c
@@ -0,0 +1,98 @@
+// REQUIRES: shell
+// REQUIRES: x86-registered-target
+
+//--- If config file is specified by relative path (workdir/cfg-s2), it is searched for by that path.
+//
+// RUN: mkdir -p %T/workdir
+// RUN: echo "@subdir/cfg-s2" > %T/workdir/cfg-1
+// RUN: mkdir -p %T/workdir/subdir
+// RUN: echo "-Wundefined-var-template" > %T/workdir/subdir/cfg-s2
+//
+// RUN: ( cd %T && %clang --config workdir/cfg-1 -c %s -### 2>&1 | FileCheck %s -check-prefix CHECK-REL )
+//
+// CHECK-REL: Configuration file: {{.*}}/workdir/cfg-1
+// CHECK-REL: -Wundefined-var-template
+
+
+//--- Invocation qqq-clang-g++ tries to find config file qqq-clang-g++.cfg first.
+//
+// RUN: mkdir -p %T/testdmode
+// RUN: [ ! -s %T/testdmode/qqq-clang-g++ ] || rm %T/testdmode/qqq-clang-g++
+// RUN: ln -s %clang %T/testdmode/qqq-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testdmode/qqq-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testdmode/qqq.cfg
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix FULL-NAME
+//
+// FULL-NAME: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
+// FULL-NAME: -Wundefined-func-template
+// FULL-NAME-NOT: -Werror
+//
+//--- File specified by --config overrides config inferred from clang executable.
+//
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --config i386-qqq -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-EXPLICIT
+//
+// CHECK-EXPLICIT: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
+//
+//--- Invocation qqq-clang-g++ tries to find config file qqq.cfg if qqq-clang-g++.cfg is not found.
+//
+// RUN: rm %T/testdmode/qqq-clang-g++.cfg
+// RUN: %T/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix SHORT-NAME
+//
+// SHORT-NAME: Configuration file: {{.*}}/testdmode/qqq.cfg
+// SHORT-NAME: -Werror
+// SHORT-NAME-NOT: -Wundefined-func-template
+
+
+//--- Config files are searched for in binary directory as well.
+//
+// RUN: mkdir -p %T/testbin
+// RUN: [ ! -s %T/testbin/clang ] || rm %T/testbin/clang
+// RUN: ln -s %clang %T/testbin/clang
+// RUN: echo "-Werror" > %T/testbin/aaa.cfg
+// RUN: %T/testbin/clang --config-system-dir= --config-user-dir= --config aaa.cfg -c -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-BIN
+//
+// CHECK-BIN: Configuration file: {{.*}}/testbin/aaa.cfg
+// CHECK-BIN: -Werror
+
+
+//--- If command line contains options that change triple (for instance, -m32), clang tries
+// reloading config file.
+
+//--- When reloading config file, x86_64-clang-g++ tries to find config i386-clang-g++.cfg first.
+//
+// RUN: mkdir -p %T/testreload
+// RUN: [ ! -s %T/testreload/x86_64-clang-g++ ] || rm %T/testreload/x86_64-clang-g++
+// RUN: ln -s %clang %T/testreload/x86_64-clang-g++
+// RUN: echo "-Wundefined-func-template" > %T/testreload/i386-clang-g++.cfg
+// RUN: echo "-Werror" > %T/testreload/i386.cfg
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir= --config-user-dir= -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD
+//
+// CHECK-RELOAD: Configuration file: {{.*}}/testreload/i386-clang-g++.cfg
+// CHECK-RELOAD: -Wundefined-func-template
+// CHECK-RELOAD-NOT: -Werror
+
+//--- If config file is specified by --config and its name does not start with architecture, it is used without reloading.
+//
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir=%S/Inputs --config-user-dir= --config config-3 -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1a
+//
+// CHECK-RELOAD1a: Configuration file: {{.*}}/Inputs/config-3.cfg
+//
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir=%S/Inputs --config-user-dir= --config config-3 -c -target i386 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1b
+//
+// CHECK-RELOAD1b: Configuration file: {{.*}}/Inputs/config-3.cfg
+
+//--- If config file is specified by --config and its name starts with architecture, it is reloaded.
+//
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --config x86_64-qqq -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1c
+//
+// CHECK-RELOAD1c: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
+
+//--- x86_64-clang-g++ tries to find config i386.cfg if i386-clang-g++.cfg is not found.
+//
+// RUN: rm %T/testreload/i386-clang-g++.cfg
+// RUN: %T/testreload/x86_64-clang-g++ --config-system-dir= --config-user-dir= -c -m32 -no-canonical-prefixes %s -### 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1d
+//
+// CHECK-RELOAD1d: Configuration file: {{.*}}/testreload/i386.cfg
+// CHECK-RELOAD1d: -Werror
+// CHECK-RELOAD1d-NOT: -Wundefined-func-template
+