[clang] [Driver] More flexible rules for loading default configs

Change the default config file loading logic to be more flexible
and more readable at the same time.  The new algorithm focuses on four
locations, in order:

1. <triple>-<mode>.cfg using real driver mode
2. <triple>-<mode>.cfg using executable suffix
3. <triple>.cfg + <mode>.cfg using real driver mode
4. <triple>.cfg + <mode>.cfg using executable suffix

This is meant to preserve reasonable level of compatibility with
the existing use, while introducing more flexibility and making the code
simpler.  Notably:

1. In this layout, the actual target triple is normally respected,
   and e.g. in `-m32` build the `x86_64-*` configs will never be used.

2. Both real driver mode (preferable) and executable suffix are
   supported.  This permits correctly handling calls with explicit
   `--driver-mode=` while at the same time preserving compatibility
   with the existing code.

3. The first two locations provide users with the ability to override
   configuration per specific target+mode combinaton, while the next two
   make it possible to independently specify per-target and per-mode
   configuration.

4. All config file locations are applicable independently of whether
   clang is started via a prefixed executable, or bare `clang`.

5. If the target is not explicitly specified and the executable prefix
   does not name a valid triple, it is used instead of the actual target
   triple for backwards compatibility.

This is particularly meant to address Gentoo's use case for
configuration files: to configure the default runtimes (i.e. `-rtlib=`,
`-stdlib=`) and `--gcc-install-dir=` for all the relevant drivers,
as well as to make it more convenient for users to override `-W` flags
to test compatibility with future versions of Clang easier.

Differential Revision: https://reviews.llvm.org/D134337
This commit is contained in:
Michał Górny 2022-09-29 20:58:35 +02:00
parent 062e515b70
commit 063e17d8b0
5 changed files with 371 additions and 163 deletions

View File

@ -242,6 +242,21 @@ Non-comprehensive list of changes in this release
- Unicode support has been updated to support Unicode 15.0. - Unicode support has been updated to support Unicode 15.0.
New unicode codepoints are supported as appropriate in diagnostics, New unicode codepoints are supported as appropriate in diagnostics,
C and C++ identifiers, and escape sequences. C and C++ identifiers, and escape sequences.
- Clang now supports loading multiple configuration files. The files from
default configuration paths are loaded first, unless ``--no-default-config``
option is used. All files explicitly specified using ``--config=`` option
are loaded afterwards.
- When loading default configuration files, clang now unconditionally uses
the real target triple (respecting options such as ``--target=`` and ``-m32``)
rather than the executable prefix. The respective configuration files are
also loaded when clang is called via an executable without a prefix (e.g.
plain ``clang``).
- Default configuration paths were partially changed. Clang now attempts to load
``<triple>-<driver>.cfg`` first, and falls back to loading both
``<driver>.cfg`` and ``<triple>.cfg`` if the former is not found. `Triple`
is the target triple and `driver` first tries the canonical name
for the driver (respecting ``--driver-mode=``), and then the name found
in the executable.
New Compiler Flags New Compiler Flags
------------------ ------------------
@ -257,12 +272,16 @@ New Compiler Flags
`::operator new(size_­t, std::aligned_val_t, nothrow_­t)` if there is `::operator new(size_­t, std::aligned_val_t, nothrow_­t)` if there is
`get_­return_­object_­on_­allocation_­failure`. We feel this is more consistent `get_­return_­object_­on_­allocation_­failure`. We feel this is more consistent
with the intention. with the intention.
- Added ``--no-default-config`` to disable automatically loading configuration
files using default paths.
Deprecated Compiler Flags Deprecated Compiler Flags
------------------------- -------------------------
Modified Compiler Flags Modified Compiler Flags
----------------------- -----------------------
- Clang now permits specifying ``--config=`` multiple times, to load multiple
configuration files.
Removed Compiler Flags Removed Compiler Flags
------------------------- -------------------------

View File

