mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-06 05:16:58 +00:00
PCH: Add PCH_WARNINGS property to get warnings from precompiled headers
The generated precompiled header is marked as a system header, which suppresses the diagnostics of every header it includes. Enabling precompiled headers therefore silently hides warnings that the same build would produce without them. Move the pragma out of CMAKE_PCH_PROLOGUE into its own CMAKE_PCH_SYSTEM_HEADER_PRAGMA variable so that it can be omitted independently of the user-facing prologue and epilogue, and add a PCH_WARNINGS target property, initialized by CMAKE_PCH_WARNINGS, to omit it. The diagnostics are then reported once, while compiling the precompiled header itself. Fixes: #21219
This commit is contained in:
20 files changed
+141
-9
No files matched your search
@@ -127,6 +127,9 @@ See Also
|
||||
* To prevent precompile headers from being used when compiling a specific
|
||||
source file, see the :prop_sf:`SKIP_PRECOMPILE_HEADERS` source file property.
|
||||
|
||||
* To get compiler warnings for the precompiled headers themselves, which are
|
||||
suppressed by default, see the :prop_tgt:`PCH_WARNINGS` target property.
|
||||
|
||||
* :command:`target_compile_definitions`
|
||||
* :command:`target_compile_features`
|
||||
* :command:`target_compile_options`
|
||||
|
||||
@@ -428,6 +428,7 @@ Properties on Targets
|
||||
/prop_tgt/OUTPUT_NAME
|
||||
/prop_tgt/OUTPUT_NAME_CONFIG
|
||||
/prop_tgt/PCH_INSTANTIATE_TEMPLATES
|
||||
/prop_tgt/PCH_WARNINGS
|
||||
/prop_tgt/PCH_WARN_INVALID
|
||||
/prop_tgt/PDB_NAME
|
||||
/prop_tgt/PDB_NAME_CONFIG
|
||||
|
||||
@@ -572,6 +572,7 @@ Variables that Control the Build
|
||||
/variable/CMAKE_OSX_DEPLOYMENT_TARGET
|
||||
/variable/CMAKE_OSX_SYSROOT
|
||||
/variable/CMAKE_PCH_INSTANTIATE_TEMPLATES
|
||||
/variable/CMAKE_PCH_WARNINGS
|
||||
/variable/CMAKE_PCH_WARN_INVALID
|
||||
/variable/CMAKE_PDB_OUTPUT_DIRECTORY
|
||||
/variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
PCH_WARNINGS
|
||||
------------
|
||||
|
||||
.. versionadded:: 4.6
|
||||
|
||||
Enable compiler warnings for the headers listed in :prop_tgt:`PRECOMPILE_HEADERS`.
|
||||
|
||||
By default CMake marks the generated precompiled header file as a system
|
||||
header, which suppresses the diagnostics of every header it includes. This
|
||||
means that enabling precompiled headers silently hides warnings that the same
|
||||
build would produce without them.
|
||||
|
||||
Set this property to true to omit the system header marker so that the headers
|
||||
collected into the precompiled header are diagnosed as they would be in a
|
||||
build without precompiled headers. The diagnostics are reported once, while
|
||||
compiling the precompiled header itself, rather than once per source file.
|
||||
|
||||
This property is initialized by the value of the :variable:`CMAKE_PCH_WARNINGS`
|
||||
variable when the target is created.
|
||||
|
||||
The :generator:`Xcode` generator never adds the system header marker, so this
|
||||
property has no effect there.
|
||||
|
||||
Targets that reuse a precompiled header through
|
||||
:prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` do not generate a precompiled header
|
||||
of their own, so this property has no effect on them either. Set it on the
|
||||
target named by :prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` instead.
|
||||
@@ -0,0 +1,15 @@
|
||||
pch-warnings
|
||||
------------
|
||||
|
||||
* The :prop_tgt:`PCH_WARNINGS` target property, and its initializing
|
||||
:variable:`CMAKE_PCH_WARNINGS` variable, were added to enable compiler
|
||||
warnings for the headers collected into a precompiled header. Previously
|
||||
the generated precompiled header was always marked as a system header,
|
||||
which suppressed those warnings.
|
||||
|
||||
The system header marker now comes from an internal
|
||||
``CMAKE_PCH_SYSTEM_HEADER_PRAGMA`` variable instead of from
|
||||
``CMAKE_PCH_PROLOGUE``. Projects that cleared or replaced
|
||||
``CMAKE_PCH_PROLOGUE`` in order to drop the marker no longer affect it,
|
||||
and must set :prop_tgt:`PCH_WARNINGS` or :variable:`CMAKE_PCH_WARNINGS`
|
||||
instead.
|
||||
@@ -0,0 +1,7 @@
|
||||
CMAKE_PCH_WARNINGS
|
||||
------------------
|
||||
|
||||
.. versionadded:: 4.6
|
||||
|
||||
This variable is used to initialize the :prop_tgt:`PCH_WARNINGS`
|
||||
property of targets when they are created.
|
||||
@@ -109,7 +109,7 @@ else()
|
||||
|
||||
set(CMAKE_PCH_EXTENSION .pch)
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Xcode")
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma clang system_header")
|
||||
endif()
|
||||
if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0.0 AND NOT __is_apple_clang)
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH -fpch-instantiate-templates)
|
||||
|
||||
@@ -142,7 +142,7 @@ macro(__compiler_gnu lang)
|
||||
if(NOT "x${lang}" STREQUAL "xFortran")
|
||||
set(CMAKE_PCH_EXTENSION .gch)
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Xcode")
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma GCC system_header")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma GCC system_header")
|
||||
endif()
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -include <PCH_HEADER>)
|
||||
|
||||
@@ -115,7 +115,9 @@ else()
|
||||
else()
|
||||
# Precompile Headers
|
||||
set(CMAKE_PCH_EXTENSION .pch)
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Xcode")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma clang system_header")
|
||||
endif()
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_INSTANTIATE_TEMPLATES_PCH -fpch-instantiate-templates)
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
|
||||
|
||||
@@ -91,7 +91,7 @@ macro(__compiler_lcc lang)
|
||||
if(NOT "x${lang}" STREQUAL "xFortran")
|
||||
set(CMAKE_PCH_EXTENSION .gch)
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Xcode")
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma GCC system_header")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma GCC system_header")
|
||||
endif()
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -include <PCH_HEADER>)
|
||||
|
||||
@@ -143,7 +143,7 @@ macro(__windows_compiler_clang_gnu lang)
|
||||
set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON)
|
||||
|
||||
set(CMAKE_PCH_EXTENSION .pch)
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma clang system_header")
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
|
||||
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER> -x ${__pch_header_${lang}})
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ macro(__windows_compiler_msvc lang)
|
||||
set(CMAKE_PCH_EXTENSION .pch)
|
||||
set(CMAKE_LINK_PCH ON)
|
||||
if (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma clang system_header")
|
||||
|
||||
# macOS paths usually start with /Users/*. Unfortunately, clang-cl interprets
|
||||
# paths starting with /U as macro undefines, so we need to put a -- before the
|
||||
@@ -458,7 +458,7 @@ macro(__windows_compiler_msvc lang)
|
||||
endif()
|
||||
elseif(MSVC_VERSION GREATER_EQUAL 1913)
|
||||
# At least MSVC toolet 14.13 from VS 2017 15.6
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma system_header")
|
||||
set(CMAKE_PCH_SYSTEM_HEADER_PRAGMA "#pragma system_header")
|
||||
endif()
|
||||
if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang")
|
||||
set(CMAKE_PCH_COPY_COMPILE_PDB ON)
|
||||
|
||||
@@ -497,6 +497,8 @@ Entry const kEntries[] = {
|
||||
"Location or short name (e.g. macosx) of the macOS platform SDK passed to the compiler via -isysroot. Initialized from the SDKROOT environment variable; empty by default."_s },
|
||||
{ "CMAKE_PCH_INSTANTIATE_TEMPLATES"_s,
|
||||
"Initializes the PCH_INSTANTIATE_TEMPLATES target property"_s },
|
||||
{ "CMAKE_PCH_WARNINGS"_s,
|
||||
"Initializes the PCH_WARNINGS target property"_s },
|
||||
{ "CMAKE_PCH_WARN_INVALID"_s,
|
||||
"Initializes the PCH_WARN_INVALID target property"_s },
|
||||
{ "CMAKE_PDB_OUTPUT_DIRECTORY"_s,
|
||||
|
||||
@@ -3359,6 +3359,12 @@ std::string cmGeneratorTarget::GetPchHeader(std::string const& config,
|
||||
|
||||
std::string const filename_tmp = cmStrCat(filename, ".tmp");
|
||||
if (!haveReuseTarget) {
|
||||
// Marking the generated header as a system header suppresses the
|
||||
// diagnostics of every header it includes. Skip it when the target
|
||||
// asks for warnings from its precompiled headers.
|
||||
cmValue pchSystemHeaderPragma = this->GetPropertyAsBool("PCH_WARNINGS")
|
||||
? nullptr
|
||||
: this->Makefile->GetDefinition("CMAKE_PCH_SYSTEM_HEADER_PRAGMA");
|
||||
cmValue pchPrologue =
|
||||
this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
|
||||
cmValue pchEpilogue =
|
||||
@@ -3370,6 +3376,9 @@ std::string cmGeneratorTarget::GetPchHeader(std::string const& config,
|
||||
filename_tmp, false,
|
||||
this->GetGlobalGenerator()->GetMakefileEncoding());
|
||||
file << "/* generated by CMake */\n\n";
|
||||
if (pchSystemHeaderPragma) {
|
||||
file << *pchSystemHeaderPragma << "\n";
|
||||
}
|
||||
if (pchPrologue) {
|
||||
file << *pchPrologue << "\n";
|
||||
}
|
||||
@@ -3405,7 +3414,12 @@ std::string cmGeneratorTarget::GetPchHeader(std::string const& config,
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstHeaderOnDisk.empty()) {
|
||||
// Give the generated header the timestamp of a header from the project
|
||||
// to help ccache. Do this only when creating it for the first time:
|
||||
// if its content later changes, e.g. because PCH_WARNINGS was toggled,
|
||||
// an older timestamp would make build systems consider the already
|
||||
// precompiled header up to date.
|
||||
if (!firstHeaderOnDisk.empty() && !cmSystemTools::FileExists(filename)) {
|
||||
cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
|
||||
}
|
||||
|
||||
|
||||
@@ -339,6 +339,7 @@ TargetProperty const StaticTargetProperties[] = {
|
||||
{ "DISABLE_PRECOMPILE_HEADERS"_s, IC::CanCompileSources },
|
||||
{ "PCH_WARN_INVALID"_s, "ON"_s, IC::CanCompileSources },
|
||||
{ "PCH_INSTANTIATE_TEMPLATES"_s, "ON"_s, IC::CanCompileSources },
|
||||
{ "PCH_WARNINGS"_s, IC::CanCompileSources },
|
||||
// -- Platforms
|
||||
// ---- Android
|
||||
{ "ANDROID_API"_s, IC::CanCompileSources },
|
||||
|
||||
@@ -1666,7 +1666,8 @@ add_RunCMake_test("CTestCommandExpandLists")
|
||||
|
||||
add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
|
||||
-DCMAKE_C_SIMULATE_ID=${CMAKE_C_SIMULATE_ID}
|
||||
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
|
||||
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
|
||||
-DMSVC_VERSION=${MSVC_VERSION})
|
||||
add_RunCMake_test(PrecompileHeaders-Reuse -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
|
||||
|
||||
# This test can take a long time due to the number of test cases.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
if (RunCMake_GENERATOR STREQUAL "Xcode" OR
|
||||
NOT CMAKE_C_COMPILER_ID MATCHES "^(GNU|LCC|Clang|AppleClang|IntelLLVM|MSVC)$")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# MSVC defines the system header pragma only for toolset 14.13 from VS 2017 15.6.
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION LESS 1913)
|
||||
return()
|
||||
endif()
|
||||
|
||||
function(check_system_header_pragma target expected)
|
||||
set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/${target}.dir/cmake_pch.h")
|
||||
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/${target}.dir/Debug/cmake_pch.h")
|
||||
endif()
|
||||
|
||||
if (NOT EXISTS "${pch_header}")
|
||||
set(RunCMake_TEST_FAILED
|
||||
"Generated pch file for '${target}'\n ${pch_header}\ndoes not exist"
|
||||
PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(STRINGS "${pch_header}" pch_header_strings REGEX "system_header")
|
||||
if (expected AND NOT pch_header_strings)
|
||||
set(RunCMake_TEST_FAILED
|
||||
"Generated pch file for '${target}' is missing the system header pragma"
|
||||
PARENT_SCOPE)
|
||||
elseif (NOT expected AND pch_header_strings)
|
||||
set(RunCMake_TEST_FAILED
|
||||
"Generated pch file for '${target}' has an unexpected system header pragma"
|
||||
PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
check_system_header_pragma(empty ON)
|
||||
if (RunCMake_TEST_FAILED)
|
||||
return()
|
||||
endif()
|
||||
check_system_header_pragma(foo OFF)
|
||||
@@ -0,0 +1,16 @@
|
||||
set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_library(empty empty.c)
|
||||
target_precompile_headers(empty PUBLIC
|
||||
<stdio.h>
|
||||
<string.h>
|
||||
)
|
||||
|
||||
add_library(foo foo.c)
|
||||
target_precompile_headers(foo PUBLIC
|
||||
<stdio.h>
|
||||
<string.h>
|
||||
)
|
||||
set_target_properties(foo PROPERTIES PCH_WARNINGS ON)
|
||||
@@ -24,6 +24,7 @@ if (RunCMake_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
|
||||
endif ()
|
||||
run_test(PchInterfaceUnity)
|
||||
run_cmake(PchPrologueEpilogue)
|
||||
run_cmake(PchWarnings)
|
||||
run_test(SkipPrecompileHeaders)
|
||||
run_test(CXXnotC)
|
||||
run_cmake(PchMultilanguage)
|
||||
|
||||
@@ -12,6 +12,7 @@ set(properties
|
||||
"DISABLE_PRECOMPILE_HEADERS" "ON" "<SAME>"
|
||||
"PCH_WARN_INVALID" "OFF" "<SAME>"
|
||||
"PCH_INSTANTIATE_TEMPLATES" "OFF" "<SAME>"
|
||||
"PCH_WARNINGS" "ON" "<SAME>"
|
||||
## Platforms
|
||||
### Android
|
||||
"ANDROID_API" "9" "<SAME>"
|
||||
|
||||
Reference in new issue
Block a user