If you have tried to keep your code clean by selecting strict compiler warning levels or code analysis rulesets, you likely know how frustrating it can be to see these warnings for headers that are not part of your project. To alleviate this, we’ve made it easy to mark headers as external to your project in the latest preview Visual Studio 2019. This is something we have been working on for a while with help and feedback from the community. Some of you may remember our previous post, Broken Warnings Theory, when we added experimental external header support to the Microsoft C++ Compiler. I’m happy to announce that, thanks to this feedback, external headers are now officially supported by the compiler, code analysis, and integrated into the IDE.
These external headers can have their own compiler warning level, code analysis, and template diagnostics settings. This leaves you free to choose stricter settings for your project’s code to enforce code quality without getting bogged down with warnings from headers that are beyond your control.
Adding External Headers to Your Projects
You can find a new “External Include Directories” property for your projects under “VC++ Directories” which can be used to designate any include directory as containing external headers. This external include directory will be added to the include search path as normal, but every header that in that directory or a subdirectory of it will be treated as external. From a compilation standpoint, you won’t notice any differences, but you can choose a different set of warning levels and other analysis settings for headers in these directories.
By default, all headers from the toolset and the Windows SDK are included as external headers. However, you can add any other include directories (such as 3rd party libraries) to this new property, separated by a semicolon as well.
Keep in mind that this new property will be ignored by earlier versions of the toolset. If you want to ensure that the project builds properly with earlier versions, you will need to make sure that any “External Include Directories” are also listed in the “Include Directories” property or they will not be found by the compiler. In Visual Studio 2019, we will continue to also include the toolset and Windows SDK headers in the existing “Include Directories” property for backwards compatibility, but in the next major release of Visual Studio this will be removed.
Customizing Warning Levels External Headers
You can customize the way external headers are treated in the project properties “C/C++ > External Includes” tab.
Customizing Code Analysis Settings for External Headers
Being able to mark certain headers as external to the project will make Code Analysis much easier to use. The examples below show some of the ways you can leverage this new feature to get the most out of Code Analysis.
Migration from undocumented CAExcludePath to /external:* and /analyze:external* options
To support one of the most common requirements of suppressing code analysis warnings for defects in library headers over which developers have no control, we created a temporary solution to use a special environment variable (“CAExcludePath”), that can be used to specify directories for which code analysis will not report any warnings.
We now have a better solution to control code analysis behavior for external files. While we decided to leave “CAExcludePath” option as is, we strongly recommend to switch to the /external:* and /analyze:external* options. With these options, code analysis of external headers can be turned off, or use a separate ruleset from the rest of the codebase. These come with even better usability and maintainability as they are all available through the VS IDE.
Using /analyze:external- with /external:*
Consider the following header and source files, with no meaningful functionality but intentionally injected bugs:
Header File (externallib.h)
#pragma once #include <Windows.h> #pragma warning (disable:26440 26497) namespace ExternalLib { #pragma warning(disable:4700) int GetValue() { int arr[2]; return arr[2]; } template <typename T> T GetValue(T, _In_range_(0, sizeof(T) - 1) int) { T arr[4]; return arr[sizeof(T)]; }; }
Source File (MyApp1.cpp)
#include <externallib.h> using namespace ExternalLib; void foo() { auto sum = GetValue(3ll, 4); sum += GetValue(3, 3); sum += GetValue(L'a', 2); sum += GetValue('a', 1); }
When analyzed with default options we get code analysis warnings for functions from both the header file and source file:
Now, if we add the directory for the externallib.h to the “External Include Directories” as follows:
And then set the “Disable Code Analysis for External Headers” to “Yes (/analyze:external-)” as follows:
Executing “Run Code Analysis” will no longer report any Code Analysis warnings from the external header file:
Some templates may have bugs depending on the template arguments. If you want to analyze templates even if they are in the external files, you can set the “Template Diagnostics in External Headers” option to “Yes (/external:templates-)”. Now, executing “Run Code Analysis” will report Code Analysis warnings for the template functions even if they are in the external header file:
Using /analyze:external:ruleset with /external:*
Instead of turning off code analysis for external files, it is now possible to analyze external files with a different ruleset from the rest of the codebase by specifying a different ruleset file with the “Analysis Ruleset for External Headers” option.
For this example, I have created a custom ruleset “ExternalHeaderRules” that enables only two rules, C6021 and C6385, as warnings. Then I selected it for the “Analysis Ruleset for External Headers” option:
Please note that the “Disable Code Analysis for External Headers” option is set to “No”, enabling code analysis on the external headers. With this change, code analysis will now analyze functions from external files using the custom “ExternalHeaderRules” ruleset, and report following warnings:
Currently, the “Template Diagnostics in External Headers” option is ignored if “Analysis Ruleset for External Headers” is used. We plan to change the behavior to honor the option and treat templates as non-external and apply the general ruleset instead of the ruleset for external headers.
Bonus: Even Better Code Analysis Performance
While we were working on this feature, we realized some of the built-in checkers were not really skipping functions from the files that are excluded through “CAExcludePath” environment variable. Instead, they were analyzed just like others and the resultant warnings from those functions were simply filtered out. As we add support for the /external:* option, we updated them to honor “CAExcludePath” as well as /external:* and /analyze:external- options, and to skip analysis of functions from excluded or external files. This resulted in observed performance improvements in our production codebase, ranging from 25% to 30%. Actual performance improvements will vary depending on how much of the codebase is from excluded or external header files, and how much of the project uses PCH, etc.
External Headers and the Microsoft C++ Compiler
Several new flags have been added to the Microsoft C++ Compiler to specify external include directories and their warning and code analysis settings. You can learn more about the behavior of these flags on our compiler documentation pages.
Send Us Feedback
Please grab a copy of the latest Visual Studio 2019 preview and try it out. We would love to hear your feedback about Visual Studio. If you have feedback, suggestions, or any other comments please submit them to Developer Community.
Setting the /analyze:external- option (Disable Code Analysis for External Headers) doesn’t appear to have any effect on headers from vcpkg usage. It’d be nice if it did.
Do you want a bug report on this, or is it work in progress already?
Thanks a lot for sharing your experience and suggestion. I recommend opening a feedback on this for the vcpkg so that vcpkg and add support for this. I guess /external:* in general does not work for vcpkg out of the box - i.e., compiler warnings also get generated for headers from vcpkg. So, please note all the related issues in the feedback. That way, we will have a tracking feedback for this regardless whether it...