@ -914,27 +914,55 @@ following the rules described in the next paragraphs. Loading default
configuration files can be disabled entirely via passing configuration files can be disabled entirely via passing
the ``--no-default-config`` flag. the ``--no-default-config`` flag.
The name of the default configuration file is deduced from the clang executable First, the algorithm searches for a configuration file named
name. For example, if the Clang executable is named ``armv7l-clang`` (it may ``<triple>-<driver>.cfg`` where `triple` is the triple for the target being
be a symbolic link to ``clang``), then Clang will search for file built for, and `driver` is the name of the currently used driver. The algorithm
``armv7l.cfg`` in the directory where Clang resides. first attempts to use the canonical name for the driver used, then falls back
to the one found in the executable name.
If a driver mode is specified in invocation, Clang tries to find a file specific The following canonical driver names are used:
for the specified mode. For example, if the executable file is named
``x86_64-clang-cl``, Clang first looks for ``x86_64-clang-cl.cfg`` and if it is
not found, looks for ``x86_64.cfg``.
If the command line contains options that effectively change target architecture - ``clang`` for the ``gcc`` driver (used to compile C programs)
(these are ``-m32``, ``-EL``, and some others) and the configuration file starts - ``clang++`` for the ``gxx`` driver (used to compile C++ programs)
with an architecture name, Clang tries to load the configuration file for the - ``clang-cpp`` for the ``cpp`` driver (pure preprocessor)
effective architecture. For example, invocation: - ``clang-cl`` for the ``cl`` driver
- ``flang`` for the ``flang`` driver
- ``clang-dxc`` for the ``dxc`` driver
:: For example, when calling ``x86_64-pc-linux-gnu-clang-g++``,
the driver will first attempt to use the configuration file named::
x86_64-clang -m32 abc.c x86_64-pc-linux-gnu-clang++.cfg
causes Clang search for a file ``i368.cfg`` first, and if no such file is found, If this file is not found, it will attempt to use the name found
Clang looks for the file ``x86_64.cfg``. in the executable instead::
x86_64-pc-linux-gnu-clang-g++.cfg
Note that options such as ``--driver-mode=``, ``--target=``, ``-m32`` affect
the search algorithm. For example, the aforementioned executable called with
``-m32`` argument will instead search for::
i386-pc-linux-gnu-clang++.cfg
If none of the aforementioned files are found, the driver will instead search
for separate driver and target configuration files and attempt to load both.
The former is named ``<driver>.cfg`` while the latter is named
``<triple>.cfg``. Similarly to the previous variants, the canonical driver name
will be preferred, and the compiler will fall back to the actual name.
For example, ``x86_64-pc-linux-gnu-clang-g++`` will attempt to load two
configuration files named respectively::
clang++.cfg
x86_64-pc-linux-gnu.cfg
with fallback to trying::
clang-g++.cfg
x86_64-pc-linux-gnu.cfg
It is not an error if either of these files is not found.
The configuration file consists of command-line options specified on one or 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 more lines. Lines composed of whitespace characters only are ignored as well as

View File

@ -731,6 +731,9 @@ private:
&CachedResults, &CachedResults,
Action::OffloadKind TargetDeviceOffloadKind) const; Action::OffloadKind TargetDeviceOffloadKind) const;
/// Return the typical executable name for the specified driver \p Mode.
static const char *getExecutableForDriverMode(DriverMode Mode);
public: public:
/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
/// return the grouped values as integers. Numbers which are not /// return the grouped values as integers. Numbers which are not

View File

