diff options
57 files changed, 639 insertions, 311 deletions
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index 5629356..5d412c2 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -450,6 +450,7 @@ syn keyword cmakeProperty contained \ VS_STARTUP_PROJECT \ VS_TOOL_OVERRIDE \ VS_USER_PROPS + \ VS_FILTER_PROPS \ VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION \ VS_WINRT_COMPONENT \ VS_WINRT_EXTENSIONS diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 38fa6f9..31f0573 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1282,7 +1282,7 @@ Compile Context .. versionadded:: 3.27 Content of ``...``, when collecting - :ref:`usage requirements <Target Usage Requirements>`, + :ref:`transitive build properties <Transitive Build Properties>`, otherwise it is the empty string. This is intended for use in an :prop_tgt:`INTERFACE_LINK_LIBRARIES` and :prop_tgt:`LINK_LIBRARIES` target properties, typically populated via the :command:`target_link_libraries` command. @@ -1670,8 +1670,8 @@ Link Context .. versionadded:: 3.1 - Content of ``...``, except while collecting - :ref:`usage requirements <Target Usage Requirements>`, + Content of ``...``, except while collecting usage requirements from + :ref:`transitive build properties <Transitive Build Properties>`, in which case it is the empty string. This is intended for use in an :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated via the :command:`target_link_libraries` command, to specify private link @@ -1788,7 +1788,16 @@ The expressions have special evaluation rules for some properties: of the value on the target itself with the values of the same properties on targets named by the target's :prop_tgt:`INTERFACE_LINK_LIBRARIES`. Evaluation is transitive over the closure of the target's - :prop_tgt:`INTERFACE_LINK_LIBRARIES`. + :prop_tgt:`INTERFACE_LINK_LIBRARIES`: + + * For :ref:`Transitive Build Properties`, the transitive closure + *excludes* entries of :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded + by the :genex:`LINK_ONLY` generator expression. + + * For :ref:`Transitive Link Properties`, the transitive closure is + *includes* entries of :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded + by the :genex:`LINK_ONLY` generator expression. + See policy :policy:`CMP0166`. Evaluation of :prop_tgt:`INTERFACE_LINK_LIBRARIES` itself is not transitive. diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index e46e88e..826790d 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,7 @@ Policies Introduced by CMake 3.30 .. toctree:: :maxdepth: 1 + CMP0166: TARGET_PROPERTY evaluates link properties transitively over private dependencies of static libraries. </policy/CMP0166> CMP0165: enable_language() must not be called before project(). </policy/CMP0165> CMP0164: add_library() rejects SHARED libraries when not supported by the platform. </policy/CMP0164> CMP0163: The GENERATED source file property is now visible in all directories. </policy/CMP0163> @@ -214,7 +215,7 @@ Policies Introduced by CMake 3.17 CMP0102: mark_as_advanced() does nothing if a cache entry does not exist. </policy/CMP0102> CMP0101: target_compile_options honors BEFORE keyword in all scopes. </policy/CMP0101> CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100> - CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099> + CMP0099: Link properties are transitive over private dependencies of static libraries. </policy/CMP0099> CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098> Policies Introduced by CMake 3.16 diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 6ccc23e..7e640df 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -448,6 +448,7 @@ Properties on Targets /prop_tgt/VS_SOURCE_SETTINGS_tool /prop_tgt/VS_USE_DEBUG_LIBRARIES /prop_tgt/VS_USER_PROPS + /prop_tgt/VS_FILTER_PROPS /prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION /prop_tgt/VS_WINRT_COMPONENT /prop_tgt/VS_WINRT_REFERENCES diff --git a/Help/policy/CMP0099.rst b/Help/policy/CMP0099.rst index c0db99d..0a2b786 100644 --- a/Help/policy/CMP0099.rst +++ b/Help/policy/CMP0099.rst @@ -3,13 +3,16 @@ CMP0099 .. versionadded:: 3.17 -Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`, -:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DEPENDS` -are now transitive over private dependencies of static libraries. +Link properties are transitive over private dependencies of static libraries. -In CMake 3.16 and below the interface link properties attached to libraries -are not propagated for private dependencies of static libraries. +In CMake 3.16 and below, evaluation of target properties +:prop_tgt:`INTERFACE_LINK_OPTIONS`, :prop_tgt:`INTERFACE_LINK_DIRECTORIES`, +and :prop_tgt:`INTERFACE_LINK_DEPENDS` during buildsystem generation does not +follow private dependencies of static libraries, which appear in their +:prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded by :genex:`LINK_ONLY` generator +expressions. Only the libraries themselves are propagated to link the dependent binary. + CMake 3.17 and later prefer to propagate all interface link properties. This policy provides compatibility for projects that have not been updated to expect the new behavior. @@ -18,6 +21,12 @@ The ``OLD`` behavior for this policy is to not propagate interface link properties. The ``NEW`` behavior of this policy is to propagate interface link properties. +.. versionadded:: 3.30 + + Policy :policy:`CMP0166` makes :genex:`TARGET_PROPERTY` evaluation of + these three transitive link properties follow private dependencies of + static libraries too. + .. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.17 .. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn .. include:: STANDARD_ADVICE.txt diff --git a/Help/policy/CMP0166.rst b/Help/policy/CMP0166.rst new file mode 100644 index 0000000..5c67880 --- /dev/null +++ b/Help/policy/CMP0166.rst @@ -0,0 +1,40 @@ +CMP0166 +------- + +.. versionadded:: 3.30 + +:genex:`TARGET_PROPERTY` evaluates link properties transitively over private +dependencies of static libraries. + +In CMake 3.29 and below, the :genex:`TARGET_PROPERTY` generator expression +evaluates properties :prop_tgt:`INTERFACE_LINK_OPTIONS`, +:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS` +as if they were :ref:`Transitive Build Properties` rather than +:ref:`Transitive Link Properties`, even when policy :policy:`CMP0099` is +set to ``NEW``. Private dependencies of static libraries, which appear in +their :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded by :genex:`LINK_ONLY` +generator expressions, are not followed. This is inconsistent with +evaluation of the same target properties during buildsystem generation. + +CMake 3.30 and above prefer that :genex:`TARGET_PROPERTY` evaluates +properties :prop_tgt:`INTERFACE_LINK_OPTIONS`, +:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS` +as :ref:`Transitive Link Properties` such that private dependencies of static +libraries, which appear in their :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded +by :genex:`LINK_ONLY` generator expressions, are followed. +This policy provides compatibility for projects that have not been updated +to expect the new behavior. + +The ``OLD`` behavior for this policy is for :genex:`TARGET_PROPERTY` to +evaluate properties :prop_tgt:`INTERFACE_LINK_OPTIONS`, +:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS` +as if they were :ref:`Transitive Build Properties` by not following private +dependencies of static libraries. The ``NEW`` behavior for this policy is +to evaluate them as :ref:`Transitive Link Properties` by following private +dependencies of static libraries. + +.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.30 +.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn +.. include:: STANDARD_ADVICE.txt + +.. include:: DEPRECATED.txt diff --git a/Help/prop_tgt/VS_FILTER_PROPS.rst b/Help/prop_tgt/VS_FILTER_PROPS.rst new file mode 100644 index 0000000..3de0a16 --- /dev/null +++ b/Help/prop_tgt/VS_FILTER_PROPS.rst @@ -0,0 +1,10 @@ +VS_FILTER_PROPS +--------------- + +.. versionadded:: 3.30 + +Sets the filter props file to be included in the visual studio +C++ project filter file. + +The ``*.filter.props`` files can be used for Visual Studio wide +configuration which is independent from cmake. diff --git a/Help/release/dev/FindOpenMP-runtime-msvc.rst b/Help/release/dev/FindOpenMP-runtime-msvc.rst new file mode 100644 index 0000000..76df237 --- /dev/null +++ b/Help/release/dev/FindOpenMP-runtime-msvc.rst @@ -0,0 +1,5 @@ +FindOpenMP-runtime-msvc +----------------------- + +* The :module:`FindOpenMP` module gained a ``OpenMP_RUNTIME_MSVC`` + option to control the OpenMP runtime used with MSVC. diff --git a/Help/release/dev/genex-link-properties.rst b/Help/release/dev/genex-link-properties.rst new file mode 100644 index 0000000..e1e84e0 --- /dev/null +++ b/Help/release/dev/genex-link-properties.rst @@ -0,0 +1,8 @@ +genex-link-properties +--------------------- + +* The :genex:`TARGET_PROPERTY` generator expression now evaluates target + properties :prop_tgt:`INTERFACE_LINK_OPTIONS`, + :prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and + :prop_tgt:`INTERFACE_LINK_DEPENDS` correctly by following private + dependencies of static libraries. See policy :policy:`CMP0166`. diff --git a/Help/release/dev/vs-filter-props.rst b/Help/release/dev/vs-filter-props.rst new file mode 100644 index 0000000..5a09511 --- /dev/null +++ b/Help/release/dev/vs-filter-props.rst @@ -0,0 +1,6 @@ +vs-filter-props +--------------- + +* A :prop_tgt:`VS_FILTER_PROPS` target property was added to tell + :ref:`Visual Studio Generators` for VS 2010 and above to use a + custom MSBuild filter ``.props`` file. diff --git a/Modules/FindICU.cmake b/Modules/FindICU.cmake index 4708aff..63c2576 100644 --- a/Modules/FindICU.cmake +++ b/Modules/FindICU.cmake @@ -24,10 +24,10 @@ platform-specific library name will be automatically selected. This module reports information about the ICU installation in several variables. General variables:: - ICU_VERSION - ICU release version ICU_FOUND - true if the main programs and libraries were found - ICU_LIBRARIES - component libraries to be linked ICU_INCLUDE_DIRS - the directories containing the ICU headers + ICU_LIBRARIES - component libraries to be linked + ICU_VERSION - ICU release version Imported targets:: @@ -83,15 +83,10 @@ The following cache variables may also be set:: In most cases none of the above variables will require setting, unless multiple ICU versions are available and a specific version is required. - -Other variables one may set to control this module are:: - - ICU_DEBUG - Set to ON to enable debug output from FindICU. #]=======================================================================] cmake_policy(PUSH) cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n> - # Written by Roger Leigh <rleigh@codelibre.net> set(icu_programs @@ -182,7 +177,6 @@ function(_ICU_FIND) # Find all ICU libraries list(APPEND icu_library_suffixes "${_lib64}" "lib") - set(ICU_REQUIRED_LIBS_FOUND ON) set(static_prefix ) # static icu libraries compiled with MSVC have the prefix 's' if(MSVC) @@ -193,8 +187,9 @@ function(_ICU_FIND) set(component_cache "ICU_${component_upcase}_LIBRARY") set(component_cache_release "${component_cache}_RELEASE") set(component_cache_debug "${component_cache}_DEBUG") - set(component_found "ICU_${component_upcase}_FOUND") + set(component_found "ICU_${component}_FOUND") set(component_found_compat "${component_upcase}_FOUND") + set(component_found_compat2 "ICU_${component_upcase}_FOUND") set(component_libnames "icu${component}") set(component_debug_libnames "icu${component}d") @@ -257,27 +252,17 @@ function(_ICU_FIND) if(${component_cache}) set("${component_found}" ON) set("${component_found_compat}" ON) + set("${component_found_compat2}" ON) list(APPEND ICU_LIBRARY "${${component_cache}}") - if (ICU_FIND_REQUIRED_${component}) - list(APPEND ICU_LIBS_FOUND "${component} (required): ${${component_cache}}") - else() - list(APPEND ICU_LIBS_FOUND "${component} (optional): ${${component_cache}}") - endif() - else() - if (ICU_FIND_REQUIRED_${component}) - set(ICU_REQUIRED_LIBS_FOUND OFF) - list(APPEND ICU_LIBS_NOTFOUND "${component} (required)") - else() - list(APPEND ICU_LIBS_NOTFOUND "${component} (optional)") - endif() endif() mark_as_advanced("${component_found}") mark_as_advanced("${component_found_compat}") + mark_as_advanced("${component_found_compat2}") set("${component_cache}" "${${component_cache}}" PARENT_SCOPE) set("${component_found}" "${${component_found}}" PARENT_SCOPE) set("${component_found_compat}" "${${component_found_compat}}" PARENT_SCOPE) + set("${component_found_compat2}" "${${component_found_compat2}}" PARENT_SCOPE) endforeach() - set(_ICU_REQUIRED_LIBS_FOUND "${ICU_REQUIRED_LIBS_FOUND}" PARENT_SCOPE) set(ICU_LIBRARY "${ICU_LIBRARY}" PARENT_SCOPE) # Find all ICU data files @@ -306,43 +291,21 @@ function(_ICU_FIND) mark_as_advanced("${cache_var}") set("${data_var}" "${${cache_var}}" PARENT_SCOPE) endforeach() - - if(NOT ICU_FIND_QUIETLY) - if(ICU_LIBS_FOUND) - message(STATUS "Found the following ICU libraries:") - foreach(found ${ICU_LIBS_FOUND}) - message(STATUS " ${found}") - endforeach() - endif() - if(ICU_LIBS_NOTFOUND) - message(STATUS "The following ICU libraries were not found:") - foreach(notfound ${ICU_LIBS_NOTFOUND}) - message(STATUS " ${notfound}") - endforeach() - endif() - endif() - - if(ICU_DEBUG) - message(STATUS "--------FindICU.cmake search debug--------") - message(STATUS "ICU binary path search order: ${icu_roots}") - message(STATUS "ICU include path search order: ${icu_roots}") - message(STATUS "ICU library path search order: ${icu_roots}") - message(STATUS "----------------") - endif() endfunction() _ICU_FIND() include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(ICU - FOUND_VAR ICU_FOUND - REQUIRED_VARS ICU_INCLUDE_DIR - ICU_LIBRARY - _ICU_REQUIRED_LIBS_FOUND - VERSION_VAR ICU_VERSION - FAIL_MESSAGE "Failed to find all ICU components") - -unset(_ICU_REQUIRED_LIBS_FOUND) +find_package_handle_standard_args(ICU + REQUIRED_VARS + ICU_INCLUDE_DIR + ICU_LIBRARY + VERSION_VAR + ICU_VERSION + HANDLE_COMPONENTS + FAIL_MESSAGE + "Failed to find all ICU components" +) if(ICU_FOUND) set(ICU_INCLUDE_DIRS "${ICU_INCLUDE_DIR}") @@ -396,47 +359,5 @@ if(ICU_FOUND) endforeach() endif() -if(ICU_DEBUG) - message(STATUS "--------FindICU.cmake results debug--------") - message(STATUS "ICU found: ${ICU_FOUND}") - message(STATUS "ICU_VERSION number: ${ICU_VERSION}") - message(STATUS "ICU_ROOT directory: ${ICU_ROOT}") - message(STATUS "ICU_INCLUDE_DIR directory: ${ICU_INCLUDE_DIR}") - message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}") - - foreach(program IN LISTS icu_programs) - string(TOUPPER "${program}" program_upcase) - set(program_lib "ICU_${program_upcase}_EXECUTABLE") - message(STATUS "${program} program: ${program_lib}=${${program_lib}}") - unset(program_upcase) - unset(program_lib) - endforeach() - - foreach(data IN LISTS icu_data) - string(TOUPPER "${data}" data_upcase) - string(REPLACE "." "_" data_upcase "${data_upcase}") - set(data_lib "ICU_${data_upcase}") - message(STATUS "${data} data: ${data_lib}=${${data_lib}}") - unset(data_upcase) - unset(data_lib) - endforeach() - - foreach(component IN LISTS ICU_FIND_COMPONENTS) - string(TOUPPER "${component}" component_upcase) - set(component_lib "ICU_${component_upcase}_LIBRARIES") - set(component_found "ICU_${component_upcase}_FOUND") - set(component_found_compat "${component_upcase}_FOUND") - message(STATUS "${component} library found: ${component_found}=${${component_found}}") - message(STATUS "${component} library found (compat name): ${component_found_compat}=${${component_found_compat}}") - message(STATUS "${component} library: ${component_lib}=${${component_lib}}") - unset(component_upcase) - unset(component_lib) - unset(component_found) - unset(component_found_compat) - endforeach() - message(STATUS "----------------") -endif() - unset(icu_programs) - cmake_policy(POP) diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake index 077a239..f88e43c 100644 --- a/Modules/FindOpenMP.cmake +++ b/Modules/FindOpenMP.cmake @@ -16,8 +16,22 @@ flag to support OpenMP. .. versionadded:: 3.5 Clang support. -Variables -^^^^^^^^^ +Input Variables +^^^^^^^^^^^^^^^ + +The following variables may be set to influence this module's behavior: + +``OpenMP_RUNTIME_MSVC`` + .. versionadded:: 3.30 + + Specify the `OpenMP Runtime <msvc-openmp_>`_ when compiling with MSVC. + If set to a non-empty value, such as ``experimental`` or ``llvm``, it + will be passed as the value of the ``-openmp:`` flag. + +.. _`msvc-openmp`: https://learn.microsoft.com/en-us/cpp/build/reference/openmp-enable-openmp-2-0-support + +Result Variables +^^^^^^^^^^^^^^^^ .. versionadded:: 3.10 The module exposes the components ``C``, ``CXX``, and ``Fortran``. @@ -121,7 +135,11 @@ function(_OPENMP_FLAG_CANDIDATES LANG) else() set(OMP_FLAG_IntelLLVM "-fiopenmp") endif() - set(OMP_FLAG_MSVC "-openmp") + if(OpenMP_RUNTIME_MSVC) + set(OMP_FLAG_MSVC "-openmp:${OpenMP_RUNTIME_MSVC}") + else() + set(OMP_FLAG_MSVC "-openmp") + endif() set(OMP_FLAG_PathScale "-openmp") set(OMP_FLAG_NAG "-openmp") set(OMP_FLAG_Absoft "-openmp") diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake index 63b2bf2..c6db433 100644 --- a/Modules/FindPackageHandleStandardArgs.cmake +++ b/Modules/FindPackageHandleStandardArgs.cmake @@ -225,6 +225,9 @@ macro(_FPHSA_FAILURE_MESSAGE _msg) set (__msg "${_msg}") if (FPHSA_REASON_FAILURE_MESSAGE) string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n") + elseif(NOT DEFINED PROJECT_NAME) + string(APPEND __msg "\n" + "Hint: The project() command has not yet been called. It sets up system-specific search paths.") endif() if (${_NAME}_FIND_REQUIRED) message(FATAL_ERROR "${__msg}") diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 7170842..203e214 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 29) -set(CMake_VERSION_PATCH 20240501) +set(CMake_VERSION_PATCH 20240502) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 677bb48..fbf39e2 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -501,7 +501,8 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher( cmValue launcherProp = this->GeneratorTarget->GetProperty(propName); if (cmNonempty(launcherProp)) { cmGeneratorExpressionDAGChecker dagChecker(this->GeneratorTarget, propName, - nullptr, nullptr); + nullptr, nullptr, + this->LocalCommonGenerator); std::string evaluatedLinklauncher = cmGeneratorExpression::Evaluate( *launcherProp, this->LocalCommonGenerator, config, this->GeneratorTarget, &dagChecker, this->GeneratorTarget, lang); diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index f4b26f3..f6ff71a 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -451,10 +451,14 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, if (cmValue feature = this->Target->GetProperty(key)) { if (!feature->empty() && key.length() > lloPrefix.length()) { auto item = key.substr(lloPrefix.length()); - cmGeneratorExpressionDAGChecker dag{ this->Target->GetBacktrace(), - this->Target, - "LINK_LIBRARY_OVERRIDE", - nullptr, nullptr }; + cmGeneratorExpressionDAGChecker dag{ + this->Target->GetBacktrace(), + this->Target, + "LINK_LIBRARY_OVERRIDE", + nullptr, + nullptr, + this->Target->GetLocalGenerator() + }; auto overrideFeature = cmGeneratorExpression::Evaluate( *feature, this->Target->GetLocalGenerator(), config, this->Target, &dag, this->Target, linkLanguage); @@ -466,9 +470,12 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, // global override property if (cmValue linkLibraryOverride = this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) { - cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, - "LINK_LIBRARY_OVERRIDE", nullptr, - nullptr }; + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), + target, + "LINK_LIBRARY_OVERRIDE", + nullptr, + nullptr, + target->GetLocalGenerator() }; auto overrideValue = cmGeneratorExpression::Evaluate( *linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag, target, linkLanguage); diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index 00c9173..4c41ff5 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -2,9 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportTryCompileFileGenerator.h" +#include <map> #include <utility> #include <cm/memory> +#include <cm/string_view> #include "cmFileSet.h" #include "cmGeneratorExpression.h" @@ -44,12 +46,10 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os) ImportPropertyMap properties; for (std::string const& lang : this->Languages) { -#define FIND_TARGETS(PROPERTY) \ - this->FindTargets("INTERFACE_" #PROPERTY, te, lang, emittedDeps); - - CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS) - -#undef FIND_TARGETS + for (auto i : cmGeneratorTarget::BuiltinTransitiveProperties) { + this->FindTargets(std::string(i.second.InterfaceName), te, lang, + emittedDeps); + } } this->PopulateProperties(te, properties, emittedDeps); @@ -76,10 +76,10 @@ std::string cmExportTryCompileFileGenerator::FindTargets( // To please constraint checks of DAGChecker, this property must have // LINK_OPTIONS property as parent parentDagChecker = cm::make_unique<cmGeneratorExpressionDAGChecker>( - tgt, "LINK_OPTIONS", nullptr, nullptr); + tgt, "LINK_OPTIONS", nullptr, nullptr, tgt->GetLocalGenerator()); } - cmGeneratorExpressionDAGChecker dagChecker(tgt, propName, nullptr, - parentDagChecker.get()); + cmGeneratorExpressionDAGChecker dagChecker( + tgt, propName, nullptr, parentDagChecker.get(), tgt->GetLocalGenerator()); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 0b96c3f..0583fd5 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -425,7 +425,7 @@ const std::string& cmGeneratorExpressionInterpreter::Evaluate( cmGeneratorExpressionDAGChecker dagChecker( this->HeadTarget, property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, nullptr, - nullptr); + nullptr, this->LocalGenerator); return this->CompiledGeneratorExpression->Evaluate( this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr, diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index fda7ec3..bb1f4b4 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -2,10 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGeneratorExpressionDAGChecker.h" -#include <cstring> #include <sstream> #include <utility> +#include <cm/optional> #include <cm/string_view> #include <cmext/string_view> @@ -20,16 +20,17 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* parent) + cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG) : cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target, - std::move(property), content, parent) + std::move(property), content, parent, + contextLG) { } cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( cmListFileBacktrace backtrace, cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* parent) + cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG) : Parent(parent) , Top(parent ? parent->Top : this) , Target(target) @@ -40,10 +41,9 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( if (parent) { this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty; } else { -#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) this->METHOD() || - this->TopIsTransitiveProperty = (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( - TEST_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(*) -#undef TEST_TRANSITIVE_PROPERTY_METHOD + this->TopIsTransitiveProperty = + this->Target->IsTransitiveProperty(this->Property, contextLG) + .has_value(); } this->CheckResult = this->CheckGraph(); @@ -169,6 +169,12 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s; } +bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const +{ + return this->Property == "SOURCES"_s || + this->Property == "INTERFACE_SOURCES"_s; +} + bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const { cm::string_view property(this->Top->Property); @@ -222,39 +228,3 @@ cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const { return this->Top->Target; } - -enum class TransitiveProperty -{ -#define DEFINE_ENUM_ENTRY(NAME) NAME, - CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY) -#undef DEFINE_ENUM_ENTRY - Terminal -}; - -template <TransitiveProperty> -bool additionalTest(const char* const /*unused*/) -{ - return false; -} - -template <> -bool additionalTest<TransitiveProperty::COMPILE_DEFINITIONS>( - const char* const prop) -{ - return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_"); -} - -#define DEFINE_TRANSITIVE_PROPERTY_METHOD(METHOD, PROPERTY) \ - bool cmGeneratorExpressionDAGChecker::METHOD() const \ - { \ - const char* const prop = this->Property.c_str(); \ - if (strcmp(prop, #PROPERTY) == 0 || \ - strcmp(prop, "INTERFACE_" #PROPERTY) == 0) { \ - return true; \ - } \ - return additionalTest<TransitiveProperty::PROPERTY>(prop); \ - } - -CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD) - -#undef DEFINE_TRANSITIVE_PROPERTY_METHOD diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index 068ba6b..b230188 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -13,33 +13,7 @@ struct GeneratorExpressionContent; struct cmGeneratorExpressionContext; class cmGeneratorTarget; - -#define CM_SELECT_BOTH(F, A1, A2) F(A1, A2) -#define CM_SELECT_FIRST(F, A1, A2) F(A1) -#define CM_SELECT_SECOND(F, A1, A2) F(A2) - -#define CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, SELECT) \ - SELECT(F, EvaluatingIncludeDirectories, INCLUDE_DIRECTORIES) \ - SELECT(F, EvaluatingSystemIncludeDirectories, SYSTEM_INCLUDE_DIRECTORIES) \ - SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS) \ - SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \ - SELECT(F, EvaluatingAutoMocMacroNames, AUTOMOC_MACRO_NAMES) \ - SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \ - SELECT(F, EvaluatingSources, SOURCES) \ - SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \ - SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \ - SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \ - SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS) \ - SELECT(F, EvaluatingPrecompileHeaders, PRECOMPILE_HEADERS) - -#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \ - CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH) - -#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F) \ - CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_FIRST) - -#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F) \ - CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_SECOND) +class cmLocalGenerator; struct cmGeneratorExpressionDAGChecker { @@ -47,11 +21,13 @@ struct cmGeneratorExpressionDAGChecker cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* parent); + cmGeneratorExpressionDAGChecker* parent, + cmLocalGenerator const* contextLG); cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target, std::string property, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* parent); + cmGeneratorExpressionDAGChecker* parent, + cmLocalGenerator const* contextLG); enum Result { @@ -83,11 +59,7 @@ struct cmGeneratorExpressionDAGChecker bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr, ForGenex genex = ForGenex::ANY) const; -#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const; - - CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD) - -#undef DECLARE_TRANSITIVE_PROPERTY_METHOD + bool EvaluatingSources() const; bool GetTransitivePropertiesOnly() const; void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 0df086b..b9feb87 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -487,7 +487,8 @@ protected: if (context->HeadTarget) { cmGeneratorExpressionDAGChecker dagChecker( context->Backtrace, context->HeadTarget, - genexOperator + ":" + expression, content, dagCheckerParent); + genexOperator + ":" + expression, content, dagCheckerParent, + context->LG); switch (dagChecker.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: { @@ -2700,7 +2701,8 @@ static const struct DeviceLinkNode : public cmGeneratorExpressionNode static std::string getLinkedTargetsContent( cmGeneratorTarget const* target, std::string const& prop, cmGeneratorExpressionContext* context, - cmGeneratorExpressionDAGChecker* dagChecker) + cmGeneratorExpressionDAGChecker* dagChecker, + cmGeneratorTarget::LinkInterfaceFor interfaceFor) { std::string result; if (cmLinkImplementationLibraries const* impl = @@ -2716,8 +2718,7 @@ static std::string getLinkedTargetsContent( target, context->EvaluateForBuildsystem, lib.Backtrace, context->Language); std::string libResult = lib.Target->EvaluateInterfaceProperty( - prop, &libContext, dagChecker, - cmGeneratorTarget::LinkInterfaceFor::Usage); + prop, &libContext, dagChecker, interfaceFor); if (!libResult.empty()) { if (result.empty()) { result = std::move(libResult); @@ -2875,25 +2876,15 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode std::string interfacePropertyName; bool isInterfaceProperty = false; + cmGeneratorTarget::LinkInterfaceFor interfaceFor = + cmGeneratorTarget::LinkInterfaceFor::Usage; -#define POPULATE_INTERFACE_PROPERTY_NAME(prop) \ - if (propertyName == #prop) { \ - interfacePropertyName = "INTERFACE_" #prop; \ - } else if (propertyName == "INTERFACE_" #prop) { \ - interfacePropertyName = "INTERFACE_" #prop; \ - isInterfaceProperty = true; \ - } else - - CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME) - // Note that the above macro terminates with an else - /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) { - cmPolicies::PolicyStatus polSt = - context->LG->GetPolicyStatus(cmPolicies::CMP0043); - if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { - interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS"; - } + if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp = + target->IsTransitiveProperty(propertyName, context->LG)) { + interfacePropertyName = std::string(transitiveProp->InterfaceName); + isInterfaceProperty = transitiveProp->InterfaceName == propertyName; + interfaceFor = transitiveProp->InterfaceFor; } -#undef POPULATE_INTERFACE_PROPERTY_NAME bool evaluatingLinkLibraries = false; @@ -2916,20 +2907,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode return std::string(); } } else { - assert(dagCheckerParent - ->EvaluatingTransitiveProperty()); // NOLINT(clang-tidy) + assert(dagCheckerParent->EvaluatingTransitiveProperty()); } } if (isInterfaceProperty) { return cmGeneratorExpression::StripEmptyListElements( - target->EvaluateInterfaceProperty( - propertyName, context, dagCheckerParent, - cmGeneratorTarget::LinkInterfaceFor::Usage)); + target->EvaluateInterfaceProperty(propertyName, context, + dagCheckerParent, interfaceFor)); } - cmGeneratorExpressionDAGChecker dagChecker( - context->Backtrace, target, propertyName, content, dagCheckerParent); + cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target, + propertyName, content, + dagCheckerParent, context->LG); switch (dagChecker.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: @@ -3011,7 +3001,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode this->EvaluateDependentExpression(result, context->LG, context, target, &dagChecker, target)); std::string linkedTargetsContent = getLinkedTargetsContent( - target, interfacePropertyName, context, &dagChecker); + target, interfacePropertyName, context, &dagChecker, interfaceFor); if (!linkedTargetsContent.empty()) { result += (result.empty() ? "" : ";") + linkedTargetsContent; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 5861dc5..75f3b6d 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -65,6 +65,7 @@ namespace { using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor; +using TransitiveProperty = cmGeneratorTarget::TransitiveProperty; const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES"; const std::string kINTERFACE_LINK_LIBRARIES_DIRECT = @@ -73,6 +74,33 @@ const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE = "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"; } +const std::map<cm::string_view, TransitiveProperty> + cmGeneratorTarget::BuiltinTransitiveProperties = { + { "AUTOMOC_MACRO_NAMES"_s, + { "INTERFACE_AUTOMOC_MACRO_NAMES"_s, LinkInterfaceFor::Usage } }, + { "AUTOUIC_OPTIONS"_s, + { "INTERFACE_AUTOUIC_OPTIONS"_s, LinkInterfaceFor::Usage } }, + { "COMPILE_DEFINITIONS"_s, + { "INTERFACE_COMPILE_DEFINITIONS"_s, LinkInterfaceFor::Usage } }, + { "COMPILE_FEATURES"_s, + { "INTERFACE_COMPILE_FEATURES"_s, LinkInterfaceFor::Usage } }, + { "COMPILE_OPTIONS"_s, + { "INTERFACE_COMPILE_OPTIONS"_s, LinkInterfaceFor::Usage } }, + { "INCLUDE_DIRECTORIES"_s, + { "INTERFACE_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } }, + { "LINK_DEPENDS"_s, + { "INTERFACE_LINK_DEPENDS"_s, LinkInterfaceFor::Link } }, + { "LINK_DIRECTORIES"_s, + { "INTERFACE_LINK_DIRECTORIES"_s, LinkInterfaceFor::Link } }, + { "LINK_OPTIONS"_s, + { "INTERFACE_LINK_OPTIONS"_s, LinkInterfaceFor::Link } }, + { "PRECOMPILE_HEADERS"_s, + { "INTERFACE_PRECOMPILE_HEADERS"_s, LinkInterfaceFor::Usage } }, + { "SOURCES"_s, { "INTERFACE_SOURCES"_s, LinkInterfaceFor::Usage } }, + { "SYSTEM_INCLUDE_DIRECTORIES"_s, + { "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } }, + }; + template <> cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( cmGeneratorTarget const* tgt, cmMakefile const& /* mf */) @@ -887,7 +915,7 @@ std::string cmGeneratorTarget::GetLinkerTypeProperty( auto linkerType = this->GetProperty(propName); if (!linkerType.IsEmpty()) { cmGeneratorExpressionDAGChecker dagChecker(this, propName, nullptr, - nullptr); + nullptr, this->LocalGenerator); auto ltype = cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(), config, this, &dagChecker, this, lang); @@ -1352,7 +1380,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( if (iter == this->SystemIncludesCache.end()) { cmGeneratorExpressionDAGChecker dagChecker( - this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr); + this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr, + this->LocalGenerator); bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED"); @@ -1460,7 +1489,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( // a subset of TargetPropertyNode::Evaluate without stringify/parse steps // but sufficient for transitive interface properties. cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop, - nullptr, dagCheckerParent); + nullptr, dagCheckerParent, + this->LocalGenerator); switch (dagChecker.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: dagChecker.ReportError( @@ -1525,6 +1555,38 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( return result; } +cm::optional<cmGeneratorTarget::TransitiveProperty> +cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop, + cmLocalGenerator const* lg) const +{ + cm::optional<TransitiveProperty> result; + static const cm::string_view kINTERFACE_ = "INTERFACE_"_s; + if (cmHasPrefix(prop, kINTERFACE_)) { + prop = prop.substr(kINTERFACE_.length()); + } + auto i = BuiltinTransitiveProperties.find(prop); + if (i != BuiltinTransitiveProperties.end()) { + result = i->second; + if (result->InterfaceFor != cmGeneratorTarget::LinkInterfaceFor::Usage) { + cmPolicies::PolicyStatus cmp0166 = + lg->GetPolicyStatus(cmPolicies::CMP0166); + if ((cmp0166 == cmPolicies::WARN || cmp0166 == cmPolicies::OLD) && + (prop == "LINK_DIRECTORIES"_s || prop == "LINK_DEPENDS"_s || + prop == "LINK_OPTIONS"_s)) { + result->InterfaceFor = cmGeneratorTarget::LinkInterfaceFor::Usage; + } + } + } else if (cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_")) { + cmPolicies::PolicyStatus cmp0043 = + lg->GetPolicyStatus(cmPolicies::CMP0043); + if (cmp0043 == cmPolicies::WARN || cmp0043 == cmPolicies::OLD) { + result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s, + LinkInterfaceFor::Usage }; + } + } + return result; +} + namespace { enum class IncludeDirectoryFallBack @@ -1539,8 +1601,10 @@ std::string AddLangSpecificInterfaceIncludeDirectories( const std::string& propertyName, IncludeDirectoryFallBack mode, cmGeneratorExpressionDAGChecker* context) { - cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, - propertyName, nullptr, context }; + cmGeneratorExpressionDAGChecker dag{ + target->GetBacktrace(), target, propertyName, nullptr, context, + target->GetLocalGenerator() + }; switch (dag.Check()) { case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: dag.ReportError( @@ -1590,8 +1654,10 @@ void AddLangSpecificImplicitIncludeDirectories( { if (const auto* libraries = target->GetLinkImplementationLibraries( config, LinkInterfaceFor::Usage)) { - cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, - propertyName, nullptr, nullptr }; + cmGeneratorExpressionDAGChecker dag{ + target->GetBacktrace(), target, propertyName, nullptr, nullptr, + target->GetLocalGenerator() + }; for (const cmLinkImplItem& library : libraries->Libraries) { if (const cmGeneratorTarget* dependency = library.Target) { @@ -1843,8 +1909,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( this->DebugSourcesDone = true; } - cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, - nullptr); + cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr, + this->LocalGenerator); EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( this, config, std::string(), &dagChecker, this->SourceEntries); @@ -3058,7 +3124,7 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result, } cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr, - nullptr); + nullptr, this->LocalGenerator); cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator, config, this, &dagChecker), result); @@ -3858,8 +3924,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( std::vector<BT<std::string>> includes; std::unordered_set<std::string> uniqueIncludes; - cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES", - nullptr, nullptr); + cmGeneratorExpressionDAGChecker dagChecker( + this, "INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -4123,7 +4189,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr, - nullptr); + nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -4164,7 +4230,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( std::unordered_set<std::string> uniqueFeatures; cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr, - nullptr); + nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -4213,8 +4279,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( std::vector<BT<std::string>> list; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS", - nullptr, nullptr); + cmGeneratorExpressionDAGChecker dagChecker( + this, "COMPILE_DEFINITIONS", nullptr, nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -4277,8 +4343,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( } std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS", - nullptr, nullptr); + cmGeneratorExpressionDAGChecker dagChecker( + this, "PRECOMPILE_HEADERS", nullptr, nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -4681,7 +4747,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr, - nullptr); + nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -4849,8 +4915,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; - cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS", - nullptr, nullptr); + cmGeneratorExpressionDAGChecker dagChecker( + this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr, this->LocalGenerator); EvaluatedTargetPropertyEntries entries; if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { @@ -4963,7 +5029,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( std::unordered_set<std::string> uniqueDirectories; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr, - nullptr); + nullptr, this->LocalGenerator); cmList debugProperties{ this->Makefile->GetDefinition( "CMAKE_DEBUG_TARGET_PROPERTIES") }; @@ -5007,7 +5073,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr, - nullptr); + nullptr, this->LocalGenerator); EvaluatedTargetPropertyEntries entries; if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) { @@ -6993,7 +7059,8 @@ void cmGeneratorTarget::ExpandLinkItems( return; } // Keep this logic in sync with ComputeLinkImplementationLibraries. - cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr); + cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr, + this->LocalGenerator); // The $<LINK_ONLY> expression may be in a link interface to specify // private link dependencies that are otherwise excluded from usage // requirements. @@ -8668,7 +8735,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( for (auto const& entry : entryRange) { // Keep this logic in sync with ExpandLinkItems. cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr, - nullptr); + nullptr, this->LocalGenerator); // The $<LINK_ONLY> expression may be used to specify link dependencies // that are otherwise excluded from usage requirements. if (implFor == LinkInterfaceFor::Usage) { @@ -9640,11 +9707,25 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, return true; } + auto targetDyndep = this->NeedCxxDyndep(config); + if (targetDyndep == CxxModuleSupport::Unavailable) { + return false; + } + auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); + if (sfProp.IsSet()) { + return sfProp.IsOn(); + } + return targetDyndep == CxxModuleSupport::Enabled; +} + +cmGeneratorTarget::CxxModuleSupport cmGeneratorTarget::NeedCxxDyndep( + std::string const& config) const +{ bool haveRule = false; switch (this->HaveCxxModuleSupport(config)) { case Cxx20SupportLevel::MissingCxx: case Cxx20SupportLevel::NoCxx20: - return false; + return CxxModuleSupport::Unavailable; case Cxx20SupportLevel::MissingRule: break; case Cxx20SupportLevel::Supported: @@ -9654,28 +9735,29 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, bool haveGeneratorSupport = this->GetGlobalGenerator()->CheckCxxModuleSupport( cmGlobalGenerator::CxxModuleSupportQuery::Inspect); - auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); - if (sfProp.IsSet()) { - return sfProp.IsOn(); - } auto const tgtProp = this->GetProperty("CXX_SCAN_FOR_MODULES"); if (tgtProp.IsSet()) { - return tgtProp.IsOn(); + return tgtProp.IsOn() ? CxxModuleSupport::Enabled + : CxxModuleSupport::Disabled; } - bool policyAnswer = false; + CxxModuleSupport policyAnswer = CxxModuleSupport::Unavailable; switch (this->GetPolicyStatusCMP0155()) { case cmPolicies::WARN: case cmPolicies::OLD: // The OLD behavior is to not scan the source. - policyAnswer = false; + policyAnswer = CxxModuleSupport::Disabled; break; case cmPolicies::REQUIRED_ALWAYS: case cmPolicies::REQUIRED_IF_USED: case cmPolicies::NEW: // The NEW behavior is to scan the source if the compiler supports // scanning and the generator supports it. - policyAnswer = haveRule && haveGeneratorSupport; + if (haveRule && haveGeneratorSupport) { + policyAnswer = CxxModuleSupport::Enabled; + } else { + policyAnswer = CxxModuleSupport::Disabled; + } break; } return policyAnswer; diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 9e5cef0..5c7201d 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -15,6 +15,7 @@ #include <vector> #include <cm/optional> +#include <cm/string_view> #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" @@ -888,6 +889,18 @@ public: cmGeneratorExpressionDAGChecker* dagCheckerParent, LinkInterfaceFor interfaceFor) const; + struct TransitiveProperty + { + cm::string_view InterfaceName; + LinkInterfaceFor InterfaceFor; + }; + + static const std::map<cm::string_view, TransitiveProperty> + BuiltinTransitiveProperties; + + cm::optional<TransitiveProperty> IsTransitiveProperty( + cm::string_view prop, cmLocalGenerator const* lg) const; + bool HaveInstallTreeRPATH(const std::string& config) const; bool GetBuildRPATH(const std::string& config, std::string& rpath) const; @@ -1344,6 +1357,13 @@ public: cmSourceFile const* sf) const; bool NeedDyndepForSource(std::string const& lang, std::string const& config, cmSourceFile const* sf) const; + enum class CxxModuleSupport + { + Unavailable, + Enabled, + Disabled, + }; + CxxModuleSupport NeedCxxDyndep(std::string const& config) const; private: void BuildFileSetInfoCache(std::string const& config) const; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index ada87dd..eb9f031 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -294,8 +294,8 @@ class cmMakefile; "FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \ 17, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0099, \ - "Link properties are transitive over private dependency on static " \ - "libraries.", \ + "Link properties are transitive over private dependencies of " \ + "static libraries.", \ 3, 17, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3, \ 17, 0, cmPolicies::WARN) \ @@ -508,7 +508,11 @@ class cmMakefile; 3, 30, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0165, \ "enable_language() must not be called before project().", 3, 30, 0, \ - cmPolicies::WARN) + cmPolicies::WARN) \ + SELECT(POLICY, CMP0166, \ + "TARGET_PROPERTY evaluates link properties transitively over " \ + "private dependencies of static libraries.", \ + 3, 30, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 0ccebfd..34a47cc 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1918,8 +1918,9 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode); info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix); - cmGeneratorExpressionDAGChecker dagChecker( - this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr); + cmGeneratorExpressionDAGChecker dagChecker(this->GenTarget, + "AUTOMOC_MACRO_NAMES", nullptr, + nullptr, this->LocalGen); EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries; if (this->MultiConfig) { diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index bca4719..0fb8bae 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -281,6 +281,16 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); this->NsightTegra = gg->IsNsightTegra(); this->Android = gg->TargetsAndroid(); + auto scanProp = target->GetProperty("CXX_SCAN_FOR_MODULES"); + for (auto const& config : this->Configurations) { + if (scanProp.IsSet()) { + this->ScanSourceForModuleDependencies[config] = scanProp.IsOn(); + } else { + this->ScanSourceForModuleDependencies[config] = + target->NeedCxxDyndep(config) == + cmGeneratorTarget::CxxModuleSupport::Enabled; + } + } for (unsigned int& version : this->NsightTegraVersion) { version = 0; } @@ -2074,6 +2084,18 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms"); } } + { + if (cmValue p = this->GeneratorTarget->GetProperty("VS_FILTER_PROPS")) { + auto props = *p; + if (!props.empty()) { + ConvertToWindowsSlash(props); + Elem(e0, "Import") + .Attribute("Project", props) + .Attribute("Condition", cmStrCat("exists('", props, "')")) + .Attribute("Label", "LocalAppDataPlatform"); + } + } + } } fout << '\n'; @@ -2860,7 +2882,9 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || !includes.empty() || compileAsPerConfig || noWinRT || - !options.empty() || needsPCHFlags || shouldScanForModules) { + !options.empty() || needsPCHFlags || + (shouldScanForModules != + this->ScanSourceForModuleDependencies[config])) { cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); @@ -2888,8 +2912,10 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( if (compileAsPerConfig) { clOptions.AddFlag("CompileAs", compileAsPerConfig); } - if (shouldScanForModules) { - clOptions.AddFlag("ScanSourceForModuleDependencies", "true"); + if (shouldScanForModules != + this->ScanSourceForModuleDependencies[config]) { + clOptions.AddFlag("ScanSourceForModuleDependencies", + shouldScanForModules ? "true" : "false"); } if (noWinRT) { clOptions.AddFlag("CompileAsWinRT", "false"); @@ -3629,8 +3655,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } } - // Disable C++ source scanning by default. - e2.Element("ScanSourceForModuleDependencies", "false"); + e2.Element("ScanSourceForModuleDependencies", + this->ScanSourceForModuleDependencies[configName] ? "true" + : "false"); } bool cmVisualStudio10TargetGenerator::ComputeRcOptions() diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index bafd5e9..056f426 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -240,6 +240,7 @@ private: bool NsightTegra; bool Android; bool HaveCustomCommandDepfile = false; + std::map<std::string, bool> ScanSourceForModuleDependencies; unsigned int NsightTegraVersion[4]; bool TargetCompileAsWinRT; std::set<std::string> IPOEnabledConfigurations; diff --git a/Tests/FindOpenMP/Test/CMakeLists.txt b/Tests/FindOpenMP/Test/CMakeLists.txt index ebdb6b8..7ead835 100644 --- a/Tests/FindOpenMP/Test/CMakeLists.txt +++ b/Tests/FindOpenMP/Test/CMakeLists.txt @@ -26,8 +26,21 @@ foreach(c C CXX Fortran) endif() endforeach() +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" + AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30 + AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") + set(test_msvc_runtime 1) + set(OpenMP_RUNTIME_MSVC "llvm") +endif() + find_package(OpenMP REQUIRED) +if(test_msvc_runtime) + if(NOT OpenMP_C_FLAGS STREQUAL "-openmp:llvm") + message(FATAL_ERROR "OpenMP_RUNTIME_MSVC='${OpenMP_RUNTIME_MSVC}' not honored: '${OpenMP_C_FLAGS}'") + endif() +endif() + foreach(c C CXX Fortran) if(NOT "${OpenMP_TEST_${c}}") continue() diff --git a/Tests/RunCMake/FPHSA/BadFoundVar-stderr.txt b/Tests/RunCMake/FPHSA/BadFoundVar-stderr.txt index 4c739d8..3ae1ba7 100644 --- a/Tests/RunCMake/FPHSA/BadFoundVar-stderr.txt +++ b/Tests/RunCMake/FPHSA/BadFoundVar-stderr.txt @@ -2,6 +2,6 @@ CMake Error at .*/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\) The argument for FOUND_VAR is "badfoundvar_FOUND", but only "BadFoundVar_FOUND" and "BADFOUNDVAR_FOUND" are valid names. Call Stack \(most recent call first\): - FindBadFoundVar.cmake:5 \(find_package_handle_standard_args\) - BadFoundVar.cmake:3 \(find_package\) - CMakeLists.txt:3 \(include\) + FindBadFoundVar.cmake:[0-9]+ \(find_package_handle_standard_args\) + BadFoundVar.cmake:[0-9]+ \(find_package\) + CMakeLists.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/FPHSA/BeforeProject-Error-result.txt b/Tests/RunCMake/FPHSA/BeforeProject-Error-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/FPHSA/BeforeProject-Error-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FPHSA/BeforeProject-Error-stderr.txt b/Tests/RunCMake/FPHSA/BeforeProject-Error-stderr.txt new file mode 100644 index 0000000..c8e53fc --- /dev/null +++ b/Tests/RunCMake/FPHSA/BeforeProject-Error-stderr.txt @@ -0,0 +1,12 @@ +^CMake Error at [^ +]*/Modules/FindPackageHandleStandardArgs\.cmake:[0-9]+ \(message\): + Could NOT find BeforeProject \(missing: SOME_VAR\) + + Hint: The project\(\) command has not yet been called\. It sets up + system-specific search paths\. +Call Stack \(most recent call first\): + [^ +]*/Modules/FindPackageHandleStandardArgs\.cmake:[0-9]+ \(_FPHSA_FAILURE_MESSAGE\) + FindBeforeProject\.cmake:[0-9]+ \(find_package_handle_standard_args\) + BeforeProject-Error\.cmake:[0-9]+ \(find_package\) + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/FPHSA/BeforeProject-Error.cmake b/Tests/RunCMake/FPHSA/BeforeProject-Error.cmake new file mode 100644 index 0000000..53a8073 --- /dev/null +++ b/Tests/RunCMake/FPHSA/BeforeProject-Error.cmake @@ -0,0 +1,2 @@ +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") +find_package(BeforeProject REQUIRED) diff --git a/Tests/RunCMake/FPHSA/BeforeProject-Missing-stdout.txt b/Tests/RunCMake/FPHSA/BeforeProject-Missing-stdout.txt new file mode 100644 index 0000000..05df0b0 --- /dev/null +++ b/Tests/RunCMake/FPHSA/BeforeProject-Missing-stdout.txt @@ -0,0 +1,2 @@ +-- Could NOT find BeforeProject \(missing: SOME_VAR\)[ ]* +Hint: The project\(\) command has not yet been called\. It sets up system-specific search paths\. diff --git a/Tests/RunCMake/FPHSA/BeforeProject-Missing.cmake b/Tests/RunCMake/FPHSA/BeforeProject-Missing.cmake new file mode 100644 index 0000000..8d44ca9 --- /dev/null +++ b/Tests/RunCMake/FPHSA/BeforeProject-Missing.cmake @@ -0,0 +1,2 @@ +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") +find_package(BeforeProject) diff --git a/Tests/RunCMake/FPHSA/CMakeLists.txt b/Tests/RunCMake/FPHSA/CMakeLists.txt index 93ee9df..dc34259 100644 --- a/Tests/RunCMake/FPHSA/CMakeLists.txt +++ b/Tests/RunCMake/FPHSA/CMakeLists.txt @@ -1,3 +1,8 @@ cmake_minimum_required(VERSION 3.5) +if(RunCMake_TEST MATCHES "^BeforeProject") + include(${RunCMake_TEST}.cmake) + project(${RunCMake_TEST} NONE) + return() +endif() project(${RunCMake_TEST} NONE) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/FPHSA/FindBeforeProject.cmake b/Tests/RunCMake/FPHSA/FindBeforeProject.cmake new file mode 100644 index 0000000..6bf49f1 --- /dev/null +++ b/Tests/RunCMake/FPHSA/FindBeforeProject.cmake @@ -0,0 +1,3 @@ +set(SOME_VAR FALSE) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(BeforeProject REQUIRED_VARS SOME_VAR) diff --git a/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt b/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt index 722b50b..8ee6ec1 100644 --- a/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt +++ b/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt @@ -5,9 +5,9 @@ CMake Warning \(dev\) at .*/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \ `find_package` result variables \(e.g., `_FOUND`\) to follow a certain pattern. Call Stack \(most recent call first\): - FindNameMismatch.cmake:3 \(find_package_handle_standard_args\) - NameMismatch.cmake:3 \(find_package\) - CMakeLists.txt:3 \(include\) + FindNameMismatch.cmake:[0-9]+ \(find_package_handle_standard_args\) + NameMismatch.cmake:[0-9]+ \(find_package\) + CMakeLists.txt:[0-9]+ \(include\) This warning is for project developers. Use -Wno-dev to suppress it. CMake Warning \(dev\) at .*/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\): @@ -17,7 +17,7 @@ CMake Warning \(dev\) at .*/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \ `find_package` result variables \(e.g., `_FOUND`\) to follow a certain pattern. Call Stack \(most recent call first\): - FindNameMismatchOld.cmake:3 \(find_package_handle_standard_args\) - NameMismatch.cmake:4 \(find_package\) - CMakeLists.txt:3 \(include\) + FindNameMismatchOld.cmake:[0-9]+ \(find_package_handle_standard_args\) + NameMismatch.cmake:[0-9]+ \(find_package\) + CMakeLists.txt:[0-9]+ \(include\) This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake index 3b095a6..be9b127 100644 --- a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake +++ b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake @@ -1,6 +1,8 @@ include(RunCMake) run_cmake(BadFoundVar) +run_cmake(BeforeProject-Error) +run_cmake(BeforeProject-Missing) run_cmake(NameMismatch) # The pseudo module will "find" a package with the given version. Check if the diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt index 32d92d8..5791993 100644 --- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.17) if(RunCMake_TEST STREQUAL "LOCATION") cmake_minimum_required(VERSION 2.8.12) # Leave CMP0026 unset. endif() project(${RunCMake_TEST} NONE) -include(${RunCMake_TEST}.cmake) +include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake index b613ad1..07052eb 100644 --- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake @@ -13,6 +13,9 @@ run_cmake(LinkImplementationCycle5) run_cmake(LinkImplementationCycle6) run_cmake(LOCATION) run_cmake(SOURCES) +run_cmake(TransitiveBuild) +run_cmake(TransitiveLink-CMP0166-OLD) +run_cmake(TransitiveLink-CMP0166-NEW) block() run_cmake(Scope) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake new file mode 100644 index 0000000..65adfaf --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake @@ -0,0 +1,25 @@ +set(expect [[ +# file\(GENERATE\) produced: +main INCLUDE_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1' +main SYSTEM_INCLUDE_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/sys1' +main COMPILE_DEFINITIONS: 'DEFM;DEF1' +main COMPILE_FEATURES: 'cxx_std_20;cxx_std_11' +main COMPILE_OPTIONS: '-optM;-opt1' +main PRECOMPILE_HEADERS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h' +main SOURCES: 'main.c;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c' +main AUTOMOC_MACRO_NAMES: 'MOCM;MOC1' +main AUTOUIC_OPTIONS: '-uicM;-uic1' +]]) + +string(REGEX REPLACE "\r\n" "\n" expect "${expect}") +string(REGEX REPLACE "\n+$" "" expect "${expect}") + +file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" actual) +string(REGEX REPLACE "\r\n" "\n" actual "${actual}") +string(REGEX REPLACE "\n+$" "" actual "${actual}") + +if(NOT actual MATCHES "^${expect}$") + string(REPLACE "\n" "\n expect> " expect " expect> ${expect}") + string(REPLACE "\n" "\n actual> " actual " actual> ${actual}") + message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}") +endif() diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake new file mode 100644 index 0000000..8f8eb96 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake @@ -0,0 +1,66 @@ +enable_language(C) +set(CMAKE_PCH_EXTENSION "") # suppress cmake_pch from SOURCES + +add_library(foo1 STATIC empty.c) +target_link_libraries(foo1 PRIVATE foo2 foo3) +target_include_directories(foo1 INTERFACE dir1) +target_compile_definitions(foo1 INTERFACE DEF1) +target_compile_features(foo1 INTERFACE cxx_std_11) +target_compile_options(foo1 INTERFACE -opt1) +target_precompile_headers(foo1 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty1.h") +target_sources(foo1 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty1.c") +set_target_properties(foo1 PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys1" + INTERFACE_AUTOMOC_MACRO_NAMES "MOC1" + INTERFACE_AUTOUIC_OPTIONS "-uic1" + ) + +add_library(foo2 STATIC empty.c) +target_include_directories(foo2 INTERFACE dir2) +target_compile_definitions(foo2 INTERFACE DEF2) +target_compile_features(foo2 INTERFACE cxx_std_14) +target_compile_options(foo2 INTERFACE -opt2) +target_precompile_headers(foo2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty2.h") +target_sources(foo2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty2.c") +set_target_properties(foo2 PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys2" + INTERFACE_AUTOMOC_MACRO_NAMES "MOC2" + INTERFACE_AUTOUIC_OPTIONS "-uic2" + ) + +add_library(foo3 STATIC empty.c) +target_include_directories(foo3 PRIVATE dir3) +target_compile_definitions(foo3 PRIVATE DEF3) +target_compile_features(foo3 PRIVATE cxx_std_17) +target_compile_options(foo3 PRIVATE -opt3) +target_precompile_headers(foo3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty3.h") +target_sources(foo3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty3.c") +set_target_properties(foo3 PROPERTIES + SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys3" + AUTOMOC_MACRO_NAMES "MOC3" + AUTOUIC_OPTIONS "-uic3" + ) + +add_executable(main main.c) +target_link_libraries(main PRIVATE foo1) +target_include_directories(main PRIVATE dirM) +target_compile_definitions(main PRIVATE DEFM) +target_compile_features(main PRIVATE cxx_std_20) +target_compile_options(main PRIVATE -optM) +target_precompile_headers(main PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty.h") +set_target_properties(main PROPERTIES + AUTOMOC_MACRO_NAMES "MOCM" + AUTOUIC_OPTIONS "-uicM" + ) + +file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced: +main INCLUDE_DIRECTORIES: '$<TARGET_PROPERTY:main,INCLUDE_DIRECTORIES>' +main SYSTEM_INCLUDE_DIRECTORIES: '$<TARGET_PROPERTY:main,SYSTEM_INCLUDE_DIRECTORIES>' +main COMPILE_DEFINITIONS: '$<TARGET_PROPERTY:main,COMPILE_DEFINITIONS>' +main COMPILE_FEATURES: '$<TARGET_PROPERTY:main,COMPILE_FEATURES>' +main COMPILE_OPTIONS: '$<TARGET_PROPERTY:main,COMPILE_OPTIONS>' +main PRECOMPILE_HEADERS: '$<TARGET_PROPERTY:main,PRECOMPILE_HEADERS>' +main SOURCES: '$<TARGET_PROPERTY:main,SOURCES>' +main AUTOMOC_MACRO_NAMES: '$<TARGET_PROPERTY:main,AUTOMOC_MACRO_NAMES>' +main AUTOUIC_OPTIONS: '$<TARGET_PROPERTY:main,AUTOUIC_OPTIONS>' +") diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake new file mode 100644 index 0000000..7ea95b8 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake @@ -0,0 +1,8 @@ +set(expect [[ +# file\(GENERATE\) produced: +main LINK_LIBRARIES: 'foo1' # not transitive +main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir2' +main LINK_OPTIONS: '-optM;-opt1;-opt2' +main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/dep1;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/dep2' +]]) +include(${CMAKE_CURRENT_LIST_DIR}/TransitiveLink-check-common.cmake) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake new file mode 100644 index 0000000..658dd84 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0166 NEW) +include(TransitiveLink-common.cmake) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake new file mode 100644 index 0000000..2d430c2 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake @@ -0,0 +1,8 @@ +set(expect [[ +# file\(GENERATE\) produced: +main LINK_LIBRARIES: 'foo1' # not transitive +main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1' +main LINK_OPTIONS: '-optM;-opt1' +main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-build/dep1' +]]) +include(${CMAKE_CURRENT_LIST_DIR}/TransitiveLink-check-common.cmake) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake new file mode 100644 index 0000000..a4a4599 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0166 OLD) +include(TransitiveLink-common.cmake) diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake new file mode 100644 index 0000000..42e63bc --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake @@ -0,0 +1,12 @@ +string(REGEX REPLACE "\r\n" "\n" expect "${expect}") +string(REGEX REPLACE "\n+$" "" expect "${expect}") + +file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" actual) +string(REGEX REPLACE "\r\n" "\n" actual "${actual}") +string(REGEX REPLACE "\n+$" "" actual "${actual}") + +if(NOT actual MATCHES "^${expect}$") + string(REPLACE "\n" "\n expect> " expect " expect> ${expect}") + string(REPLACE "\n" "\n actual> " actual " actual> ${actual}") + message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}") +endif() diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake new file mode 100644 index 0000000..c120366 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake @@ -0,0 +1,42 @@ +enable_language(C) + +add_library(foo1 STATIC empty.c) +target_link_libraries(foo1 PRIVATE foo2 foo3) +target_link_directories(foo1 INTERFACE dir1) +target_link_options(foo1 INTERFACE -opt1) +set_target_properties(foo1 PROPERTIES + INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep1" + ) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep1" "") + +add_library(foo2 STATIC empty.c) +target_link_directories(foo2 INTERFACE dir2) +target_link_options(foo2 INTERFACE -opt2) +set_target_properties(foo2 PROPERTIES + INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep2" + ) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep2" "") + +add_library(foo3 STATIC empty.c) +target_link_directories(foo3 PRIVATE dir3) +target_link_options(foo3 PRIVATE -opt3) +set_target_properties(foo3 PROPERTIES + LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep3" + ) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep3" "") + +add_executable(main main.c) +target_link_libraries(main PRIVATE foo1) +target_link_directories(main PRIVATE dirM) +target_link_options(main PRIVATE -optM) +set_target_properties(main PROPERTIES + LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/depM" + ) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/depM" "") + +file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced: +main LINK_LIBRARIES: '$<TARGET_PROPERTY:main,LINK_LIBRARIES>' # not transitive +main LINK_DIRECTORIES: '$<TARGET_PROPERTY:main,LINK_DIRECTORIES>' +main LINK_OPTIONS: '$<TARGET_PROPERTY:main,LINK_OPTIONS>' +main LINK_DEPENDS: '$<TARGET_PROPERTY:main,LINK_DEPENDS>' +") diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/VS10Project/VsCustomProps-check.cmake b/Tests/RunCMake/VS10Project/VsCustomProps-check.cmake index 22a3df0..ad585d5 100644 --- a/Tests/RunCMake/VS10Project/VsCustomProps-check.cmake +++ b/Tests/RunCMake/VS10Project/VsCustomProps-check.cmake @@ -1,25 +1,30 @@ -set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") -if(NOT EXISTS "${vcProjectFile}") - set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") - return() -endif() +macro(check_custom_prop suffix) + set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj${suffix}") + if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() + endif() -set(importFound FALSE) + set(importFound FALSE) -set(props_file "${RunCMake_SOURCE_DIR}/my.props") -file(TO_NATIVE_PATH "${props_file}" check_file) -file(STRINGS "${vcProjectFile}" lines) -foreach(line IN LISTS lines) - if(line MATCHES "^ *<Import Project=\"([^\"]+)\".*Label=\"([^\"]+)\".*$") - if("${CMAKE_MATCH_1}" STREQUAL "${check_file}" AND - "${CMAKE_MATCH_2}" STREQUAL "LocalAppDataPlatform") - message(STATUS "foo.vcxproj is importing ${check_file}") - set(importFound TRUE) + set(props_file "${RunCMake_SOURCE_DIR}/my.props") + file(TO_NATIVE_PATH "${props_file}" check_file) + file(STRINGS "${vcProjectFile}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "^ *<Import Project=\"([^\"]+)\".*Label=\"([^\"]+)\".*$") + if("${CMAKE_MATCH_1}" STREQUAL "${check_file}" AND + "${CMAKE_MATCH_2}" STREQUAL "LocalAppDataPlatform") + message(STATUS "foo.vcxproj${suffix} is importing ${check_file}") + set(importFound TRUE) + endif() endif() + endforeach() + + if(NOT importFound) + set(RunCMake_TEST_FAILED "Import of custom .props file not found.") + return() endif() -endforeach() +endmacro() -if(NOT importFound) - set(RunCMake_TEST_FAILED "Import of custom .props file not found.") - return() -endif() +check_custom_prop("") +check_custom_prop(".filters") diff --git a/Tests/RunCMake/VS10Project/VsCustomProps.cmake b/Tests/RunCMake/VS10Project/VsCustomProps.cmake index fbbcfcf..d6c905f 100644 --- a/Tests/RunCMake/VS10Project/VsCustomProps.cmake +++ b/Tests/RunCMake/VS10Project/VsCustomProps.cmake @@ -4,4 +4,5 @@ add_library(foo foo.cpp) set(props_file "${CMAKE_CURRENT_SOURCE_DIR}/my.props") set_target_properties(foo PROPERTIES - VS_USER_PROPS "${props_file}") + VS_USER_PROPS "${props_file}" + VS_FILTER_PROPS "${props_file}") diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in index 20e1340..09a7d5a 100644 --- a/Utilities/Sphinx/conf.py.in +++ b/Utilities/Sphinx/conf.py.in @@ -98,6 +98,7 @@ linkcheck_allowed_redirects = { r'https://cdash\.org': r'https://www\.cdash\.org/', r'https://cmake.org/get-involved/': r'https://cmake.org/documentation/', r'https://docs\.nvidia\.com/cuda/': r'https://docs\.nvidia\.com/cuda/index\.html', + r'https://learn\.microsoft\.com/en-us/cpp/build/reference/openmp-enable-openmp-2-0-support': r'https://learn\.microsoft\.com/en-us/cpp/build/reference/openmp-enable-openmp-2-0-support\?.*', r'https://learn\.microsoft\.com/en-us/cpp/c-language/parsing-c-command-line-arguments': r'https://learn\.microsoft\.com/en-us/cpp/c-language/parsing-c-command-line-arguments\?.*', r'https://openjdk\.java\.net/jeps/313': r'https://openjdk\.org:443/jeps/313', r'https://www\.sphinx-doc\.org': r'https://www\.sphinx-doc\.org/en/master/', |