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:
+Configuration files can be either specified on the command line or loaded
+from default locations. If both variants are present, the default configuration
+files are loaded first.
+
+The command line option ``--config`` can be used to specify explicit
+configuration files in a Clang invocation. If the option is used multiple times,
+all specified files are loaded, in order. For example:
::
clang --config /home/user/cfgs/testing.txt
- clang --config debug.cfg
+ clang --config debug.cfg --config runtimes.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
``CLANG_CONFIG_FILE_SYSTEM_DIR`` respectively. The first file found is used.
It is an error if the required file cannot be found.
-If no explicit configuration file is specified, Clang searches for a default
-configuration file following the rules described in the next paragraphs.
-To disable this behavior, ``--no-default-config`` flag can be used.
+The default configuration files are searched for in the same directories
+following the rules described in the next paragraphs. Loading default
+configuration files can be disabled entirely via passing
+the ``--no-default-config`` flag.
-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.
+The name of the default configuration file is deduced from the clang 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
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
+ // objects than Args. This copies an Arg from one of those other InputArgLists
+ // to the ownership of Args.
+ unsigned Index = Args.MakeIndex(Opt->getSpelling());
+ Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
+ Index, BaseArg);
+ Copy->getValues() = Opt->getValues();
+ if (Opt->isClaimed())
+ Copy->claim();
+ Copy->setOwnsValues(Opt->getOwnsValues());
+ Opt->setOwnsValues(false);
+ Args.append(Copy);
+}
+
bool Driver::readConfigFile(StringRef FileName) {
// Try reading the given file.
SmallVector<const char *, 32> NewCfgArgs;
// Read options from config file.
llvm::SmallString<128> CfgFileName(FileName);
llvm::sys::path::native(CfgFileName);
- ConfigFile = std::string(CfgFileName);
bool ContainErrors;
- CfgOptions = std::make_unique<InputArgList>(
+ std::unique_ptr<InputArgList> NewOptions = std::make_unique<InputArgList>(
ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors));
- if (ContainErrors) {
- CfgOptions.reset();
+ if (ContainErrors)
return true;
- }
- if (CfgOptions->hasArg(options::OPT_config)) {
- CfgOptions.reset();
+ if (NewOptions->hasArg(options::OPT_config)) {
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)
+ for (Arg *A : *NewOptions)
A->claim();
+
+ if (!CfgOptions)
+ CfgOptions = std::move(NewOptions);
+ else {
+ // If this is a subsequent config file, append options to the previous one.
+ for (auto *Opt : *NewOptions) {
+ const Arg *BaseArg = &Opt->getBaseArg();
+ if (BaseArg == Opt)
+ BaseArg = nullptr;
+ appendOneArg(*CfgOptions, Opt, BaseArg);
+ }
+ }
+ ConfigFiles.push_back(std::string(CfgFileName));
return false;
}
-bool Driver::loadConfigFile() {
- std::string CfgFileName;
-
+bool Driver::loadConfigFiles() {
// Process options that change search path for config files.
if (CLOptions) {
if (CLOptions->hasArg(options::OPT_config_system_dir_EQ)) {
// Prepare list of directories where config file is searched for.
StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
- // First try to find config file specified in command line.
+ // First try to load configuration from the default files, return on error.
+ if (loadDefaultConfigFiles(CfgFileSearchDirs))
+ return true;
+
+ // Then load configuration files specified explicitly.
llvm::SmallString<128> CfgFilePath;
if (CLOptions) {
- std::vector<std::string> ConfigFiles =
- CLOptions->getAllArgValues(options::OPT_config);
- if (ConfigFiles.size() > 1) {
- if (!llvm::all_equal(ConfigFiles)) {
- Diag(diag::err_drv_duplicate_config);
- return true;
- }
- }
-
- if (!ConfigFiles.empty()) {
- CfgFileName = ConfigFiles.front();
- assert(!CfgFileName.empty());
-
+ 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)) {
- SmallString<128> CfgFilePath(CfgFileName);
+ CfgFilePath = CfgFileName;
if (llvm::sys::path::is_relative(CfgFilePath)) {
if (getVFS().makeAbsolute(CfgFilePath))
return true;
return true;
}
}
- return readConfigFile(CfgFilePath);
+ } else if (!searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName,
+ getVFS())) {
+ // 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)
+ if (!SearchDir.empty())
+ Diag(diag::note_drv_config_file_searched_in) << SearchDir;
+ return true;
}
- // Look for the configuration file in the usual locations.
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()))
- 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.
- Diag(diag::err_drv_config_file_not_found) << CfgFileName;
- for (const StringRef &SearchDir : CfgFileSearchDirs)
- if (!SearchDir.empty())
- Diag(diag::note_drv_config_file_searched_in) << SearchDir;
- return true;
+ // Try to read the config file, return on error.
+ if (readConfigFile(CfgFilePath))
+ return true;
}
}
- if (!(CLOptions && CLOptions->hasArg(options::OPT_no_default_config))) {
- // 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;
- }
+ // No error occurred.
+ return false;
+}
- if (CfgFileName.empty())
+bool Driver::loadDefaultConfigFiles(ArrayRef<StringRef> CfgFileSearchDirs) {
+ if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config))
return false;
+ if (ClangNameParts.TargetPrefix.empty())
+ return false;
+
+ // 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'.
+ std::string CfgFileName =
+ ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix;
// Determine architecture part of the file name, if it is present.
StringRef CfgFileArch = CfgFileName;
}
// Try to find config file. First try file with corrected architecture.
+ llvm::SmallString<128> CfgFilePath;
if (!FixedConfigFile.empty()) {
if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile,
getVFS()))
// Try parsing configuration file.
if (!ContainsError)
- ContainsError = loadConfigFile();
+ ContainsError = loadConfigFiles();
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));
- // The args for config files or /clang: flags belong to different InputArgList
- // objects than Args. This copies an Arg from one of those other InputArgLists
- // to the ownership of Args.
- auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) {
- unsigned Index = Args.MakeIndex(Opt->getSpelling());
- Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
- Index, BaseArg);
- Copy->getValues() = Opt->getValues();
- if (Opt->isClaimed())
- Copy->claim();
- Copy->setOwnsValues(Opt->getOwnsValues());
- Opt->setOwnsValues(false);
- Args.append(Copy);
- };
-
if (HasConfigFile)
for (auto *Opt : *CLOptions) {
if (Opt->getOption().matches(options::OPT_config))
const Arg *BaseArg = &Opt->getBaseArg();
if (BaseArg == Opt)
BaseArg = nullptr;
- appendOneArg(Opt, BaseArg);
+ appendOneArg(Args, Opt, BaseArg);
}
// In CL mode, look for any pass-through arguments
if (!ContainsError)
for (auto *Opt : *CLModePassThroughOptions) {
- appendOneArg(Opt, nullptr);
+ appendOneArg(Args, Opt, nullptr);
}
}
}
// Print out the install directory.
OS << "InstalledDir: " << InstalledDir << '\n';
- // If configuration file was used, print its path.
- if (!ConfigFile.empty())
+ // If configuration files were used, print their paths.
+ for (auto ConfigFile : ConfigFiles)
OS << "Configuration file: " << ConfigFile << '\n';
}