You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Clang] Support for MSVC compatible header search path ordering.
Clang has historically matched GCC's behavior for header search path order
and pruning of duplicate paths. That traditional behavior is to order user
search paths before system search paths, to ignore user search paths that
duplicate a (later) system search path, and to ignore search paths that
duplicate an earlier search path of the same user/system kind. This differs
from MSVC and can result in inconsistent header file resolution for `#include`
directives.
MSVC orders header search paths as follows:
1) Paths specified by the `/I` and `/external:I` options are processed in
the order that they appear. Paths specified by `/I` that duplicate a path
specified by `/external:I` are ignored regardless of the order of the
options. Paths specified by `/I` that duplicate a path from a prior `/I`
option are ignored. Paths specified by `/external:I` that duplicate a
path from a later `/external:I` option are ignored.
2) Paths specified by `/external:env` are processed in the order that they
appear. Paths that duplicate a path from a `/I` or `/external:I` option
are ignored regardless of the order of the options. Paths that duplicate a
path from a prior `/external:env` option or an earlier path from the same
`/external:env` option are ignored.
3) Paths specified by the `INCLUDE` environment variable are processed in
the order they appear. Paths that duplicate a path from a `/I`,
`/external:I`, or `/external:env` option are ignored. Paths that
duplicate an earlier path in the `INCLUDE` environment variable are
ignored.
4) Paths specified by the `EXTERNAL_INCLUDE` environment variable are
processed in the order they appear. Paths that duplicate a path from a
`/I`, `/external:I`, or `/external:env` option are ignored. Paths that
duplicate a path from the `INCLUDE` environment variable are ignored.
Paths that duplicate an earlier path in the `EXTERNAL_INCLUDE
environment variable are ignored.
Prior to this change, Clang handled the MSVC `/external:I` and `/external:env`
options and the paths present in the `INCLUDE` and `EXTERNAL_INCLUDE`
environment variables as though they were specified with the `-isystem` option.
The GCC behavior described above then lead to a command line such as
`/external:I dir1 /Idir2` having a header search order of `dir2` followed by
`dir1`; contrary to MSVC behavior.
Paths specified by the MSVC `/external:I` or `/external:env` options or by the
`EXTERNAL_INCLUDE` environment variable are not just used to nominate a header
search path. MSVC also uses these paths as external directory prefixes to mark
paths that are to be treated as system directories. When a header file is
resolved to a path for which one of these paths is a prefix match, that header
file is treated as a system header regardless of whether the header file was
resolved against a `/I` specified path. Note that it is not necessary for the
final path component of the external path to match a directory in the filesystem
in order to be used as an external directory prefix, though trailing path
separators are significant. For example:
Include directive Command line System header
------------------------ ------------------ -------------
#include <foobar/file.h> /I. /external:Ifoo Yes
#include <foobar/file.h> /I. /external:Ifoo\ No
This change adds support for the MSVC external path concept through the addition
of new driver options with the following option syntax.
clang clang-cl
------------------------ -------------------
-iexternal <dir> /external:I <dir>
-iexternal-env=<ENV> /external:env:<ENV>
Paths specified by these options are treated as system paths. That is, whether
warnings are issued in header files found via these paths remains subject to
use of the `-Wsystem-headers` and `-Wno-system-headers` options. Note that the
MSVC `/external:W<N>` options are mapped to these options.
The MSVC behavior described above implies that (system) paths present in the
`INCLUDE` and `EXTERNAL_INCLUDE` environment variables do not suppress matching
user paths specified via `/I`. This contrasts with GCC's behavior, and Clang's
historical behavior, of suppressing user paths that match a system path
regardless of how each is specified. In order to support both behaviors, the
following driver option has been added. The option arguments shown reflect the
default behavior for each driver.
clang clang-cl
------------------------ -------------------------
-fheader-search=gcc -fheader-search=microsoft
Use of the MSVC compatible header search path order by default for `clang-cl`
is a change in behavior with potential to cause problems for some projects that
build with `clang-cl`. Potentially impacted projects include those that specify
a header search path via either the `/I` option or in the `CPATH` environment
variable, but rely on the path being suppressed and/or treated as a system
header due to a duplicate path specified by another MSVC option or environment
variable or by the `-imsvc` option or one of the `-isystem` family of options.
Such projects can pass the `-fheader-search=gcc` option in their `clang-cl`
invocations to (mostly) restore previous behavior.
Clang emulates the MSVC behavior of resolving quoted header file inclusions
(e.g., `#include "file.h"`) by searching for a matching file in the directories
for the including files in the include stack. See Microsoft's documentation of
this feature in the Microsoft-specific section of
https://learn.microsoft.com/en-us/cpp/preprocessor/hash-include-directive-c-cpp.
Previously, this behavior was implicitly enabled when the `-fms-compatibility`
option is specified (implicitly for Windows targets). This change ties this
behavior to the `-fheader-search=microsoft` option instead. Projects that use
the `clang` (not `clang-cl`) driver to build code targeting Windows that depend
on this local header file lookup may be impacted by this change. Such projects
can try adding `-fheader-search=microsoft` to their `clang` invocations to
restore the prior behavior.
There is at least one behavior that MSVC exhibits that is not currently
replicated with these changes. Clang treats paths specified in the `INCLUDE`
environment variable as system directories; MSVC does not. Clang will therefore
suppress warnings in header files found via these paths by default while MSVC
will not. However, recent MSVC releases set the `EXTERNAL_INCLUDE` environment
variable to have the same paths as `INCLUDE` by default, so, for recent
releases, MSVC appears to suppress warnings for header files found via
`INCLUDE` by default when it does not. Note that many Microsoft provided header
files use `#pragma` directives to suppress warnings.
0 commit comments