@ -1068,79 +1068,74 @@ bool Driver::loadConfigFiles() {
bool Driver::loadDefaultConfigFiles(ArrayRef<StringRef> CfgFileSearchDirs) { bool Driver::loadDefaultConfigFiles(ArrayRef<StringRef> CfgFileSearchDirs) {
if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config)) if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config))
return false; return false;
if (ClangNameParts.TargetPrefix.empty())
return false;
// If config file is not specified explicitly, try to deduce configuration std::string RealMode = getExecutableForDriverMode(Mode);
// from executable name. For instance, an executable 'armv7l-clang' will std::string Triple;
// 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. // If name prefix is present, no --target= override was passed via CLOptions
StringRef CfgFileArch = CfgFileName; // and the name prefix is not a valid triple, force it for backwards
size_t ArchPrefixLen = CfgFileArch.find('-'); // compatibility.
if (ArchPrefixLen == StringRef::npos) if (!ClangNameParts.TargetPrefix.empty() &&
ArchPrefixLen = CfgFileArch.size(); computeTargetTriple(*this, "/invalid/", *CLOptions).str() ==
llvm::Triple CfgTriple; "/invalid/") {
CfgFileArch = CfgFileArch.take_front(ArchPrefixLen); llvm::Triple PrefixTriple{ClangNameParts.TargetPrefix};
CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch)); if (PrefixTriple.getArch() == llvm::Triple::UnknownArch ||
if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch) PrefixTriple.isOSUnknown())
ArchPrefixLen = 0; Triple = PrefixTriple.str();
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);
}
} }
// Try to find config file. First try file with corrected architecture. // Otherwise, use the real triple as used by the driver.
if (Triple.empty()) {
llvm::Triple RealTriple =
computeTargetTriple(*this, TargetTriple, *CLOptions);
Triple = RealTriple.str();
assert(!Triple.empty());
}
// Search for config files in the following order:
// 1. <triple>-<mode>.cfg using real driver mode
// (e.g. i386-pc-linux-gnu-clang++.cfg).
// 2. <triple>-<mode>.cfg using executable suffix
// (e.g. i386-pc-linux-gnu-clang-g++.cfg for *clang-g++).
// 3. <triple>.cfg + <mode>.cfg using real driver mode
// (e.g. i386-pc-linux-gnu.cfg + clang++.cfg).
// 4. <triple>.cfg + <mode>.cfg using executable suffix
// (e.g. i386-pc-linux-gnu.cfg + clang-g++.cfg for *clang-g++).
// Try loading <triple>-<mode>.cfg, and return if we find a match.
llvm::SmallString<128> CfgFilePath; llvm::SmallString<128> CfgFilePath;
if (!FixedConfigFile.empty()) { std::string CfgFileName = Triple + '-' + RealMode + ".cfg";
if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile,
getVFS()))
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,
getVFS()))
return readConfigFile(CfgFilePath);
}
// Then try original file name.
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()))
return readConfigFile(CfgFilePath); return readConfigFile(CfgFilePath);
// Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'. bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() &&
if (!ClangNameParts.ModeSuffix.empty() && ClangNameParts.ModeSuffix != RealMode;
!ClangNameParts.TargetPrefix.empty()) { if (TryModeSuffix) {
CfgFileName.assign(ClangNameParts.TargetPrefix); CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg";
CfgFileName.append(".cfg");
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()))
return readConfigFile(CfgFilePath); return readConfigFile(CfgFilePath);
} }
// Try loading <mode>.cfg, and return if loading failed. If a matching file
// was not found, still proceed on to try <triple>.cfg.
CfgFileName = RealMode + ".cfg";
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS())) {
if (readConfigFile(CfgFilePath))
return true;
} else if (TryModeSuffix) {
CfgFileName = ClangNameParts.ModeSuffix + ".cfg";
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()) &&
readConfigFile(CfgFilePath))
return true;
}
// Try loading <triple>.cfg and return if we find a match.
CfgFileName = Triple + ".cfg";
if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName, getVFS()))
return readConfigFile(CfgFilePath);
// If we were unable to find a config file deduced from executable name, // If we were unable to find a config file deduced from executable name,
// do not report an error. // that is not an error.
return false; return false;
} }
@ -6201,6 +6196,25 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const {
return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask); return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
} }
const char *Driver::getExecutableForDriverMode(DriverMode Mode) {
switch (Mode) {
case GCCMode:
return "clang";
case GXXMode:
return "clang++";
case CPPMode:
return "clang-cpp";
case CLMode:
return "clang-cl";
case FlangMode:
return "flang";
case DXCMode:
return "clang-dxc";
}
llvm_unreachable("Unhandled Mode");
}
bool clang::driver::isOptimizationLevelFast(const ArgList &Args) { bool clang::driver::isOptimizationLevelFast(const ArgList &Args) {
return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false); return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false);
} }

