From b61637f90fcef017643db0698f091cae0e61a5d0 Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Mon, 5 Jan 2026 19:30:02 +1100 Subject: [PATCH] File sets: Add verification of private file sets Add support for PRIVATE header sets, analogous to the existing INTERFACE header sets support. A key difference between the two is the way they handle build and usage requirements. INTERFACE header sets rely on the original target's INTERFACE, whereas PRIVATE header sets copy across various properties from the original target. Generated files need special handling for PRIVATE header sets. Add a dependency on the original target to the verification target to ensure such generated files will exist. Fixes: #23448 --- Help/manual/cmake-properties.7.rst | 2 + Help/manual/cmake-variables.7.rst | 1 + .../INTERFACE_HEADER_SETS_TO_VERIFY.rst | 12 +- .../PRIVATE_HEADER_SETS_TO_VERIFY.rst | 15 + .../prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst | 35 +- Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst | 34 ++ .../include/VERIFY_XXX_HEADER_SETS.rst | 34 ++ .../dev/verify-private-header-sets.rst | 7 + .../CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst | 39 +- .../CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst | 10 + .../include/CMAKE_VERIFY_XXX_HEADER_SETS.rst | 39 ++ Modules/FetchContent.cmake | 41 ++- Source/cmGeneratorTarget.cxx | 333 +++++++++++------- Source/cmGlobalGenerator.cxx | 31 +- Source/cmTarget.cxx | 1 + .../FetchContent/VerifyHeaderSet-stdout.txt | 10 +- .../FetchContent/VerifyHeaderSet.cmake | 13 +- .../VerifyHeaderSet/CMakeLists.txt | 5 +- ...rivate_header_sets-Debug-build-check.cmake | 10 + .../AllVerifyPrivateHeaderSets.cmake | 4 + .../VerifyHeaderSets/RunCMakeTest.cmake | 44 +++ ...ivateHeaderSets-a_h-Debug-build-result.txt | 1 + ...ivateHeaderSets-a_h-Debug-build-stderr.txt | 1 + ...ivateHeaderSets-a_h-Debug-build-stdout.txt | 1 + ...teHeaderSets-config-Debug-build-result.txt | 1 + ...teHeaderSets-config-Debug-build-stderr.txt | 1 + ...teHeaderSets-config-Debug-build-stdout.txt | 1 + ...HeaderSets-config-Release-build-result.txt | 1 + ...HeaderSets-config-Release-build-stderr.txt | 1 + ...HeaderSets-config-Release-build-stdout.txt | 1 + ...eHeaderSets-dir_c_h-Debug-build-result.txt | 1 + ...eHeaderSets-dir_c_h-Debug-build-stderr.txt | 1 + ...eHeaderSets-dir_c_h-Debug-build-stdout.txt | 1 + ...eaderSets-dir_cxx_h-Debug-build-result.txt | 1 + ...eaderSets-dir_cxx_h-Debug-build-stderr.txt | 1 + ...eaderSets-dir_cxx_h-Debug-build-stdout.txt | 1 + ...Sets-iface_lang_cxx-Debug-build-result.txt | 1 + ...Sets-iface_lang_cxx-Debug-build-stderr.txt | 1 + ...eaderSets-interface-Debug-build-result.txt | 1 + ...eaderSets-interface-Debug-build-stderr.txt | 1 + ...vateHeaderSets-none-Debug-build-result.txt | 1 + ...vateHeaderSets-none-Debug-build-stderr.txt | 1 + ...erSets-property_off-Debug-build-result.txt | 1 + ...erSets-property_off-Debug-build-stderr.txt | 1 + .../VerifyPrivateHeaderSets.cmake | 88 +++++ ...ifyPrivateHeaderSetsNonexistent-result.txt | 1 + ...ifyPrivateHeaderSetsNonexistent-stderr.txt | 9 + .../VerifyPrivateHeaderSetsNonexistent.cmake | 5 + .../VerifyHeaderSets/dir3/CMakeLists.txt | 3 + Tests/RunCMake/VerifyHeaderSets/dir3/lib3.h | 5 + .../VerifyHeaderSets/dir4/CMakeLists.txt | 3 + Tests/RunCMake/VerifyHeaderSets/dir4/lib4.h | 5 + Tests/RunCMake/property_init/Always.cmake | 1 + 53 files changed, 642 insertions(+), 221 deletions(-) create mode 100644 Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst create mode 100644 Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst create mode 100644 Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst create mode 100644 Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst create mode 100644 Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst create mode 100644 Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets-all_verify_private_header_sets-Debug-build-check.cmake create mode 100644 Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets.cmake create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stdout.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stdout.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stdout.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stdout.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stdout.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-result.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-stderr.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent.cmake create mode 100644 Tests/RunCMake/VerifyHeaderSets/dir3/CMakeLists.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/dir3/lib3.h create mode 100644 Tests/RunCMake/VerifyHeaderSets/dir4/CMakeLists.txt create mode 100644 Tests/RunCMake/VerifyHeaderSets/dir4/lib4.h diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 5de9ccf157..b4ebb1049a 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -392,6 +392,7 @@ Properties on Targets /prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM /prop_tgt/PREFIX /prop_tgt/PRIVATE_HEADER + /prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY /prop_tgt/PROJECT_LABEL /prop_tgt/PUBLIC_HEADER /prop_tgt/RESOURCE @@ -432,6 +433,7 @@ Properties on Targets /prop_tgt/UNITY_BUILD_RELOCATABLE /prop_tgt/UNITY_BUILD_UNIQUE_ID /prop_tgt/VERIFY_INTERFACE_HEADER_SETS + /prop_tgt/VERIFY_PRIVATE_HEADER_SETS /prop_tgt/VERSION /prop_tgt/VISIBILITY_INLINES_HIDDEN /prop_tgt/VS_CONFIGURATION_TYPE diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index fc22d57cb4..4759f333b3 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -598,6 +598,7 @@ Variables that Control the Build /variable/CMAKE_UNITY_BUILD_RELOCATABLE /variable/CMAKE_UNITY_BUILD_UNIQUE_ID /variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS + /variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS /variable/CMAKE_VISIBILITY_INLINES_HIDDEN /variable/CMAKE_VS_DEBUGGER_COMMAND /variable/CMAKE_VS_DEBUGGER_COMMAND_ARGUMENTS diff --git a/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst b/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst index b0d63f3cd6..7eb6ec3e8f 100644 --- a/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst +++ b/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst @@ -4,10 +4,12 @@ INTERFACE_HEADER_SETS_TO_VERIFY .. versionadded:: 3.24 Used to specify which ``PUBLIC`` and ``INTERFACE`` header sets of a target -should be verified. +should be verified as interface headers. This property contains a semicolon-separated list of header sets which -should be verified if :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to -``TRUE``. If the list is empty, all ``PUBLIC`` and ``INTERFACE`` header sets -are verified. (If the project does not want to verify any header sets on the -target, simply set :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` to ``FALSE``.) +should be verified if :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to true. +If the list is empty, all ``PUBLIC`` and ``INTERFACE`` header sets are +verified. If the project does not want to verify any interface header sets on +the target, set :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` to false. + +See also :prop_tgt:`PRIVATE_HEADER_SETS_TO_VERIFY`. diff --git a/Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst b/Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst new file mode 100644 index 0000000000..e7ad64207b --- /dev/null +++ b/Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst @@ -0,0 +1,15 @@ +PRIVATE_HEADER_SETS_TO_VERIFY +----------------------------- + +.. versionadded:: 4.3 + +Used to specify which ``PUBLIC`` and ``PRIVATE`` header sets of a target +should be verified as private headers. + +This property contains a semicolon-separated list of header sets which +should be verified if :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` is set to true. +If the list is empty, all ``PUBLIC`` and ``PRIVATE`` header sets are verified. +If the project does not want to verify any private header sets on the target, +set :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` to false. + +See also :prop_tgt:`INTERFACE_HEADER_SETS_TO_VERIFY`. diff --git a/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst b/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst index 78492a30ab..a14f7c8f23 100644 --- a/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst +++ b/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst @@ -14,30 +14,13 @@ header sets, an object library target named target has one source file per header in the ``PUBLIC`` and ``INTERFACE`` header sets. Each source file only includes its associated header file. The verification target links against the original target to get all of its -usage requirements. The verification target has its -:prop_tgt:`EXCLUDE_FROM_ALL` and :prop_tgt:`DISABLE_PRECOMPILE_HEADERS` -properties set to true, and its :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC`, -:prop_tgt:`AUTOUIC`, :prop_tgt:`UNITY_BUILD`, and -:prop_tgt:`CXX_SCAN_FOR_MODULES` properties set to false. +usage requirements. -If the header's :prop_sf:`LANGUAGE` property is set, the value of that property -is used to determine the language with which to compile the header file. -Otherwise, if the target has any C++ sources, the header is compiled as C++. -Otherwise, if the target has any C sources, the header is compiled as C. -Otherwise, if C++ is enabled globally, the header is compiled as C++. -Otherwise, if C is enabled globally, the header is compiled as C. Otherwise, -the header file is not compiled. - -If the header's :prop_sf:`SKIP_LINTING` property is set to true, the file is -not compiled. - -If any verification targets are created, a top-level target called -``all_verify_interface_header_sets`` is created which depends on all -verification targets. - -This property is initialized by the value of the -:variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` variable if it is set when -a target is created. - -If the project wishes to control which header sets are verified by this -property, it can set :prop_tgt:`INTERFACE_HEADER_SETS_TO_VERIFY`. +.. |xxx| replace:: interface +.. |THIS_PROPERTY| replace:: ``VERIFY_INTERFACE_HEADER_SETS`` +.. |COMPLEMENTARY_PROPERTY| replace:: :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` +.. |THIS_ALL_TARGET| replace:: ``all_verify_interface_header_sets`` +.. |COMPLEMENTARY_ALL_TARGET| replace:: ``all_verify_private_header_sets`` +.. |INIT_VARIABLE| replace:: :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` +.. |SETS_TO_VERIFY_PROPERTY| replace:: :prop_tgt:`INTERFACE_HEADER_SETS_TO_VERIFY` +.. include:: include/VERIFY_XXX_HEADER_SETS.rst diff --git a/Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst b/Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst new file mode 100644 index 0000000000..df9d18384d --- /dev/null +++ b/Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst @@ -0,0 +1,34 @@ +VERIFY_PRIVATE_HEADER_SETS +-------------------------- + +.. versionadded:: 4.3 + +Used to verify that all headers in a target's ``PUBLIC`` and ``PRIVATE`` +header sets can be included on their own. + +When this property is set to true, and the target is an object library, static +library, shared library, module library, interface library, or executable, and +the target has one or more ``PUBLIC`` or ``PRIVATE`` header sets, an object +library target named ``_verify_private_header_sets`` is created. +This verification target has one source file per header in the ``PUBLIC`` and +``PRIVATE`` header sets. Each source file only includes its associated header +file. + +Properties affecting compilation are copied from the original target to the +verification target so that the headers will be interpreted the same way by +the compiler as when compiling the original target's sources. There are some +caveats with this approach. It cannot replicate the same conditions if any +of those properties or properties inherited through build requirements from +transitive dependencies contain +:ref:`target-dependent generator expressions ` +that do not specify the target for the expansion. Such expressions can expand +to different contents depending on the target they are being used on. + +.. |xxx| replace:: private +.. |THIS_PROPERTY| replace:: ``VERIFY_PRIVATE_HEADER_SETS`` +.. |COMPLEMENTARY_PROPERTY| replace:: :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` +.. |THIS_ALL_TARGET| replace:: ``all_verify_private_header_sets`` +.. |COMPLEMENTARY_ALL_TARGET| replace:: ``all_verify_interface_header_sets`` +.. |INIT_VARIABLE| replace:: :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` +.. |SETS_TO_VERIFY_PROPERTY| replace:: :prop_tgt:`PRIVATE_HEADER_SETS_TO_VERIFY` +.. include:: include/VERIFY_XXX_HEADER_SETS.rst diff --git a/Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst b/Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst new file mode 100644 index 0000000000..f1902136bd --- /dev/null +++ b/Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst @@ -0,0 +1,34 @@ +The verification target has its +:prop_tgt:`EXCLUDE_FROM_ALL` and :prop_tgt:`DISABLE_PRECOMPILE_HEADERS` +properties set to true, and its :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC`, +:prop_tgt:`AUTOUIC`, :prop_tgt:`UNITY_BUILD`, and +:prop_tgt:`CXX_SCAN_FOR_MODULES` properties set to false. + +If the header's :prop_sf:`LANGUAGE` property is set, the value of that property +is used to determine the language with which to compile the header file. +Otherwise, if the target has any C++ sources, the header is compiled as C++. +Otherwise, if the target has any C sources, the header is compiled as C. +Otherwise, if C++ is enabled globally, the header is compiled as C++. +Otherwise, if C is enabled globally, the header is compiled as C. Otherwise, +the header file is not compiled. + +If the header's :prop_sf:`SKIP_LINTING` property is set to true, the file is +not compiled. + +If |THIS_PROPERTY| and |COMPLEMENTARY_PROPERTY| are both set to true, headers +belonging to ``PUBLIC`` file sets will be verified twice, but with different +conditions. The compiler flags used for private and interface contexts can be +different, leading to the compiler interpreting the contents of the header +differently. + +If any |xxx| file set verification targets are created, a top-level target +called |THIS_ALL_TARGET| is created which depends on all |xxx| verification +targets. Another target called ``all_verify_header_sets`` is also created +which depends on |THIS_ALL_TARGET|, and on |COMPLEMENTARY_ALL_TARGET| if it +exists (see |COMPLEMENTARY_PROPERTY|). + +This property is initialized by the value of the |INIT_VARIABLE| variable if +it is set when a target is created. + +If the project wishes to control which header sets are verified by this +property, it can set |SETS_TO_VERIFY_PROPERTY|. diff --git a/Help/release/dev/verify-private-header-sets.rst b/Help/release/dev/verify-private-header-sets.rst index 32f250edc1..40cee31601 100644 --- a/Help/release/dev/verify-private-header-sets.rst +++ b/Help/release/dev/verify-private-header-sets.rst @@ -4,3 +4,10 @@ verify-private-header-sets * When :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to true on an executable target, that target's interface file sets are verified regardless of its :prop_tgt:`ENABLE_EXPORTS` property. See policy :policy:`CMP0209`. +* The :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` variable and corresponding + :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` target property were added to + enable build rules that verify all headers in private file sets can be used + on their own. +* The :prop_tgt:`PRIVATE_HEADER_SETS_TO_VERIFY` target property was added to + customize which private file sets to verify when the target's + :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` property is true. diff --git a/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst b/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst index 3fb8817f4e..f0302ba7d8 100644 --- a/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst +++ b/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst @@ -3,37 +3,8 @@ CMAKE_VERIFY_INTERFACE_HEADER_SETS .. versionadded:: 3.24 -This variable is used to initialize the -:prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` property of targets when they are -created. Setting it to true enables header set verification. - -Projects should not normally set this variable, it is intended as a developer -control to be set on the :manual:`cmake(1)` command line or other -equivalent methods. The developer must have the ability to enable or -disable header set verification according to the capabilities of their own -machine and compiler. - -Verification of a dependency's header sets is not typically of interest -to developers. Therefore, :command:`FetchContent_MakeAvailable` explicitly -sets ``CMAKE_VERIFY_INTERFACE_HEADER_SETS`` to false for the duration of its -call, but restores its original value before returning. If a project brings -a dependency directly into the main build (e.g. calling -:command:`add_subdirectory` on a vendored project from a git submodule), it -should also do likewise. For example: - -.. code:: cmake - - # Save original setting so we can restore it later - set(want_header_set_verification ${CMAKE_VERIFY_INTERFACE_HEADER_SETS}) - - # Include the vendored dependency with header set verification disabled - set(CMAKE_VERIFY_INTERFACE_HEADER_SETS OFF) - add_subdirectory(...) # Vendored sources, e.g. from git submodules - - # Add the project's own sources. Restore the developer's original choice - # for whether to enable header set verification. - set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${want_header_set_verification}) - add_subdirectory(src) - -By default, this variable is not set, which will result in header set -verification being disabled. +.. |VERIFY_XXX_HEADER_SETS| replace:: :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` +.. |CMAKE_VERIFY_XXX_HEADER_SETS| replace:: ``CMAKE_VERIFY_INTERFACE_HEADER_SETS`` +.. |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS| replace:: :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` +.. |xxx| replace:: interface +.. include:: include/CMAKE_VERIFY_XXX_HEADER_SETS.rst diff --git a/Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst b/Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst new file mode 100644 index 0000000000..3dd15fa03e --- /dev/null +++ b/Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst @@ -0,0 +1,10 @@ +CMAKE_VERIFY_PRIVATE_HEADER_SETS +-------------------------------- + +.. versionadded:: 4.3 + +.. |VERIFY_XXX_HEADER_SETS| replace:: :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` +.. |CMAKE_VERIFY_XXX_HEADER_SETS| replace:: ``CMAKE_VERIFY_PRIVATE_HEADER_SETS`` +.. |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS| replace:: :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` +.. |xxx| replace:: private +.. include:: include/CMAKE_VERIFY_XXX_HEADER_SETS.rst diff --git a/Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst b/Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst new file mode 100644 index 0000000000..9a274d3e8e --- /dev/null +++ b/Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst @@ -0,0 +1,39 @@ +This variable is used to initialize the |VERIFY_XXX_HEADER_SETS| property of +targets when they are created. Setting it to true enables |xxx| header set +verification. + +Projects should not normally set this variable, it is intended as a developer +control to be set on the :manual:`cmake(1)` command line or other +equivalent methods. The developer must have the ability to enable or +disable header set verification according to the capabilities of their own +machine and compiler. + +Verification of a dependency's header sets is not typically of interest to +developers. Therefore, :command:`FetchContent_MakeAvailable` explicitly sets +|CMAKE_VERIFY_XXX_HEADER_SETS| and |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS| +to false for the duration of its call, but restores their original values +before returning. If a project brings a dependency directly into the main +build (e.g. calling :command:`add_subdirectory` on a vendored project from a +git submodule), it should also do likewise. For example: + +.. code:: cmake + + # Save original setting so we can restore it later + set(want_interface_header_set_verification ${CMAKE_VERIFY_INTERFACE_HEADER_SETS}) + set(want_private_header_set_verification ${CMAKE_VERIFY_PRIVATE_HEADER_SETS}) + + # Include the vendored dependency with header set verification disabled + set(CMAKE_VERIFY_INTERFACE_HEADER_SETS OFF) + set(CMAKE_VERIFY_PRIVATE_HEADER_SETS OFF) + add_subdirectory(...) # Vendored sources, e.g. from git submodules + + # Add the project's own sources. Restore the developer's original choice + # for whether to enable header set verification. + set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${want_interface_header_set_verification}) + set(CMAKE_VERIFY_PRIVATE_HEADER_SETS ${want_private_header_set_verification}) + add_subdirectory(src) + +By default, this variable is not set, which will result in |xxx| header set +verification being disabled. + +See also |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS|. diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake index 4c1068ee82..80152f61c9 100644 --- a/Modules/FetchContent.cmake +++ b/Modules/FetchContent.cmake @@ -397,17 +397,20 @@ Commands FetchContent_Declare(other ...) FetchContent_MakeAvailable(uses_other other) - Note that :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` is explicitly set - to false upon entry to ``FetchContent_MakeAvailable()``, and is restored to - its original value before the command returns. Developers typically only + Note that :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` and + :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` are explicitly set to false + upon entry to ``FetchContent_MakeAvailable()``, and are restored to their + original values before the command returns. Developers typically only want to verify header sets from the main project, not those from any dependencies. This local manipulation of the - :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` variable provides that + :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` and + :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` variables provides that intuitive behavior. You can use variables like :variable:`CMAKE_PROJECT_INCLUDE` or :variable:`CMAKE_PROJECT__INCLUDE` to turn verification back on for all or some dependencies. You can also set the - :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` property of individual targets. + :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` and + :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` properties of individual targets. .. command:: FetchContent_Populate @@ -2240,12 +2243,14 @@ endfunction() # calls will be available to the caller. macro(FetchContent_MakeAvailable) - # We must append an item, even if the variable is unset, so prefix its value. - # We will strip that prefix when we pop the value at the end of the macro. + # We must append these, even if the variables are unset, so prefix the values. + # We will strip that prefix when we pop the values at the end of the macro. list(APPEND __cmake_fcCurrentVarsStack "__fcprefix__${CMAKE_VERIFY_INTERFACE_HEADER_SETS}" + "__fcprefix__${CMAKE_VERIFY_PRIVATE_HEADER_SETS}" ) set(CMAKE_VERIFY_INTERFACE_HEADER_SETS FALSE) + set(CMAKE_VERIFY_PRIVATE_HEADER_SETS FALSE) get_property(__cmake_providerCommand GLOBAL PROPERTY __FETCHCONTENT_MAKEAVAILABLE_SERIAL_PROVIDER @@ -2453,18 +2458,30 @@ macro(FetchContent_MakeAvailable) endforeach() # Prefix will be "__fcprefix__" - list(POP_BACK __cmake_fcCurrentVarsStack __cmake_original_verify_setting) - string(SUBSTRING "${__cmake_original_verify_setting}" - 12 -1 __cmake_original_verify_setting + list(POP_BACK __cmake_fcCurrentVarsStack + __cmake_original_verify_private_setting + __cmake_original_verify_interface_setting + ) + string(SUBSTRING "${__cmake_original_verify_private_setting}" + 12 -1 __cmake_original_verify_private_setting + ) + string(SUBSTRING "${__cmake_original_verify_interface_setting}" + 12 -1 __cmake_original_verify_interface_setting + ) + set(CMAKE_VERIFY_PRIVATE_HEADER_SETS + ${__cmake_original_verify_private_setting} + ) + set(CMAKE_VERIFY_INTERFACE_HEADER_SETS + ${__cmake_original_verify_interface_setting} ) - set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${__cmake_original_verify_setting}) # clear local variables to prevent leaking into the caller's scope unset(__cmake_contentName) unset(__cmake_contentNameLower) unset(__cmake_contentNameUpper) unset(__cmake_providerCommand) - unset(__cmake_original_verify_setting) + unset(__cmake_original_verify_interface_setting) + unset(__cmake_original_verify_private_setting) endmacro() diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 4bc1e107f7..6d70395e9b 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -5703,166 +5704,236 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( bool cmGeneratorTarget::AddHeaderSetVerification() { - if (!this->GetPropertyAsBool("VERIFY_INTERFACE_HEADER_SETS")) { - return true; - } + for (bool const isInterface : { false, true }) { + if (!this->GetPropertyAsBool(isInterface ? "VERIFY_INTERFACE_HEADER_SETS" + : "VERIFY_PRIVATE_HEADER_SETS")) { + continue; + } - if (this->GetType() != cmStateEnums::STATIC_LIBRARY && - this->GetType() != cmStateEnums::SHARED_LIBRARY && - this->GetType() != cmStateEnums::UNKNOWN_LIBRARY && - this->GetType() != cmStateEnums::OBJECT_LIBRARY && - this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetType() != cmStateEnums::EXECUTABLE) { - return true; - } + if (this->GetType() != cmStateEnums::STATIC_LIBRARY && + this->GetType() != cmStateEnums::SHARED_LIBRARY && + (this->GetType() != cmStateEnums::MODULE_LIBRARY || isInterface) && + this->GetType() != cmStateEnums::UNKNOWN_LIBRARY && + this->GetType() != cmStateEnums::OBJECT_LIBRARY && + this->GetType() != cmStateEnums::INTERFACE_LIBRARY && + this->GetType() != cmStateEnums::EXECUTABLE) { + continue; + } - auto verifyValue = this->GetProperty("INTERFACE_HEADER_SETS_TO_VERIFY"); - bool const all = verifyValue.IsEmpty(); - std::set verifySet; - if (!all) { - cmList verifyList{ verifyValue }; - verifySet.insert(verifyList.begin(), verifyList.end()); - } + char const* headerSetsProperty = isInterface + ? "INTERFACE_HEADER_SETS_TO_VERIFY" + : "PRIVATE_HEADER_SETS_TO_VERIFY"; - cmTarget* verifyTarget = nullptr; - std::string const verifyTargetName = - cmStrCat(this->GetName(), "_verify_interface_header_sets"); + auto verifyValue = this->GetProperty(headerSetsProperty); + bool const all = verifyValue.IsEmpty(); + std::set verifySet; + if (!all) { + cmList verifyList{ verifyValue }; + verifySet.insert(verifyList.begin(), verifyList.end()); + } - char const* allVerifyTargetName = "all_verify_interface_header_sets"; - cmTarget* allVerifyTarget = - this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse( - allVerifyTargetName, { cmStateEnums::TargetDomain::NATIVE }); + cmTarget* verifyTarget = nullptr; + std::string const verifyTargetName = + cmStrCat(this->GetName(), + isInterface ? "_verify_interface_header_sets" + : "_verify_private_header_sets"); - auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries(); + char const* allVerifyTargetName = isInterface + ? "all_verify_interface_header_sets" + : "all_verify_private_header_sets"; + cmTarget* allVerifyTarget = + this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse( + allVerifyTargetName, { cmStateEnums::TargetDomain::NATIVE }); - std::set fileSets; - for (auto const& entry : interfaceFileSetEntries) { - for (auto const& name : cmList{ entry.Value }) { - if (all || verifySet.count(name)) { - fileSets.insert(this->Target->GetFileSet(name)); - verifySet.erase(name); + auto fileSetEntries = isInterface + ? this->Target->GetInterfaceHeaderSetsEntries() + : this->Target->GetHeaderSetsEntries(); + + std::set fileSets; + for (auto const& entry : fileSetEntries) { + for (auto const& name : cmList{ entry.Value }) { + if (all || verifySet.count(name)) { + fileSets.insert(this->Target->GetFileSet(name)); + verifySet.erase(name); + } } } - } - cmPolicies::PolicyStatus const cmp0209 = this->GetPolicyStatusCMP0209(); - if (cmp0209 != cmPolicies::NEW && - this->GetType() == cmStateEnums::EXECUTABLE && - !this->GetPropertyAsBool("ENABLE_EXPORTS")) { - if (cmp0209 == cmPolicies::WARN && !fileSets.empty()) { + if (isInterface) { + cmPolicies::PolicyStatus const cmp0209 = this->GetPolicyStatusCMP0209(); + if (cmp0209 != cmPolicies::NEW && + this->GetType() == cmStateEnums::EXECUTABLE && + !this->GetPropertyAsBool("ENABLE_EXPORTS")) { + if (cmp0209 == cmPolicies::WARN && !fileSets.empty()) { + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0209), + "\n" + "Executable target \"", + this->GetName(), + "\" has interface header file sets, but it does not " + "enable exports. Those headers would be verified under " + "CMP0209 NEW behavior.\n")); + } + continue; + } + } + + if (!verifySet.empty()) { this->Makefile->IssueMessage( - MessageType::AUTHOR_WARNING, - cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0209), - "\n" - "Executable target \"", + MessageType::FATAL_ERROR, + cmStrCat("Property ", headerSetsProperty, " of target \"", this->GetName(), - "\" has interface header file sets, but it does not " - "enable exports. Those headers would be verified under " - "CMP0209 NEW behavior.\n")); + "\" contained the following header sets that are nonexistent " + "or not ", + isInterface ? "INTERFACE" : "PRIVATE", ":\n ", + cmJoin(verifySet, "\n "))); + return false; } - return true; - } - if (!verifySet.empty()) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Property INTERFACE_HEADER_SETS_TO_VERIFY of target \"", - this->GetName(), - "\" contained the following header sets that are nonexistent " - "or not INTERFACE:\n ", - cmJoin(verifySet, "\n "))); - return false; - } - cm::optional> languages; - for (auto* fileSet : fileSets) { - auto dirCges = fileSet->CompileDirectoryEntries(); - auto fileCges = fileSet->CompileFileEntries(); + cm::optional> languages; + for (auto* fileSet : fileSets) { + auto dirCges = fileSet->CompileDirectoryEntries(); + auto fileCges = fileSet->CompileFileEntries(); - static auto const contextSensitive = - [](std::unique_ptr const& cge) { - return cge->GetHadContextSensitiveCondition(); - }; - bool dirCgesContextSensitive = false; - bool fileCgesContextSensitive = false; + static auto const contextSensitive = + [](std::unique_ptr const& cge) { + return cge->GetHadContextSensitiveCondition(); + }; + bool dirCgesContextSensitive = false; + bool fileCgesContextSensitive = false; - std::vector dirs; - std::map> filesPerDir; - bool first = true; - for (auto const& config : this->Makefile->GetGeneratorConfigs( - cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) { - cm::GenEx::Context context(this->LocalGenerator, config); - if (first || dirCgesContextSensitive) { - dirs = fileSet->EvaluateDirectoryEntries(dirCges, context, this); - dirCgesContextSensitive = - std::any_of(dirCges.begin(), dirCges.end(), contextSensitive); - } - if (first || fileCgesContextSensitive) { - filesPerDir.clear(); - for (auto const& fileCge : fileCges) { - fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, context, - this); - if (fileCge->GetHadContextSensitiveCondition()) { - fileCgesContextSensitive = true; + std::vector dirs; + std::map> filesPerDir; + bool first = true; + for (auto const& config : this->Makefile->GetGeneratorConfigs( + cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) { + cm::GenEx::Context context(this->LocalGenerator, config); + if (first || dirCgesContextSensitive) { + dirs = fileSet->EvaluateDirectoryEntries(dirCges, context, this); + dirCgesContextSensitive = + std::any_of(dirCges.begin(), dirCges.end(), contextSensitive); + } + if (first || fileCgesContextSensitive) { + filesPerDir.clear(); + for (auto const& fileCge : fileCges) { + fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, context, + this); + if (fileCge->GetHadContextSensitiveCondition()) { + fileCgesContextSensitive = true; + } } } - } - for (auto const& files : filesPerDir) { - for (auto const& file : files.second) { - std::string filename = this->GenerateHeaderSetVerificationFile( - *this->Makefile->GetOrCreateSource(file), files.first, - verifyTargetName, languages); - if (filename.empty()) { - continue; - } - - if (!verifyTarget) { - { - cmMakefile::PolicyPushPop polScope(this->Makefile); - this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW); - verifyTarget = this->Makefile->AddLibrary( - verifyTargetName, cmStateEnums::OBJECT_LIBRARY, {}, true); + for (auto const& files : filesPerDir) { + for (auto const& file : files.second) { + std::string filename = this->GenerateHeaderSetVerificationFile( + *this->Makefile->GetOrCreateSource(file), files.first, + verifyTargetName, languages); + if (filename.empty()) { + continue; } - verifyTarget->AddLinkLibrary( - *this->Makefile, this->GetName(), - cmTargetLinkLibraryType::GENERAL_LibraryType); - verifyTarget->SetProperty("AUTOMOC", "OFF"); - verifyTarget->SetProperty("AUTORCC", "OFF"); - verifyTarget->SetProperty("AUTOUIC", "OFF"); - verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON"); - verifyTarget->SetProperty("UNITY_BUILD", "OFF"); - verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF"); - verifyTarget->FinalizeTargetConfiguration( - this->Makefile->GetCompileDefinitionsEntries()); + if (!verifyTarget) { + { + cmMakefile::PolicyPushPop polScope(this->Makefile); + this->Makefile->SetPolicy(cmPolicies::CMP0119, + cmPolicies::NEW); + verifyTarget = this->Makefile->AddLibrary( + verifyTargetName, cmStateEnums::OBJECT_LIBRARY, {}, true); + } - if (!allVerifyTarget) { - allVerifyTarget = - this->GlobalGenerator->GetMakefiles() - .front() - ->AddNewUtilityTarget(allVerifyTargetName, true); + if (isInterface) { + // Link to the original target so that we pick up its + // interface compile options just like a consumer would. + // This also ensures any generated headers in the original + // target will be created. + verifyTarget->AddLinkLibrary( + *this->Makefile, this->GetName(), + cmTargetLinkLibraryType::GENERAL_LibraryType); + } else { + // For private file sets, we need to simulate compiling the + // same way as the original target. That includes linking to + // the same things so we pick up the same transitive + // properties. For the _... properties, we don't care if + // we set them for languages this target won't eventually use. + // The verify header sets feature currently only supports the + // C and C++ languages, so we just always set those here for + // simplicity rather than working out all languages the target + // has to compile for. + static std::vector propertiesToCopy = { + "COMPILE_DEFINITIONS", "COMPILE_FEATURES", + "COMPILE_FLAGS", "COMPILE_OPTIONS", + "DEFINE_SYMBOL", "INCLUDE_DIRECTORIES", + "LINK_LIBRARIES", "C_STANDARD", + "C_STANDARD_REQUIRED", "C_EXTENSIONS", + "CXX_STANDARD", "CXX_STANDARD_REQUIRED", + "CXX_EXTENSIONS" + }; + for (std::string const& prop : propertiesToCopy) { + cmValue propValue = this->Target->GetProperty(prop); + if (propValue.IsSet()) { + verifyTarget->SetProperty(prop, propValue); + } + } + // The original target might have generated headers. Since + // we only link to the original target for compilation, + // there's nothing to force such generation to happen yet. + // Our verify target must depend on the original target to + // ensure such generated files will be created. + verifyTarget->AddUtility(this->GetName(), false, + this->Makefile); + verifyTarget->AddCodegenDependency(this->GetName()); + } + + verifyTarget->SetProperty("AUTOMOC", "OFF"); + verifyTarget->SetProperty("AUTORCC", "OFF"); + verifyTarget->SetProperty("AUTOUIC", "OFF"); + verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON"); + verifyTarget->SetProperty("UNITY_BUILD", "OFF"); + verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF"); + + if (isInterface) { + verifyTarget->FinalizeTargetConfiguration( + this->Makefile->GetCompileDefinitionsEntries()); + } else { + // Private verification only needs to add the directory scope + // definitions here + for (auto const& def : + this->Makefile->GetCompileDefinitionsEntries()) { + verifyTarget->InsertCompileDefinition(def); + } + } + + if (!allVerifyTarget) { + allVerifyTarget = + this->GlobalGenerator->GetMakefiles() + .front() + ->AddNewUtilityTarget(allVerifyTargetName, true); + } + + allVerifyTarget->AddUtility(verifyTargetName, false); } - allVerifyTarget->AddUtility(verifyTargetName, false); + if (fileCgesContextSensitive) { + filename = cmStrCat("$<$:", filename, '>'); + } + verifyTarget->AddSource(filename); } - - if (fileCgesContextSensitive) { - filename = cmStrCat("$<$:", filename, '>'); - } - verifyTarget->AddSource(filename); } - } - if (!dirCgesContextSensitive && !fileCgesContextSensitive) { - break; + if (!dirCgesContextSensitive && !fileCgesContextSensitive) { + break; + } + first = false; } - first = false; } - } - if (verifyTarget) { - this->LocalGenerator->AddGeneratorTarget( - cm::make_unique(verifyTarget, this->LocalGenerator)); + if (verifyTarget) { + this->LocalGenerator->AddGeneratorTarget( + cm::make_unique(verifyTarget, + this->LocalGenerator)); + } } return true; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 836947568d..b20f079f4b 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1861,13 +1861,36 @@ bool cmGlobalGenerator::AddHeaderSetVerification() } } - cmTarget* allVerifyTarget = this->Makefiles.front()->FindTargetToUse( - "all_verify_interface_header_sets", - { cmStateEnums::TargetDomain::NATIVE }); - if (allVerifyTarget) { + cmTarget* allVerifyInterfaceTarget = + this->Makefiles.front()->FindTargetToUse( + "all_verify_interface_header_sets", + { cmStateEnums::TargetDomain::NATIVE }); + if (allVerifyInterfaceTarget) { + this->LocalGenerators.front()->AddGeneratorTarget( + cm::make_unique(allVerifyInterfaceTarget, + this->LocalGenerators.front().get())); + } + cmTarget* allVerifyPrivateTarget = this->Makefiles.front()->FindTargetToUse( + "all_verify_private_header_sets", { cmStateEnums::TargetDomain::NATIVE }); + if (allVerifyPrivateTarget) { + this->LocalGenerators.front()->AddGeneratorTarget( + cm::make_unique(allVerifyPrivateTarget, + this->LocalGenerators.front().get())); + } + + if (allVerifyInterfaceTarget || allVerifyPrivateTarget) { + cmTarget* allVerifyTarget = + this->GetMakefiles().front()->AddNewUtilityTarget( + "all_verify_header_sets", true); this->LocalGenerators.front()->AddGeneratorTarget( cm::make_unique(allVerifyTarget, this->LocalGenerators.front().get())); + if (allVerifyInterfaceTarget) { + allVerifyTarget->AddUtility(allVerifyInterfaceTarget->GetName(), false); + } + if (allVerifyPrivateTarget) { + allVerifyTarget->AddUtility(allVerifyPrivateTarget->GetName(), false); + } } return true; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 6c0cd8b6cc..a97f0e0a24 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -498,6 +498,7 @@ TargetProperty const StaticTargetProperties[] = { { "UNITY_BUILD_RELOCATABLE"_s, IC::CanCompileSources }, { "OPTIMIZE_DEPENDENCIES"_s, IC::CanCompileSources }, { "VERIFY_INTERFACE_HEADER_SETS"_s }, + { "VERIFY_PRIVATE_HEADER_SETS"_s }, // -- Android { "ANDROID_ANT_ADDITIONAL_OPTIONS"_s, IC::CanCompileSources }, { "ANDROID_PROCESS_MAX"_s, IC::CanCompileSources }, diff --git a/Tests/RunCMake/FetchContent/VerifyHeaderSet-stdout.txt b/Tests/RunCMake/FetchContent/VerifyHeaderSet-stdout.txt index 354529da6a..aa1a1aa669 100644 --- a/Tests/RunCMake/FetchContent/VerifyHeaderSet-stdout.txt +++ b/Tests/RunCMake/FetchContent/VerifyHeaderSet-stdout.txt @@ -1,4 +1,8 @@ --- Before subproject, var = 'TRUE' --- Inside subproject, var = 'FALSE' --- After subproject, var = 'TRUE' +-- Before subproject, interface var = 'TRUE' +-- Before subproject, private var = 'TRUE' +-- Inside subproject, interface var = 'FALSE' +-- Inside subproject, private var = 'FALSE' +-- After subproject, interface var = 'TRUE' +-- After subproject, private var = 'TRUE' -- Subproject target property VERIFY_INTERFACE_HEADER_SETS='FALSE' +-- Subproject target property VERIFY_PRIVATE_HEADER_SETS='FALSE' diff --git a/Tests/RunCMake/FetchContent/VerifyHeaderSet.cmake b/Tests/RunCMake/FetchContent/VerifyHeaderSet.cmake index 8adfceaa25..af244c360f 100644 --- a/Tests/RunCMake/FetchContent/VerifyHeaderSet.cmake +++ b/Tests/RunCMake/FetchContent/VerifyHeaderSet.cmake @@ -1,16 +1,21 @@ enable_language(C) set(CMAKE_VERIFY_INTERFACE_HEADER_SETS TRUE) +set(CMAKE_VERIFY_PRIVATE_HEADER_SETS TRUE) include(FetchContent) FetchContent_Declare(verify_subproj SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/VerifyHeaderSet ) -message(STATUS "Before subproject, var = '${CMAKE_VERIFY_INTERFACE_HEADER_SETS}'") +message(STATUS "Before subproject, interface var = '${CMAKE_VERIFY_INTERFACE_HEADER_SETS}'") +message(STATUS "Before subproject, private var = '${CMAKE_VERIFY_PRIVATE_HEADER_SETS}'") FetchContent_MakeAvailable(verify_subproj) # Provide a way to verify the variable was reset back to its original value -message(STATUS "After subproject, var = '${CMAKE_VERIFY_INTERFACE_HEADER_SETS}'") +message(STATUS "After subproject, interface var = '${CMAKE_VERIFY_INTERFACE_HEADER_SETS}'") +message(STATUS "After subproject, private var = '${CMAKE_VERIFY_PRIVATE_HEADER_SETS}'") -get_property(verify TARGET Blah PROPERTY VERIFY_INTERFACE_HEADER_SETS) -message(STATUS "Subproject target property VERIFY_INTERFACE_HEADER_SETS='${verify}'") +get_property(verify_interface TARGET Blah PROPERTY VERIFY_INTERFACE_HEADER_SETS) +get_property(verify_private TARGET Blah PROPERTY VERIFY_PRIVATE_HEADER_SETS) +message(STATUS "Subproject target property VERIFY_INTERFACE_HEADER_SETS='${verify_interface}'") +message(STATUS "Subproject target property VERIFY_PRIVATE_HEADER_SETS='${verify_private}'") diff --git a/Tests/RunCMake/FetchContent/VerifyHeaderSet/CMakeLists.txt b/Tests/RunCMake/FetchContent/VerifyHeaderSet/CMakeLists.txt index c6ba37e78c..22e740c9e5 100644 --- a/Tests/RunCMake/FetchContent/VerifyHeaderSet/CMakeLists.txt +++ b/Tests/RunCMake/FetchContent/VerifyHeaderSet/CMakeLists.txt @@ -1,9 +1,10 @@ cmake_minimum_required(VERSION 3.24) project(VerifyHeaderSet LANGUAGES C) -message(STATUS "Inside subproject, var = '${CMAKE_VERIFY_INTERFACE_HEADER_SETS}'") +message(STATUS "Inside subproject, interface var = '${CMAKE_VERIFY_INTERFACE_HEADER_SETS}'") +message(STATUS "Inside subproject, private var = '${CMAKE_VERIFY_PRIVATE_HEADER_SETS}'") add_library(Blah INTERFACE) target_sources(Blah - INTERFACE FILE_SET HEADERS FILES blah.h + PUBLIC FILE_SET HEADERS FILES blah.h ) diff --git a/Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets-all_verify_private_header_sets-Debug-build-check.cmake b/Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets-all_verify_private_header_sets-Debug-build-check.cmake new file mode 100644 index 0000000000..1b78af67b7 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets-all_verify_private_header_sets-Debug-build-check.cmake @@ -0,0 +1,10 @@ +# A custom command is used to copy the header file from the source directory to +# the binary directory. If the verification target was built, the custom +# command should have been executed, and the file should be present in the +# binary directory. +if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/dir3/lib3.h") + string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/dir3/lib3.h should exist but it does not\n") +endif() +if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/dir4/lib4.h") + string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/dir4/lib4.h should exist but it does not\n") +endif() diff --git a/Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets.cmake b/Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets.cmake new file mode 100644 index 0000000000..af30b1ece1 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/AllVerifyPrivateHeaderSets.cmake @@ -0,0 +1,4 @@ +enable_language(C) + +add_subdirectory(dir3) +add_subdirectory(dir4) diff --git a/Tests/RunCMake/VerifyHeaderSets/RunCMakeTest.cmake b/Tests/RunCMake/VerifyHeaderSets/RunCMakeTest.cmake index 7475c0f585..61e4df7c2e 100644 --- a/Tests/RunCMake/VerifyHeaderSets/RunCMakeTest.cmake +++ b/Tests/RunCMake/VerifyHeaderSets/RunCMakeTest.cmake @@ -59,3 +59,47 @@ unset(RunCMake_TEST_OPTIONS) run_cmake(VerifyInterfaceHeaderSets-CMP0209-NEW) run_cmake(VerifyInterfaceHeaderSets-CMP0209-OLD) run_cmake(VerifyInterfaceHeaderSets-CMP0209-WARN) + +set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_PRIVATE_HEADER_SETS=ON) +if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) +endif() +run_cmake(VerifyPrivateHeaderSets) +unset(RunCMake_TEST_OPTIONS) + +run_cmake_build(VerifyPrivateHeaderSets private static) +run_cmake_build(VerifyPrivateHeaderSets private shared) +run_cmake_build(VerifyPrivateHeaderSets private object) +run_cmake_build(VerifyPrivateHeaderSets private interface) +run_cmake_build(VerifyPrivateHeaderSets private iface_private) +run_cmake_build(VerifyPrivateHeaderSets private exe) +run_cmake_build(VerifyPrivateHeaderSets private none) +run_cmake_build(VerifyPrivateHeaderSets private property_off) +run_cmake_build(VerifyPrivateHeaderSets private a_h) +run_cmake_build(VerifyPrivateHeaderSets private dir_c_h) +run_cmake_build(VerifyPrivateHeaderSets private dir_cxx_h) + +if(NOT RunCMake_GENERATOR STREQUAL "Xcode") + run_cmake_build(VerifyPrivateHeaderSets private config) + if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(BUILD_CONFIG Release) + run_cmake_build(VerifyPrivateHeaderSets private config) + unset(BUILD_CONFIG) + endif() +endif() + +run_cmake_build(VerifyPrivateHeaderSets private lang_test_c) +run_cmake_build(VerifyPrivateHeaderSets private lang_test_cxx) +run_cmake_build(VerifyPrivateHeaderSets private iface_lang_cxx) +run_cmake_build(VerifyPrivateHeaderSets private list) +run_cmake_build(VerifyPrivateHeaderSets private skip_linting) + +set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_PRIVATE_HEADER_SETS=ON) +run_cmake(AllVerifyPrivateHeaderSets) +unset(RunCMake_TEST_OPTIONS) + +run_cmake_build(AllVerifyPrivateHeaderSets private all) + +set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_PRIVATE_HEADER_SETS=ON) +run_cmake(VerifyPrivateHeaderSetsNonexistent) +unset(RunCMake_TEST_OPTIONS) diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stderr.txt new file mode 100644 index 0000000000..b78bc52633 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stderr.txt @@ -0,0 +1 @@ +(TEST_A_H defined)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stdout.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stdout.txt new file mode 100644 index 0000000000..b78bc52633 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-a_h-Debug-build-stdout.txt @@ -0,0 +1 @@ +(TEST_A_H defined)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stderr.txt new file mode 100644 index 0000000000..eaa9a031e9 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stderr.txt @@ -0,0 +1 @@ +(Compiled in debug mode)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stdout.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stdout.txt new file mode 100644 index 0000000000..eaa9a031e9 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Debug-build-stdout.txt @@ -0,0 +1 @@ +(Compiled in debug mode)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stderr.txt new file mode 100644 index 0000000000..25699f9943 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stderr.txt @@ -0,0 +1 @@ +(Compiled in release mode)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stdout.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stdout.txt new file mode 100644 index 0000000000..25699f9943 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-config-Release-build-stdout.txt @@ -0,0 +1 @@ +(Compiled in release mode)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stderr.txt new file mode 100644 index 0000000000..27ef042dab --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stderr.txt @@ -0,0 +1 @@ +(TEST_DIR_C_H defined)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stdout.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stdout.txt new file mode 100644 index 0000000000..27ef042dab --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_c_h-Debug-build-stdout.txt @@ -0,0 +1 @@ +(TEST_DIR_C_H defined)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stderr.txt new file mode 100644 index 0000000000..cd17d11756 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stderr.txt @@ -0,0 +1 @@ +(TEST_DIR_CXX_H defined)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stdout.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stdout.txt new file mode 100644 index 0000000000..cd17d11756 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-dir_cxx_h-Debug-build-stdout.txt @@ -0,0 +1 @@ +(TEST_DIR_CXX_H defined)? diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-iface_lang_cxx-Debug-build-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-interface-Debug-build-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-none-Debug-build-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-result.txt new file mode 100644 index 0000000000..d197c913c2 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-result.txt @@ -0,0 +1 @@ +[^0] diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets-property_off-Debug-build-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake new file mode 100644 index 0000000000..1fc92e1a66 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSets.cmake @@ -0,0 +1,88 @@ +cmake_policy(SET CMP0209 NEW) + +enable_language(C CXX) + +add_compile_definitions(TEST_ADD_COMPILE_DEFINITIONS) + +set_property(SOURCE a.h PROPERTY LANGUAGE C) +set_property(SOURCE dir/c.h PROPERTY LANGUAGE C) +set_property(SOURCE dir/cxx.h PROPERTY LANGUAGE CXX) + +add_library(static STATIC lib.c) +target_sources(static PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(shared SHARED lib.c) +target_sources(shared PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(module MODULE lib.c) +target_sources(module PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(object OBJECT lib.c) +target_sources(object PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(interface INTERFACE) +target_sources(interface INTERFACE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +# Though a bit strange, INTERFACE libraries can have PRIVATE file sets. +# A more likely scenario would be generated headers which might be PUBLIC. +# Don't make the name of this target any longer or else it triggers a crash in the OpenWatcom compiler. +# That crash only occurs when debug information is enabled, which is the case when this test runs. +add_library(iface_private INTERFACE) +target_sources(iface_private PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_executable(exe main.c) +target_sources(exe PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(none STATIC lib.c) + +add_library(property_off STATIC lib.c) +target_sources(property_off PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) +set_property(TARGET property_off PROPERTY VERIFY_PRIVATE_HEADER_SETS OFF) + +add_library(a_h STATIC lib.c) +target_compile_definitions(a_h PRIVATE TEST_A_H) +target_sources(a_h PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(dir_c_h STATIC lib.c) +target_compile_definitions(dir_c_h PRIVATE TEST_DIR_C_H) +target_sources(dir_c_h PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +add_library(dir_cxx_h STATIC lib.c) +target_compile_definitions(dir_cxx_h PRIVATE TEST_DIR_CXX_H) +target_sources(dir_cxx_h PRIVATE FILE_SET HEADERS FILES a.h dir/c.h dir/cxx.h) + +set_property(SOURCE debug.h PROPERTY LANGUAGE C) +set_property(SOURCE release.h PROPERTY LANGUAGE C) + +if(NOT CMAKE_GENERATOR STREQUAL "Xcode") + add_library(config STATIC lib.c) + target_sources(config PRIVATE FILE_SET HEADERS FILES $,debug.h,release.h>) +endif() + +add_library(lang_test_c STATIC lib.c) +target_sources(lang_test_c PRIVATE FILE_SET HEADERS FILES lang_test.h) + +add_library(lang_test_cxx STATIC lib.c lib.cxx) +target_compile_definitions(lang_test_cxx PRIVATE EXPECT_CXX) +target_sources(lang_test_cxx PRIVATE FILE_SET HEADERS FILES lang_test.h) + +# Don't make the name of this target any longer or else it triggers a crash in the OpenWatcom compiler. +# That crash only occurs when debug information is enabled, which is the case when this test runs. +add_library(iface_lang_cxx INTERFACE) +target_compile_definitions(iface_lang_cxx INTERFACE EXPECT_CXX) +target_sources(iface_lang_cxx INTERFACE FILE_SET HEADERS FILES lang_test.h) + +set_property(SOURCE error.h PROPERTY LANGUAGE C) + +add_library(list STATIC lib.c) +target_sources(list PRIVATE + FILE_SET a TYPE HEADERS FILES a.h + FILE_SET c TYPE HEADERS FILES dir/c.h + FILE_SET error TYPE HEADERS FILES error.h +) +set_property(TARGET list PROPERTY PRIVATE_HEADER_SETS_TO_VERIFY "a;c") + +add_library(skip_linting STATIC lib.c) +target_sources(skip_linting PRIVATE FILE_SET HEADERS FILES lang_test.h skip_linting.h) +set_property(SOURCE skip_linting.h PROPERTY LANGUAGE C) +set_property(SOURCE skip_linting.h PROPERTY SKIP_LINTING TRUE) diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-result.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-stderr.txt b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-stderr.txt new file mode 100644 index 0000000000..3473b61846 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error in CMakeLists\.txt: + Property PRIVATE_HEADER_SETS_TO_VERIFY of target "nonexistent" contained + the following header sets that are nonexistent or not PRIVATE: + + b + c + + +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent.cmake b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent.cmake new file mode 100644 index 0000000000..234e4109b9 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/VerifyPrivateHeaderSetsNonexistent.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +add_library(nonexistent STATIC lib.c) +target_sources(nonexistent PRIVATE FILE_SET a TYPE HEADERS FILES a.h) +set_property(TARGET nonexistent PROPERTY PRIVATE_HEADER_SETS_TO_VERIFY "a;c;b") diff --git a/Tests/RunCMake/VerifyHeaderSets/dir3/CMakeLists.txt b/Tests/RunCMake/VerifyHeaderSets/dir3/CMakeLists.txt new file mode 100644 index 0000000000..4ec6134051 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/dir3/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(lib3 STATIC ../lib.c) +add_custom_command(OUTPUT lib3.h COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/lib3.h lib3.h) +target_sources(lib3 PRIVATE FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR} FILES ${CMAKE_CURRENT_BINARY_DIR}/lib3.h) diff --git a/Tests/RunCMake/VerifyHeaderSets/dir3/lib3.h b/Tests/RunCMake/VerifyHeaderSets/dir3/lib3.h new file mode 100644 index 0000000000..66d2eba283 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/dir3/lib3.h @@ -0,0 +1,5 @@ +#ifdef _WIN32 +__declspec(dllimport) +#endif +extern void +lib3(void); diff --git a/Tests/RunCMake/VerifyHeaderSets/dir4/CMakeLists.txt b/Tests/RunCMake/VerifyHeaderSets/dir4/CMakeLists.txt new file mode 100644 index 0000000000..0f5a79239c --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/dir4/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(lib4 STATIC ../lib.c) +add_custom_command(OUTPUT lib4.h COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/lib4.h lib4.h) +target_sources(lib4 PRIVATE FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR} FILES ${CMAKE_CURRENT_BINARY_DIR}/lib4.h) diff --git a/Tests/RunCMake/VerifyHeaderSets/dir4/lib4.h b/Tests/RunCMake/VerifyHeaderSets/dir4/lib4.h new file mode 100644 index 0000000000..12e873a938 --- /dev/null +++ b/Tests/RunCMake/VerifyHeaderSets/dir4/lib4.h @@ -0,0 +1,5 @@ +#ifdef _WIN32 +__declspec(dllimport) +#endif +extern void +lib4(void); diff --git a/Tests/RunCMake/property_init/Always.cmake b/Tests/RunCMake/property_init/Always.cmake index db23563e7d..5e2eae8c86 100644 --- a/Tests/RunCMake/property_init/Always.cmake +++ b/Tests/RunCMake/property_init/Always.cmake @@ -5,6 +5,7 @@ set(properties # Build graph properties "VERIFY_INTERFACE_HEADER_SETS" "TRUE" "" + "VERIFY_PRIVATE_HEADER_SETS" "TRUE" "" # Metadata "FOLDER" "folder" ""