View File

@ -9,112 +9,256 @@
// RUN: echo "@subdir/cfg-s2" > %t/workdir/cfg-1 // RUN: echo "@subdir/cfg-s2" > %t/workdir/cfg-1
// RUN: echo "-Wundefined-var-template" > %t/workdir/subdir/cfg-s2 // 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 ) // 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: Configuration file: {{.*}}/workdir/cfg-1
// CHECK-REL: -Wundefined-var-template // CHECK-REL: -Wundefined-var-template
//--- Invocation qqq-clang-g++ tries to find config file qqq-clang-g++.cfg first.
//
// RUN: mkdir %t/testdmode
// 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
//
//--- Invocation qqq-clang-g++ tries to find config file qqq-clang-g++.cfg even without -no-canonical-prefixes.
// (As the clang executable and symlink are in different directories, this
// requires specifying the path via --config-*-dir= though.)
//
// RUN: %t/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir=%t/testdmode -c -### %s 2>&1 | FileCheck %s -check-prefix SYMLINK
//
// SYMLINK: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
//--- File specified by --config is loaded after the one inferred from the executable.
//
// RUN: %t/testdmode/qqq-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --config i386-qqq.cfg -c -no-canonical-prefixes -### %s 2>&1 | FileCheck %s -check-prefix CHECK-EXPLICIT
//
// CHECK-EXPLICIT: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
// CHECK-EXPLICIT-NEXT: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
//--- --no-default-config disables config search.
//
// RUN: %t/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir=%t/testdmode --no-default-config -c -### %s 2>&1 | FileCheck %s -check-prefix NO-DEFAULT-CONFIG
//
// NO-DEFAULT-CONFIG-NOT: Configuration file:
//--- Explicit --config works with --no-default-config.
//
// RUN: %t/testdmode/qqq-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --no-default-config --config i386-qqq.cfg -c -no-canonical-prefixes -### %s 2>&1 | FileCheck %s -check-prefix CHECK-EXPLICIT-NO-DEFAULT
//
// CHECK-EXPLICIT-NO-DEFAULT-NOT: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
// CHECK-EXPLICIT-NO-DEFAULT: 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. //--- Config files are searched for in binary directory as well.
// //
// RUN: mkdir %t/testbin // RUN: mkdir %t/testbin
// RUN: ln -s %clang %t/testbin/clang // RUN: ln -s %clang %t/testbin/clang
// RUN: echo "-Werror" > %t/testbin/aaa.cfg // 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 // 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: Configuration file: {{.*}}/testbin/aaa.cfg
// CHECK-BIN: -Werror // CHECK-BIN: -Werror
//--- Invocation x86_64-unknown-linux-gnu-clang-g++ tries x86_64-unknown-linux-gnu-clang++.cfg first.
//--- 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 %t/testreload // RUN: mkdir %t/testdmode
// RUN: ln -s %clang %t/testreload/x86_64-clang-g++ // RUN: ln -s %clang %t/testdmode/cheribsd-riscv64-hybrid-clang++
// RUN: echo "-Wundefined-func-template" > %t/testreload/i386-clang-g++.cfg // RUN: ln -s %clang %t/testdmode/qqq-clang-g++
// RUN: echo "-Werror" > %t/testreload/i386.cfg // RUN: ln -s %clang %t/testdmode/x86_64-clang
// RUN: echo "-Wall" > %t/testreload/x86_64-clang-g++.cfg // RUN: ln -s %clang %t/testdmode/i386-unknown-linux-gnu-clang-g++
// 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 // RUN: ln -s %clang %t/testdmode/x86_64-unknown-linux-gnu-clang-g++
// RUN: ln -s %clang %t/testdmode/x86_64-unknown-linux-gnu-clang
// RUN: touch %t/testdmode/cheribsd-riscv64-hybrid-clang++.cfg
// RUN: touch %t/testdmode/cheribsd-riscv64-hybrid.cfg
// RUN: touch %t/testdmode/qqq-clang-g++.cfg
// RUN: touch %t/testdmode/qqq.cfg
// RUN: touch %t/testdmode/x86_64-clang.cfg
// RUN: touch %t/testdmode/x86_64.cfg
// RUN: touch %t/testdmode/x86_64-unknown-linux-gnu-clang++.cfg
// RUN: touch %t/testdmode/x86_64-unknown-linux-gnu-clang-g++.cfg
// RUN: touch %t/testdmode/x86_64-unknown-linux-gnu-clang.cfg
// RUN: touch %t/testdmode/x86_64-unknown-linux-gnu.cfg
// RUN: touch %t/testdmode/i386-unknown-linux-gnu-clang++.cfg
// RUN: touch %t/testdmode/i386-unknown-linux-gnu-clang-g++.cfg
// RUN: touch %t/testdmode/i386-unknown-linux-gnu-clang.cfg
// RUN: touch %t/testdmode/i386-unknown-linux-gnu.cfg
// RUN: touch %t/testdmode/clang++.cfg
// RUN: touch %t/testdmode/clang-g++.cfg
// RUN: touch %t/testdmode/clang.cfg
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1
// //
// CHECK-RELOAD: Configuration file: {{.*}}/testreload/i386-clang-g++.cfg // FULL1-NOT: Configuration file:
// CHECK-RELOAD: -Wundefined-func-template // FULL1: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu-clang++.cfg
// CHECK-RELOAD-NOT: -Werror // FULL1-NOT: Configuration file:
// CHECK-RELOAD-NOT: -Wall
//--- Same for -target in place of -m32. //--- -m32 overrides triple.
// RUN: %t/testreload/x86_64-clang-g++ --config-system-dir= --config-user-dir= -c -target i386 -no-canonical-prefixes -### %s 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD //
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ -m32 --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1-I386
//
// FULL1-I386-NOT: Configuration file:
// FULL1-I386: Configuration file: {{.*}}/testdmode/i386-unknown-linux-gnu-clang++.cfg
// FULL1-I386-NOT: Configuration file:
//--- `-target i386 -m64` should load the 64-bit config. //--- --target= also works for overriding triple.
// RUN: %t/testreload/x86_64-clang-g++ --config-system-dir= --config-user-dir= -c -target i386 -m64 -no-canonical-prefixes -### %s 2>&1 | FileCheck %s -check-prefix CHECK-RELOAD1a
// //
// CHECK-RELOAD1a: Configuration file: {{.*}}/testreload/x86_64-clang-g++.cfg // RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --target=i386-unknown-linux-gnu --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1-I386
// CHECK-RELOAD1a: -Wall
// CHECK-RELOAD1a-NOT: -Werror
// CHECK-RELOAD1a-NOT: -Wundefined-func-template
//--- x86_64-clang-g++ tries to find config i386.cfg if i386-clang-g++.cfg is not found. //--- With --target= + -m64, -m64 takes precedence.
// //
// RUN: rm %t/testreload/i386-clang-g++.cfg // RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --target=i386-unknown-linux-gnu -m64 --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1
// 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
// CHECK-RELOAD1d-NOT: -Wall
//--- x86_64-clang-g++ uses x86_64-clang-g++.cfg if i386*.cfg are not found. //--- i386 prefix also works for 32-bit.
// //
// RUN: rm %t/testreload/i386.cfg // RUN: %t/testdmode/i386-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1-I386
// 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-RELOAD1a
//--- i386 prefix + -m64 also works for 64-bit.
//
// RUN: %t/testdmode/i386-unknown-linux-gnu-clang-g++ -m64 --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1
//--- File specified by --config= is loaded after the one inferred from the executable.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --config=i386-qqq.cfg -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix EXPLICIT
//
// EXPLICIT: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu-clang++.cfg
// EXPLICIT-NEXT: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
//--- --no-default-config --config= loads only specified file.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --no-default-config --config=i386-qqq.cfg -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix EXPLICIT-ONLY
//
// EXPLICIT-ONLY-NOT: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu-clang++.cfg
// EXPLICIT-ONLY: Configuration file: {{.*}}/Inputs/config/i386-qqq.cfg
//--- --no-default-config disables default filenames.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir=%S/Inputs/config --config-user-dir= --no-default-config -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix NO-CONFIG
//
// NO-CONFIG-NOT: Configuration file:
//--- --driver-mode= is respected.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --driver-mode=gcc --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1-GCC
//
// FULL1-GCC-NOT: Configuration file:
// FULL1-GCC: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu-clang.cfg
// FULL1-GCC-NOT: Configuration file:
//--- "clang" driver symlink should yield the "*-clang" configuration file.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1-GCC
//--- "clang" + --driver-mode= should yield "*-clang++".
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang --driver-mode=g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1
//--- Clang started via name prefix that is not valid is forcing that prefix instead of target triple.
//
// RUN: %t/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix QQQ
//
// QQQ-NOT: Configuration file:
// QQQ: Configuration file: {{.*}}/testdmode/qqq-clang-g++.cfg
// QQQ-NOT: Configuration file:
//--- Explicit --target= overrides the triple even with non-standard name prefix.
//
// RUN: %t/testdmode/qqq-clang-g++ --target=x86_64-unknown-linux-gnu --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL1
//--- "x86_64" prefix does not form a valid triple either.
//
// RUN: %t/testdmode/x86_64-clang --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix X86_64
//
// X86_64-NOT: Configuration file:
// X86_64: Configuration file: {{.*}}/testdmode/x86_64-clang.cfg
// X86_64-NOT: Configuration file:
//--- Try cheribsd prefix using misordered triple components.
//
// RUN: %t/testdmode/cheribsd-riscv64-hybrid-clang++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix CHERIBSD
//
// CHERIBSD-NOT: Configuration file:
// CHERIBSD: Configuration file: {{.*}}/testdmode/cheribsd-riscv64-hybrid-clang++.cfg
// CHERIBSD-NOT: Configuration file:
//--- Test fallback to x86_64-unknown-linux-gnu-clang-g++.cfg.
//
// RUN: rm %t/testdmode/x86_64-unknown-linux-gnu-clang++.cfg
// RUN: rm %t/testdmode/i386-unknown-linux-gnu-clang++.cfg
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL2
//
// FULL2-NOT: Configuration file:
// FULL2: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu-clang-g++.cfg
// FULL2-NOT: Configuration file:
//--- FULL2 + -m32.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ -m32 --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL2-I386
//
// FULL2-I386-NOT: Configuration file:
// FULL2-I386: Configuration file: {{.*}}/testdmode/i386-unknown-linux-gnu-clang-g++.cfg
// FULL2-I386-NOT: Configuration file:
//--- Test fallback to x86_64-unknown-linux-gnu-clang.cfg + clang++.cfg.
//
// RUN: rm %t/testdmode/cheribsd-riscv64-hybrid-clang++.cfg
// RUN: rm %t/testdmode/qqq-clang-g++.cfg
// RUN: rm %t/testdmode/x86_64-clang.cfg
// RUN: rm %t/testdmode/x86_64-unknown-linux-gnu-clang-g++.cfg
// RUN: rm %t/testdmode/i386-unknown-linux-gnu-clang-g++.cfg
// RUN: rm %t/testdmode/x86_64-unknown-linux-gnu-clang.cfg
// RUN: rm %t/testdmode/i386-unknown-linux-gnu-clang.cfg
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL3
//
// FULL3-NOT: Configuration file:
// FULL3: Configuration file: {{.*}}/testdmode/clang++.cfg
// FULL3-NOT: Configuration file:
// FULL3: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu.cfg
// FULL3-NOT: Configuration file:
//--- FULL3 + -m32.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ -m32 --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL3-I386
//
// FULL3-I386-NOT: Configuration file:
// FULL3-I386: Configuration file: {{.*}}/testdmode/clang++.cfg
// FULL3-I386-NOT: Configuration file:
// FULL3-I386: Configuration file: {{.*}}/testdmode/i386-unknown-linux-gnu.cfg
// FULL3-I386-NOT: Configuration file:
//--- FULL3 + --driver-mode=.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --driver-mode=gcc --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL3-GCC
//
// FULL3-GCC-NOT: Configuration file:
// FULL3-GCC: Configuration file: {{.*}}/testdmode/clang.cfg
// FULL3-GCC-NOT: Configuration file:
// FULL3-GCC: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu.cfg
// FULL3-GCC-NOT: Configuration file:
//--- QQQ fallback.
//
// RUN: %t/testdmode/qqq-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix QQQ-FALLBACK
//
// QQQ-FALLBACK-NOT: Configuration file:
// QQQ-FALLBACK: Configuration file: {{.*}}/testdmode/clang++.cfg
// QQQ-FALLBACK-NOT: Configuration file:
// QQQ-FALLBACK: Configuration file: {{.*}}/testdmode/qqq.cfg
// QQQ-FALLBACK-NOT: Configuration file:
//--- "x86_64" falback.
//
// RUN: %t/testdmode/x86_64-clang --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix X86_64-FALLBACK
//
// X86_64-FALLBACK-NOT: Configuration file:
// X86_64-FALLBACK: Configuration file: {{.*}}/testdmode/clang.cfg
// X86_64-FALLBACK-NOT: Configuration file:
// X86_64-FALLBACK: Configuration file: {{.*}}/testdmode/x86_64.cfg
// X86_64-FALLBACK-NOT: Configuration file:
//--- cheribsd fallback.
//
// RUN: %t/testdmode/cheribsd-riscv64-hybrid-clang++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix CHERIBSD-FALLBACK
//
// CHERIBSD-FALLBACK-NOT: Configuration file:
// CHERIBSD-FALLBACK: Configuration file: {{.*}}/testdmode/clang++.cfg
// CHERIBSD-FALLBACK-NOT: Configuration file:
// CHERIBSD-FALLBACK: Configuration file: {{.*}}/testdmode/cheribsd-riscv64-hybrid.cfg
// CHERIBSD-FALLBACK-NOT: Configuration file:
//--- Test fallback to x86_64-unknown-linux-gnu.cfg + clang-g++.cfg.
//
// RUN: rm %t/testdmode/clang++.cfg
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL4
//
// FULL4-NOT: Configuration file:
// FULL4: Configuration file: {{.*}}/testdmode/clang-g++.cfg
// FULL4-NOT: Configuration file:
// FULL4: Configuration file: {{.*}}/testdmode/x86_64-unknown-linux-gnu.cfg
// FULL4-NOT: Configuration file:
//--- Test fallback to clang-g++.cfg if x86_64-unknown-linux-gnu-clang.cfg does not exist.
//
// RUN: rm %t/testdmode/x86_64-unknown-linux-gnu.cfg
// RUN: rm %t/testdmode/i386-unknown-linux-gnu.cfg
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL5
//
// FULL5-NOT: Configuration file:
// FULL5: Configuration file: {{.*}}/testdmode/clang-g++.cfg
// FULL5-NOT: Configuration file:
//--- FULL5 + -m32.
//
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ -m32 --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix FULL5-I386
//
// FULL5-I386-NOT: Configuration file:
// FULL5-I386: Configuration file: {{.*}}/testdmode/clang-g++.cfg
// FULL5-I386-NOT: Configuration file:
//--- Test that incorrect driver mode config file is not used.
//
// RUN: rm %t/testdmode/clang-g++.cfg
// RUN: %t/testdmode/x86_64-unknown-linux-gnu-clang-g++ --config-system-dir= --config-user-dir= -no-canonical-prefixes --version 2>&1 | FileCheck %s -check-prefix NO-CONFIG