diff options
44 files changed, 1201 insertions, 362 deletions
diff --git a/.gitlab/ci/configure_windows_common.cmake b/.gitlab/ci/configure_windows_common.cmake index a70d165..7467cfd 100644 --- a/.gitlab/ci/configure_windows_common.cmake +++ b/.gitlab/ci/configure_windows_common.cmake @@ -2,5 +2,6 @@ set(BUILD_QtDialog ON CACHE BOOL "") set(BUILD_CursesDialog ON CACHE BOOL "") set(CMAKE_PREFIX_PATH "$ENV{CI_PROJECT_DIR}/.gitlab/qt" CACHE STRING "") set(CMake_TEST_Java OFF CACHE BOOL "") +set(Python_FIND_REGISTRY NEVER CACHE STRING "") include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake") diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml index e89dba8..f36fe6d 100644 --- a/.gitlab/os-macos.yml +++ b/.gitlab/os-macos.yml @@ -7,7 +7,7 @@ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci ext/$CI_CONCURRENT_ID" # TODO: Factor this out so that each job selects the Xcode version to # use so that different versions can be tested in a single pipeline. - DEVELOPER_DIR: "/Applications/Xcode-13.2.app/Contents/Developer" + DEVELOPER_DIR: "/Applications/Xcode-13.3.app/Contents/Developer" # Avoid conflicting with other projects running on the same machine. SCCACHE_SERVER_PORT: 4227 @@ -87,7 +87,7 @@ - cmake # Since this is a bare runner, pin to a project. - macos - shell - - xcode-13.2 + - xcode-13.3 - nonconcurrent .macos_x86_64_builder_tags_package: @@ -95,7 +95,7 @@ - cmake # Since this is a bare runner, pin to a project. - macos - shell - - xcode-13.2 + - xcode-13.3 - nonconcurrent - finder @@ -104,7 +104,7 @@ - cmake # Since this is a bare runner, pin to a project. - macos - shell - - xcode-13.2 + - xcode-13.3 - concurrent .macos_arm64_builder_tags: @@ -112,7 +112,7 @@ - cmake # Since this is a bare runner, pin to a project. - macos-arm64 - shell - - xcode-13.2 + - xcode-13.3 - nonconcurrent .macos_arm64_builder_ext_tags: @@ -120,7 +120,7 @@ - cmake # Since this is a bare runner, pin to a project. - macos-arm64 - shell - - xcode-13.2 + - xcode-13.3 - concurrent ## macOS-specific scripts diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index 2a55db4..e1a2885 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -3781,6 +3781,7 @@ syn keyword cmakeGeneratorExpressions contained \ STREQUAL \ TARGET_BUNDLE_CONTENT_DIR \ TARGET_BUNDLE_DIR + \ TARGET_BUNDLE_DIR_NAME \ TARGET_EXISTS \ TARGET_FILE \ TARGET_FILE_BASE_NAME diff --git a/Help/dev/source.rst b/Help/dev/source.rst index 9be4451..0ee104f 100644 --- a/Help/dev/source.rst +++ b/Help/dev/source.rst @@ -117,6 +117,11 @@ These are: * ``cm::contains``: Checks if element or key is contained in container. +* ``<cmext/enum_set>`` + + * ``cm::enum_set``: + Container to manage set of elements from an ``enum class`` definition. + * ``<cmext/iterator>``: * ``cm::is_terator``: diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 3389968..1ef1ec8 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1019,8 +1019,19 @@ which is just the string ``tgt``. .. versionadded:: 3.9 - Full path to the bundle directory (``my.app``, ``my.framework``, or - ``my.bundle``) where ``tgt`` is the name of a target. + Full path to the bundle directory (``/path/to/my.app``, + ``/path/to/my.framework``, or ``/path/to/my.bundle``), + where ``tgt`` is the name of a target. + + Note that ``tgt`` is not added as a dependency of the target this + expression is evaluated on (see policy :policy:`CMP0112`). + +.. genex:: $<TARGET_BUNDLE_DIR_NAME:tgt> + + .. versionadded:: 3.24 + + Name of the bundle directory (``my.app``, ``my.framework``, or + ``my.bundle``), where ``tgt`` is the name of a target. Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on (see policy :policy:`CMP0112`). @@ -1030,10 +1041,11 @@ which is just the string ``tgt``. .. versionadded:: 3.9 Full path to the bundle content directory where ``tgt`` is the name of a - target. For the macOS SDK it leads to ``my.app/Contents``, ``my.framework``, - or ``my.bundle/Contents``. For all other SDKs (e.g. iOS) it leads to - ``my.app``, ``my.framework``, or ``my.bundle`` due to the flat bundle - structure. + target. For the macOS SDK it leads to ``/path/to/my.app/Contents``, + ``/path/to/my.framework``, or ``/path/to/my.bundle/Contents``. + For all other SDKs (e.g. iOS) it leads to ``/path/to/my.app``, + ``/path/to/my.framework``, or ``/path/to/my.bundle`` due to the flat + bundle structure. Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on (see policy :policy:`CMP0112`). diff --git a/Help/policy/CMP0112.rst b/Help/policy/CMP0112.rst index 5b00d07..25c3896 100644 --- a/Help/policy/CMP0112.rst +++ b/Help/policy/CMP0112.rst @@ -18,6 +18,7 @@ file name components no longer add a dependency on the evaluated target. - ``TARGET_PDB_FILE_NAME`` - ``TARGET_PDB_FILE_DIR`` - ``TARGET_BUNDLE_DIR`` + - ``TARGET_BUNDLE_DIR_NAME`` - ``TARGET_BUNDLE_CONTENT_DIR`` diff --git a/Help/release/dev/target-bundle-dir-name-genex.rst b/Help/release/dev/target-bundle-dir-name-genex.rst new file mode 100644 index 0000000..0ae835a --- /dev/null +++ b/Help/release/dev/target-bundle-dir-name-genex.rst @@ -0,0 +1,6 @@ +target-bundle-dir-name-genex +---------------------------- + +* Added the new :genex:`TARGET_BUNDLE_DIR_NAME` generator expression + which evaluates to the name of the bundle directory for a given bundle + target. diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index 91d4eee..0f407c8 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -1380,7 +1380,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret) set(_Boost_TIMER_DEPENDENCIES chrono) set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono atomic) set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) - if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.79.0 AND NOT Boost_NO_WARN_NEW_VERSIONS) + if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.80.0 AND NOT Boost_NO_WARN_NEW_VERSIONS) message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets") endif() endif() @@ -1653,6 +1653,7 @@ else() # _Boost_COMPONENT_HEADERS. See the instructions at the top of # _Boost_COMPONENT_DEPENDENCIES. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} + "1.79.0" "1.79" "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74" "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake index afdd4c4..538e132 100644 --- a/Modules/FindCUDAToolkit.cmake +++ b/Modules/FindCUDAToolkit.cmake @@ -843,7 +843,7 @@ endif() if(CUDAToolkit_FOUND) function(_CUDAToolkit_find_and_add_import_lib lib_name) - cmake_parse_arguments(arg "" "" "ALT;DEPS;EXTRA_PATH_SUFFIXES" ${ARGN}) + cmake_parse_arguments(arg "" "" "ALT;DEPS;EXTRA_PATH_SUFFIXES;EXTRA_INCLUDE_DIRS" ${ARGN}) set(search_names ${lib_name} ${arg_ALT}) @@ -883,6 +883,9 @@ if(CUDAToolkit_FOUND) target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dep}) endif() endforeach() + if(arg_EXTRA_INCLUDE_DIRS) + target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${arg_EXTRA_INCLUDE_DIRS}") + endif() endif() endfunction() @@ -974,12 +977,22 @@ if(CUDAToolkit_FOUND) _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS nppc_static) endforeach() - _CUDAToolkit_find_and_add_import_lib(cupti - EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/ - ../extras/CUPTI/lib/) - _CUDAToolkit_find_and_add_import_lib(cupti_static - EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/ - ../extras/CUPTI/lib/) + find_path(CUDAToolkit_CUPTI_INCLUDE_DIR cupti.h PATHS + "${CUDAToolkit_ROOT_DIR}/extras/CUPTI/include" + "${CUDAToolkit_INCLUDE_DIR}/../extras/CUPTI/include" + "${CUDATookit_INCLUDE_DIR}" + NO_DEFAULT_PATH) + + if(CUDAToolkit_CUPTI_INCLUDE_DIR) + _CUDAToolkit_find_and_add_import_lib(cupti + EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/ + ../extras/CUPTI/lib/ + EXTRA_INCLUDE_DIRS "${CUDAToolkit_CUPTI_INCLUDE_DIR}") + _CUDAToolkit_find_and_add_import_lib(cupti_static + EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/ + ../extras/CUPTI/lib/ + EXTRA_INCLUDE_DIRS "${CUDAToolkit_CUPTI_INCLUDE_DIR}") + endif() _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS cuda_driver) diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake index e4d6cf3..c1531a4 100644 --- a/Modules/FindThreads.cmake +++ b/Modules/FindThreads.cmake @@ -91,12 +91,27 @@ int main(void) # Internal helper macro. # Do NOT even think about using it outside of this file! -macro(_check_threads_lib LIBNAME FUNCNAME VARNAME) +macro(_threads_check_libc) + if(NOT Threads_FOUND) + if(CMAKE_C_COMPILER_LOADED) + CHECK_C_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD) + elseif(CMAKE_CXX_COMPILER_LOADED) + CHECK_CXX_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD) + endif() + if(CMAKE_HAVE_LIBC_PTHREAD) + set(CMAKE_THREAD_LIBS_INIT "") + set(Threads_FOUND TRUE) + endif() + endif () +endmacro() + +# Internal helper macro. +# Do NOT even think about using it outside of this file! +macro(_threads_check_lib LIBNAME FUNCNAME VARNAME) if(NOT Threads_FOUND) CHECK_LIBRARY_EXISTS(${LIBNAME} ${FUNCNAME} "" ${VARNAME}) if(${VARNAME}) set(CMAKE_THREAD_LIBS_INIT "-l${LIBNAME}") - set(CMAKE_HAVE_THREADS_LIBRARY 1) set(Threads_FOUND TRUE) endif() endif () @@ -104,7 +119,7 @@ endmacro() # Internal helper macro. # Do NOT even think about using it outside of this file! -macro(_check_pthreads_flag) +macro(_threads_check_flag_pthread) if(NOT Threads_FOUND) # If we did not find -lpthreads, -lpthread, or -lthread, look for -pthread if(NOT DEFINED THREADS_HAVE_PTHREAD_ARG) @@ -153,42 +168,29 @@ if(CMAKE_HAVE_PTHREAD_H) # We have pthread.h # Let's check for the library now. # - set(CMAKE_HAVE_THREADS_LIBRARY) - if(NOT THREADS_HAVE_PTHREAD_ARG) - # Check if pthread functions are in normal C library. - # We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code. - # If the pthread functions already exist in C library, we could just use - # them instead of linking to the additional pthread library. - if(CMAKE_C_COMPILER_LOADED) - CHECK_C_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD) - elseif(CMAKE_CXX_COMPILER_LOADED) - CHECK_CXX_SOURCE_COMPILES("${PTHREAD_C_CXX_TEST_SOURCE}" CMAKE_HAVE_LIBC_PTHREAD) - endif() - if(CMAKE_HAVE_LIBC_PTHREAD) - set(CMAKE_THREAD_LIBS_INIT "") - set(CMAKE_HAVE_THREADS_LIBRARY 1) - set(Threads_FOUND TRUE) - else() - # Check for -pthread first if enabled. This is the recommended - # way, but not backwards compatible as one must also pass -pthread - # as compiler flag then. - if (THREADS_PREFER_PTHREAD_FLAG) - _check_pthreads_flag() - endif () - - if(CMAKE_SYSTEM MATCHES "GHS-MULTI") - _check_threads_lib(posix pthread_create CMAKE_HAVE_PTHREADS_CREATE) - endif() - _check_threads_lib(pthreads pthread_create CMAKE_HAVE_PTHREADS_CREATE) - _check_threads_lib(pthread pthread_create CMAKE_HAVE_PTHREAD_CREATE) - if(CMAKE_SYSTEM_NAME MATCHES "SunOS") - # On sun also check for -lthread - _check_threads_lib(thread thr_create CMAKE_HAVE_THR_CREATE) - endif() - endif() + + # Check if pthread functions are in normal C library. + # We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code. + # If the pthread functions already exist in C library, we could just use + # them instead of linking to the additional pthread library. + _threads_check_libc() + + # Check for -pthread first if enabled. This is the recommended + # way, but not backwards compatible as one must also pass -pthread + # as compiler flag then. + if (THREADS_PREFER_PTHREAD_FLAG) + _threads_check_flag_pthread() + endif () + + if(CMAKE_SYSTEM MATCHES "GHS-MULTI") + _threads_check_lib(posix pthread_create CMAKE_HAVE_PTHREADS_CREATE) endif() + _threads_check_lib(pthreads pthread_create CMAKE_HAVE_PTHREADS_CREATE) + _threads_check_lib(pthread pthread_create CMAKE_HAVE_PTHREAD_CREATE) - _check_pthreads_flag() + if (NOT THREADS_PREFER_PTHREAD_FLAG) + _threads_check_flag_pthread() + endif() endif() if(CMAKE_THREAD_LIBS_INIT OR CMAKE_HAVE_LIBC_PTHREAD) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 2dae8fd..7d6a51d 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 23) -set(CMake_VERSION_PATCH 20220425) +set(CMake_VERSION_PATCH 20220428) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmEnableTestingCommand.h b/Source/cmEnableTestingCommand.h index 1722511..a1374f3 100644 --- a/Source/cmEnableTestingCommand.h +++ b/Source/cmEnableTestingCommand.h @@ -14,10 +14,10 @@ class cmExecutionStatus; * * Produce the output testfile. This produces a file in the build directory * called CMakeTestfile with a syntax similar to CMakeLists.txt. It contains - * the SUBDIRS() and ADD_TEST() commands from the source CMakeLists.txt + * the subdirs() and add_test() commands from the source CMakeLists.txt * file with CMake variables expanded. Only the subdirs and tests * within the valid control structures are replicated in Testfile - * (i.e. SUBDIRS() and ADD_TEST() commands within IF() commands that are + * (i.e. subdirs() and add_test() commands within IF() commands that are * not entered by CMake are not replicated in Testfile). * Note that CTest expects to find this file in the build directory root; * therefore, this command should be in the source directory root too. diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h index 410d4c3..1a9a626 100644 --- a/Source/cmExportBuildAndroidMKGenerator.h +++ b/Source/cmExportBuildAndroidMKGenerator.h @@ -20,7 +20,7 @@ class cmGeneratorTarget; * a build tree. This exports the targets to the Android ndk build tool * makefile format for prebuilt libraries. * - * This is used to implement the EXPORT() command. + * This is used to implement the export() command. */ class cmExportBuildAndroidMKGenerator : public cmExportBuildFileGenerator { diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 3db8719..5681e8f 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -28,7 +28,7 @@ class cmTargetExport; * a build tree. A single file exports information for all * configurations built. * - * This is used to implement the EXPORT() command. + * This is used to implement the export() command. */ class cmExportBuildFileGenerator : public cmExportFileGenerator { diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index a9bc435..26ffd4b 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -2098,6 +2098,7 @@ class ArtifactPathTag; class ArtifactPdbTag; class ArtifactSonameTag; class ArtifactBundleDirTag; +class ArtifactBundleDirNameTag; class ArtifactBundleContentDirTag; template <typename ArtifactT, typename ComponentT> @@ -2158,6 +2159,12 @@ struct TargetFilesystemArtifactDependency<ArtifactBundleDirTag, { }; template <> +struct TargetFilesystemArtifactDependency<ArtifactBundleDirNameTag, + ArtifactPathTag> + : TargetFilesystemArtifactDependencyCMP0112 +{ +}; +template <> struct TargetFilesystemArtifactDependency<ArtifactBundleContentDirTag, ArtifactPathTag> : TargetFilesystemArtifactDependencyCMP0112 @@ -2285,6 +2292,31 @@ struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag> }; template <> +struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirNameTag> +{ + static std::string Create(cmGeneratorTarget* target, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content) + { + if (target->IsImported()) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_BUNDLE_DIR_NAME not allowed for IMPORTED targets."); + return std::string(); + } + if (!target->IsBundleOnApple()) { + ::reportError( + context, content->GetOriginalExpression(), + "TARGET_BUNDLE_DIR_NAME is allowed only for Bundle targets."); + return std::string(); + } + + return target->GetAppBundleDirectory(context->Config, + cmGeneratorTarget::BundleDirLevel); + } +}; + +template <> struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag> { static std::string Create(cmGeneratorTarget* target, @@ -2417,7 +2449,8 @@ struct TargetFilesystemArtifact : public TargetArtifactBase return std::string(); } // Not a dependent target if we are querying for ArtifactDirTag, - // ArtifactNameTag, ArtifactBundleDirTag, and ArtifactBundleContentDirTag + // ArtifactNameTag, ArtifactBundleDirTag, ArtifactBundleDirNameTag, + // and ArtifactBundleContentDirTag TargetFilesystemArtifactDependency<ArtifactT, ComponentT>::AddDependency( target, context); @@ -2458,6 +2491,10 @@ static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag> static const TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag> targetBundleDirNode; +static const TargetFilesystemArtifact<ArtifactBundleDirNameTag, + ArtifactNameTag> + targetBundleDirNameNode; + static const TargetFilesystemArtifact<ArtifactBundleContentDirTag, ArtifactPathTag> targetBundleContentDirNode; @@ -2783,6 +2820,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "TARGET_SONAME_FILE_DIR", &targetSoNameNodeGroup.FileDir }, { "TARGET_PDB_FILE_DIR", &targetPdbNodeGroup.FileDir }, { "TARGET_BUNDLE_DIR", &targetBundleDirNode }, + { "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode }, { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode }, { "STREQUAL", &strEqualNode }, { "EQUAL", &equalNode }, diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 0a394b5..adbdba8 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -76,6 +76,13 @@ static void MergeOptions(std::vector<std::string>& baseOpts, unsigned int const cmQtAutoGen::ParallelMax = 64; +#ifdef _WIN32 +// Actually 32767 (see +// https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553) but we +// allow for a small margin +size_t const cmQtAutoGen::CommandLineLengthMax = 32000; +#endif + cm::string_view cmQtAutoGen::GeneratorName(GenT genType) { switch (genType) { diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index 5a23ae9..d111422 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -64,6 +64,11 @@ public: /// @brief Maximum number of parallel threads/processes in a generator static unsigned int const ParallelMax; +#ifdef _WIN32 + /// @brief Maximum number of characters on command line + static size_t const CommandLineLengthMax; +#endif + /// @brief Returns the generator name static cm::string_view GeneratorName(GenT genType); /// @brief Returns the generator name in upper case diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 4ed728e..0d38dfb 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -497,6 +497,10 @@ public: protected: ParseCacheT::FileHandleT CacheEntry; + + private: + void MaybeWriteMocResponseFile(std::string const& outputFile, + std::vector<std::string>& cmd) const; }; /** uic compiles a file. */ @@ -2025,6 +2029,8 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() cmd.push_back(outputFile); // Add source file cmd.push_back(sourceFile); + + MaybeWriteMocResponseFile(outputFile, cmd); } // Execute moc command @@ -2070,6 +2076,51 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() } } +/* + * Check if command line exceeds maximum length supported by OS + * (if on Windows) and switch to using a response file instead. + */ +void cmQtAutoMocUicT::JobCompileMocT::MaybeWriteMocResponseFile( + std::string const& outputFile, std::vector<std::string>& cmd) const +{ +#ifdef _WIN32 + // Ensure cmd is less than CommandLineLengthMax characters + size_t commandLineLength = cmd.size(); // account for separating spaces + for (std::string const& str : cmd) { + commandLineLength += str.length(); + } + if (commandLineLength >= CommandLineLengthMax) { + // Command line exceeds maximum size allowed by OS + // => create response file + std::string const responseFile = cmStrCat(outputFile, ".rsp"); + + cmsys::ofstream fout(responseFile.c_str()); + if (!fout) { + this->LogError( + GenT::MOC, + cmStrCat("AUTOMOC was unable to create a response file at\n ", + this->MessagePath(responseFile))); + return; + } + + auto it = cmd.begin(); + while (++it != cmd.end()) { + fout << *it << "\n"; + } + fout.close(); + + // Keep all but executable + cmd.resize(1); + + // Specify response file + cmd.push_back(cmStrCat('@', responseFile)); + } +#else + static_cast<void>(outputFile); + static_cast<void>(cmd); +#endif +} + void cmQtAutoMocUicT::JobCompileUicT::Process() { std::string const& sourceFile = this->Mapping->SourceFile->FileName; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index a01321d..446964c 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -13,6 +13,7 @@ #include <unordered_set> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -164,6 +165,66 @@ cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt, return cmValue(srcs); } +namespace { +struct FileSetEntries +{ + FileSetEntries(cm::static_string_view propertyName) + : PropertyName(propertyName) + { + } + + cm::static_string_view const PropertyName; + std::vector<BT<std::string>> Entries; +}; + +struct FileSetType +{ + FileSetType(cm::static_string_view typeName, + cm::static_string_view defaultDirectoryProperty, + cm::static_string_view defaultPathProperty, + cm::static_string_view directoryPrefix, + cm::static_string_view pathPrefix, + cm::static_string_view typeDescription, + cm::static_string_view defaultDescription, + cm::static_string_view arbitraryDescription, + FileSetEntries selfEntries, FileSetEntries interfaceEntries) + : TypeName(typeName) + , DefaultDirectoryProperty(defaultDirectoryProperty) + , DefaultPathProperty(defaultPathProperty) + , DirectoryPrefix(directoryPrefix) + , PathPrefix(pathPrefix) + , TypeDescription(typeDescription) + , DefaultDescription(defaultDescription) + , ArbitraryDescription(arbitraryDescription) + , SelfEntries(std::move(selfEntries)) + , InterfaceEntries(std::move(interfaceEntries)) + { + } + + cm::static_string_view const TypeName; + cm::static_string_view const DefaultDirectoryProperty; + cm::static_string_view const DefaultPathProperty; + cm::static_string_view const DirectoryPrefix; + cm::static_string_view const PathPrefix; + cm::static_string_view const TypeDescription; + cm::static_string_view const DefaultDescription; + cm::static_string_view const ArbitraryDescription; + + FileSetEntries SelfEntries; + FileSetEntries InterfaceEntries; + + template <typename ValueType> + bool WriteProperties(cmTarget* tgt, cmTargetInternals* impl, + const std::string& prop, ValueType value, bool clear); + std::pair<bool, cmValue> ReadProperties(cmTarget const* tgt, + cmTargetInternals const* impl, + const std::string& prop) const; + + void AddFileSet(const std::string& name, cmFileSetVisibility vis, + cmListFileBacktrace bt); +}; +} + class cmTargetInternals { public: @@ -205,19 +266,152 @@ public: std::vector<BT<std::string>> LinkInterfacePropertyEntries; std::vector<BT<std::string>> LinkInterfaceDirectPropertyEntries; std::vector<BT<std::string>> LinkInterfaceDirectExcludePropertyEntries; - std::vector<BT<std::string>> HeaderSetsEntries; - std::vector<BT<std::string>> InterfaceHeaderSetsEntries; std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>> TLLCommands; std::map<std::string, cmFileSet> FileSets; cmListFileBacktrace Backtrace; + FileSetType HeadersFileSets; + + cmTargetInternals(); + bool CheckImportedLibName(std::string const& prop, std::string const& value) const; std::string ProcessSourceItemCMP0049(const std::string& s) const; + + template <typename ValueType> + void AddDirectoryToFileSet(cmTarget* self, std::string const& fileSetName, + ValueType value, cm::string_view fileSetType, + cm::string_view description, bool clear); + template <typename ValueType> + void AddPathToFileSet(cmTarget* self, std::string const& fileSetName, + ValueType value, cm::string_view fileSetType, + cm::string_view description, bool clear); + cmValue GetFileSetDirectories(cmTarget const* self, + std::string const& fileSetName, + cm::string_view fileSetType) const; + cmValue GetFileSetPaths(cmTarget const* self, std::string const& fileSetName, + cm::string_view fileSetType) const; }; +cmTargetInternals::cmTargetInternals() + : HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s, + "HEADER_DIRS_"_s, "HEADER_SET_"_s, "Header"_s, + "The default header set"_s, "Header set"_s, + FileSetEntries("HEADER_SETS"_s), + FileSetEntries("INTERFACE_HEADER_SETS"_s)) +{ +} + +template <typename ValueType> +bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl, + const std::string& prop, ValueType value, + bool clear) +{ + if (prop == this->DefaultDirectoryProperty) { + impl->AddDirectoryToFileSet(tgt, std::string(this->TypeName), value, + this->TypeName, this->DefaultDescription, + clear); + return true; + } + if (prop == this->DefaultPathProperty) { + impl->AddPathToFileSet(tgt, std::string(this->TypeName), value, + this->TypeName, this->DefaultDescription, clear); + return true; + } + if (cmHasPrefix(prop, this->DirectoryPrefix)) { + auto fileSetName = prop.substr(this->DirectoryPrefix.size()); + if (fileSetName.empty()) { + impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->ArbitraryDescription, " name cannot be empty.")); + } else { + impl->AddDirectoryToFileSet( + tgt, fileSetName, value, this->TypeName, + cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear); + } + return true; + } + if (cmHasPrefix(prop, this->PathPrefix)) { + auto fileSetName = prop.substr(this->PathPrefix.size()); + if (fileSetName.empty()) { + impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->ArbitraryDescription, " name cannot be empty.")); + } else { + impl->AddPathToFileSet( + tgt, fileSetName, value, this->TypeName, + cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear); + } + return true; + } + if (prop == this->SelfEntries.PropertyName) { + impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->SelfEntries.PropertyName, " property is read-only\n")); + return true; + } + if (prop == this->InterfaceEntries.PropertyName) { + impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat(this->InterfaceEntries.PropertyName, + " property is read-only\n")); + return true; + } + return false; +} + +std::pair<bool, cmValue> FileSetType::ReadProperties( + cmTarget const* tgt, cmTargetInternals const* impl, + const std::string& prop) const +{ + bool did_read = false; + cmValue value = nullptr; + if (prop == this->DefaultDirectoryProperty) { + value = impl->GetFileSetDirectories(tgt, std::string(this->TypeName), + this->TypeName); + did_read = true; + } else if (prop == this->DefaultPathProperty) { + value = + impl->GetFileSetPaths(tgt, std::string(this->TypeName), this->TypeName); + did_read = true; + } else if (prop == this->SelfEntries.PropertyName) { + static std::string output; + output = cmJoin(this->SelfEntries.Entries, ";"_s); + value = cmValue(output); + did_read = true; + } else if (prop == this->InterfaceEntries.PropertyName) { + static std::string output; + output = cmJoin(this->InterfaceEntries.Entries, ";"_s); + value = cmValue(output); + did_read = true; + } else if (cmHasPrefix(prop, this->DirectoryPrefix)) { + std::string fileSetName = prop.substr(this->DirectoryPrefix.size()); + if (!fileSetName.empty()) { + value = impl->GetFileSetDirectories(tgt, fileSetName, this->TypeName); + } + did_read = true; + } else if (cmHasPrefix(prop, this->PathPrefix)) { + std::string fileSetName = prop.substr(this->PathPrefix.size()); + if (!fileSetName.empty()) { + value = impl->GetFileSetPaths(tgt, fileSetName, this->TypeName); + } + did_read = true; + } + return { did_read, value }; +} + +void FileSetType::AddFileSet(const std::string& name, cmFileSetVisibility vis, + cmListFileBacktrace bt) +{ + if (cmFileSetVisibilityIsForSelf(vis)) { + this->SelfEntries.Entries.emplace_back(name, bt); + } + if (cmFileSetVisibilityIsForInterface(vis)) { + this->InterfaceEntries.Entries.emplace_back(name, std::move(bt)); + } +} + namespace { #define SETUP_COMMON_LANGUAGE_PROPERTIES(lang) \ initProp(#lang "_COMPILER_LAUNCHER"); \ @@ -1162,12 +1356,12 @@ cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const cmBTStringRange cmTarget::GetHeaderSetsEntries() const { - return cmMakeRange(this->impl->HeaderSetsEntries); + return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries); } cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const { - return cmMakeRange(this->impl->InterfaceHeaderSetsEntries); + return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries); } namespace { @@ -1199,10 +1393,6 @@ MAKE_PROP(BINARY_DIR); MAKE_PROP(SOURCE_DIR); MAKE_PROP(FALSE); MAKE_PROP(TRUE); -MAKE_PROP(HEADER_DIRS); -MAKE_PROP(HEADER_SET); -MAKE_PROP(HEADER_SETS); -MAKE_PROP(INTERFACE_HEADER_SETS); MAKE_PROP(INTERFACE_LINK_LIBRARIES); MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT); MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE); @@ -1227,19 +1417,25 @@ std::string ConvertToString<cmValue>(cmValue value) } template <typename ValueType> -bool StringIsEmpty(ValueType value); +bool StringIsEmpty(ValueType const& value); template <> -bool StringIsEmpty<const char*>(const char* value) +bool StringIsEmpty<const char*>(const char* const& value) { return cmValue::IsEmpty(value); } template <> -bool StringIsEmpty<cmValue>(cmValue value) +bool StringIsEmpty<cmValue>(cmValue const& value) { return value.IsEmpty(); } + +template <> +bool StringIsEmpty<std::string>(std::string const& value) +{ + return value.empty(); +} } template <typename ValueType> @@ -1371,7 +1567,9 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) } } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") && !this->impl->CheckImportedLibName( - prop, value ? value : std::string{})) { + prop, + value ? value + : std::string{})) { // NOLINT(bugprone-branch-clone) /* error was reported by check method */ } else if (prop == propCUDA_PTX_COMPILATION && this->GetType() != cmStateEnums::OBJECT_LIBRARY) { @@ -1422,81 +1620,9 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) } else { this->impl->LanguageStandardProperties.erase(prop); } - } else if (prop == propHEADER_DIRS) { - auto* fileSet = this->GetFileSet("HEADERS"); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "The default header set has not yet been created."); - return; - } - fileSet->ClearDirectoryEntries(); - if (!StringIsEmpty(value)) { - fileSet->AddDirectoryEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } - } else if (prop == propHEADER_SET) { - auto* fileSet = this->GetFileSet("HEADERS"); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "The default header set has not yet been created."); - return; - } - fileSet->ClearFileEntries(); - if (!StringIsEmpty(value)) { - fileSet->AddFileEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } - } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) { - auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_")); - if (fileSetName.empty()) { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "Header set name cannot be empty."); - return; - } - auto* fileSet = this->GetFileSet(fileSetName); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Header set \"", fileSetName, - "\" has not yet been created.")); - return; - } - fileSet->ClearDirectoryEntries(); - if (!StringIsEmpty(value)) { - fileSet->AddDirectoryEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } - } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) { - auto fileSetName = prop.substr(cmStrLen("HEADER_SET_")); - if (fileSetName.empty()) { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "Header set name cannot be empty."); - return; - } - auto* fileSet = this->GetFileSet(fileSetName); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Header set \"", fileSetName, - "\" has not yet been created.")); - return; - } - fileSet->ClearFileEntries(); - if (!StringIsEmpty(value)) { - fileSet->AddFileEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } - } else if (prop == propHEADER_SETS) { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "HEADER_SETS property is read-only\n"); - return; - } else if (prop == propINTERFACE_HEADER_SETS) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "INTERFACE_HEADER_SETS property is read-only\n"); - return; + } else if (this->impl->HeadersFileSets.WriteProperties( + this, this->impl.get(), prop, value, true)) { + /* Handled in the `if` condition. */ } else { this->impl->Properties.SetProperty(prop, value); } @@ -1607,69 +1733,9 @@ void cmTarget::AppendProperty(const std::string& prop, prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") { this->impl->Makefile->IssueMessage( MessageType::FATAL_ERROR, prop + " property may not be appended."); - } else if (prop == "HEADER_DIRS") { - auto* fileSet = this->GetFileSet("HEADERS"); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "The default header set has not yet been created."); - return; - } - fileSet->AddDirectoryEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) { - auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_")); - if (fileSetName.empty()) { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "Header set name cannot be empty."); - return; - } - auto* fileSet = this->GetFileSet(fileSetName); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Header set \"", fileSetName, - "\" has not yet been created.")); - return; - } - fileSet->AddDirectoryEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } else if (prop == "HEADER_SET") { - auto* fileSet = this->GetFileSet("HEADERS"); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "The default header set has not yet been created."); - return; - } - fileSet->AddFileEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) { - auto fileSetName = prop.substr(cmStrLen("HEADER_SET_")); - if (fileSetName.empty()) { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "Header set name cannot be empty."); - return; - } - auto* fileSet = this->GetFileSet(fileSetName); - if (!fileSet) { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Header set \"", fileSetName, - "\" has not yet been created.")); - return; - } - fileSet->AddFileEntry( - BT<std::string>(value, this->impl->Makefile->GetBacktrace())); - } else if (prop == "HEADER_SETS") { - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "HEADER_SETS property is read-only\n"); - return; - } else if (prop == "INTERFACE_HEADER_SETS") { - this->impl->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "INTERFACE_HEADER_SETS property is read-only\n"); - return; + } else if (this->impl->HeadersFileSets.WriteProperties( + this, this->impl.get(), prop, value, false)) { + /* Handled in the `if` condition. */ } else { this->impl->Properties.AppendProperty(prop, value, asString); } @@ -1684,6 +1750,102 @@ void cmTarget::SetProperty(const std::string& prop, cmValue value) this->StoreProperty(prop, value); } +template <typename ValueType> +void cmTargetInternals::AddDirectoryToFileSet( + cmTarget* self, std::string const& fileSetName, ValueType value, + cm::string_view fileSetType, cm::string_view description, bool clear) +{ + auto* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(description, "has not yet been created.")); + return; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return; + } + if (clear) { + fileSet->ClearDirectoryEntries(); + } + if (!StringIsEmpty(value)) { + fileSet->AddDirectoryEntry( + BT<std::string>(value, this->Makefile->GetBacktrace())); + } +} + +template <typename ValueType> +void cmTargetInternals::AddPathToFileSet( + cmTarget* self, std::string const& fileSetName, ValueType value, + cm::string_view fileSetType, cm::string_view description, bool clear) +{ + auto* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(description, "has not yet been created.")); + return; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return; + } + if (clear) { + fileSet->ClearFileEntries(); + } + if (!StringIsEmpty(value)) { + fileSet->AddFileEntry( + BT<std::string>(value, this->Makefile->GetBacktrace())); + } +} + +cmValue cmTargetInternals::GetFileSetDirectories( + cmTarget const* self, std::string const& fileSetName, + cm::string_view fileSetType) const +{ + auto const* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + return nullptr; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s); + return cmValue(output); +} + +cmValue cmTargetInternals::GetFileSetPaths(cmTarget const* self, + std::string const& fileSetName, + cm::string_view fileSetType) const +{ + auto const* fileSet = self->GetFileSet(fileSetName); + if (!fileSet) { + return nullptr; + } + if (fileSet->GetType() != fileSetType) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("File set \"", fileSetName, + "\" is not of type \"", fileSetType, + "\".")); + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetFileEntries(), ";"_s); + return cmValue(output); +} + void cmTarget::AppendBuildInterfaceIncludes() { if (this->GetType() != cmStateEnums::SHARED_LIBRARY && @@ -1915,10 +2077,6 @@ cmValue cmTarget::GetProperty(const std::string& prop) const propBINARY_DIR, propSOURCE_DIR, propSOURCES, - propHEADER_DIRS, - propHEADER_SET, - propHEADER_SETS, - propINTERFACE_HEADER_SETS, propINTERFACE_LINK_LIBRARIES, propINTERFACE_LINK_LIBRARIES_DIRECT, propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, @@ -2075,73 +2233,15 @@ cmValue cmTarget::GetProperty(const std::string& prop) const .GetDirectory() .GetCurrentSource()); } - if (prop == propHEADER_DIRS) { - auto const* fileSet = this->GetFileSet("HEADERS"); - if (!fileSet) { - return nullptr; - } - static std::string output; - output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s); - return cmValue(output); - } - if (prop == propHEADER_SET) { - auto const* fileSet = this->GetFileSet("HEADERS"); - if (!fileSet) { - return nullptr; - } - static std::string output; - output = cmJoin(fileSet->GetFileEntries(), ";"_s); - return cmValue(output); - } - if (prop == propHEADER_SETS) { - std::vector<std::string> set_names; - for (auto const& file_set : this->impl->FileSets) { - if (cmFileSetVisibilityIsForSelf(file_set.second.GetVisibility())) { - set_names.push_back(file_set.second.GetName()); - } - } - static std::string output; - output = cmJoin(set_names, ";"_s); - return cmValue(output); - } - if (prop == propINTERFACE_HEADER_SETS) { - std::vector<std::string> set_names; - for (auto const& file_set : this->impl->FileSets) { - if (cmFileSetVisibilityIsForInterface( - file_set.second.GetVisibility())) { - set_names.push_back(file_set.second.GetName()); - } - } - static std::string output; - output = cmJoin(set_names, ";"_s); - return cmValue(output); - } } - if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) { - std::string fileSetName = prop.substr(cmStrLen("HEADER_DIRS_")); - if (fileSetName.empty()) { - return nullptr; - } - auto const* fileSet = this->GetFileSet(fileSetName); - if (!fileSet) { - return nullptr; - } - static std::string output; - output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s); - return cmValue(output); - } - if (cmHasLiteralPrefix(prop, "HEADER_SET_")) { - std::string fileSetName = prop.substr(cmStrLen("HEADER_SET_")); - if (fileSetName.empty()) { - return nullptr; - } - auto const* fileSet = this->GetFileSet(fileSetName); - if (!fileSet) { - return nullptr; + + // Check fileset properties. + { + auto headers = + this->impl->HeadersFileSets.ReadProperties(this, this->impl.get(), prop); + if (headers.first) { + return headers.second; } - static std::string output; - output = cmJoin(fileSet->GetFileEntries(), ";"_s); - return cmValue(output); } cmValue retVal = this->impl->Properties.GetPropertyValue(prop); @@ -2416,13 +2516,9 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet( auto result = this->impl->FileSets.emplace( std::make_pair(name, cmFileSet(name, type, vis))); if (result.second) { - if (cmFileSetVisibilityIsForSelf(vis)) { - this->impl->HeaderSetsEntries.emplace_back( - name, this->impl->Makefile->GetBacktrace()); - } - if (cmFileSetVisibilityIsForInterface(vis)) { - this->impl->InterfaceHeaderSetsEntries.emplace_back( - name, this->impl->Makefile->GetBacktrace()); + auto bt = this->impl->Makefile->GetBacktrace(); + if (type == this->impl->HeadersFileSets.TypeName) { + this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt)); } } return std::make_pair(&result.first->second, result.second); @@ -2456,7 +2552,7 @@ std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const } }; - appendEntries(this->impl->InterfaceHeaderSetsEntries); + appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries); return result; } diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx index 05b3f05..130c228 100644 --- a/Source/cmTryCompileCommand.cxx +++ b/Source/cmTryCompileCommand.cxx @@ -20,7 +20,7 @@ bool cmTryCompileCommand::InitialPass(std::vector<std::string> const& argv, cmake::FIND_PACKAGE_MODE) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - "The TRY_COMPILE() command is not supported in --find-package mode."); + "The try_compile() command is not supported in --find-package mode."); return false; } diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index cd468b9..c82ac64 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -31,7 +31,7 @@ bool cmTryRunCommand::InitialPass(std::vector<std::string> const& argv, cmake::FIND_PACKAGE_MODE) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - "The TRY_RUN() command is not supported in --find-package mode."); + "The try_run() command is not supported in --find-package mode."); return false; } @@ -217,7 +217,7 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs, retStr = "FAILED_TO_RUN"; } this->Makefile->AddCacheDefinition(this->RunResultVariable, retStr, - "Result of TRY_RUN", + "Result of try_run()", cmStateEnums::INTERNAL); } @@ -230,7 +230,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, std::string* out) { // copy the executable out of the CMakeFiles/ directory, so it is not - // removed at the end of TRY_RUN and the user can run it manually + // removed at the end of try_run() and the user can run it manually // on the target platform. std::string copyDest = cmStrCat(this->Makefile->GetHomeOutputDirectory(), "/CMakeFiles/", @@ -252,7 +252,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, // if the variables doesn't exist, create it with a helpful error text // and mark it as advanced std::string comment = - cmStrCat("Run result of TRY_RUN(), indicates whether the executable " + cmStrCat("Run result of try_run(), indicates whether the executable " "would have been able to run on its target platform.\n", detailsString); this->Makefile->AddCacheDefinition(this->RunResultVariable, @@ -274,7 +274,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, // if the variables doesn't exist, create it with a helpful error text // and mark it as advanced std::string comment = cmStrCat( - "Output of TRY_RUN(), contains the text, which the executable " + "Output of try_run(), contains the text, which the executable " "would have printed on stdout and stderr on its target platform.\n", detailsString); @@ -299,7 +299,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, if (firstTryRun) { /* clang-format off */ file << "# This file was generated by CMake because it detected " - "TRY_RUN() commands\n" + "try_run() commands\n" "# in crosscompiling mode. It will be overwritten by the next " "CMake run.\n" "# Copy it to a safe location, set the variables to " @@ -332,7 +332,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, } comment += "The "; comment += this->CompileResultVariable; - comment += " variable holds the build result for this TRY_RUN().\n\n" + comment += " variable holds the build result for this try_run().\n\n" "Source file : "; comment += srcFile + "\n"; comment += "Executable : "; @@ -346,19 +346,19 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, file << "set( " << this->RunResultVariable << " \n \"" << this->Makefile->GetSafeDefinition(this->RunResultVariable) - << "\"\n CACHE STRING \"Result from TRY_RUN\" FORCE)\n\n"; + << "\"\n CACHE STRING \"Result from try_run\" FORCE)\n\n"; if (out) { file << "set( " << internalRunOutputName << " \n \"" << this->Makefile->GetSafeDefinition(internalRunOutputName) - << "\"\n CACHE STRING \"Output from TRY_RUN\" FORCE)\n\n"; + << "\"\n CACHE STRING \"Output from try_run\" FORCE)\n\n"; } file.close(); } firstTryRun = false; std::string errorMessage = - cmStrCat("TRY_RUN() invoked in cross-compiling mode, " + cmStrCat("try_run() invoked in cross-compiling mode, " "please set the following cache variables " "appropriately:\n ", this->RunResultVariable, " (advanced)\n"); diff --git a/Tests/AliasTarget/CMakeLists.txt b/Tests/AliasTarget/CMakeLists.txt index fc70135..aa4abc4 100644 --- a/Tests/AliasTarget/CMakeLists.txt +++ b/Tests/AliasTarget/CMakeLists.txt @@ -2,14 +2,6 @@ cmake_minimum_required(VERSION 2.8.11) cmake_policy(SET CMP0054 NEW) project(AliasTarget) -set(CMAKE_CXX_STANDARD 98) - -# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND - CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - set(CMAKE_CXX_STANDARD 11) -endif() - add_library(foo SHARED empty.cpp) add_library(PREFIX::Foo ALIAS foo) add_library(Another::Alias ALIAS foo) diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 87925bd..1d45162 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -29,6 +29,7 @@ set(CMakeLib_TESTS testUVStreambuf.cxx testCMExtMemory.cxx testCMExtAlgorithm.cxx + testCMExtEnumSet.cxx ) if (CMake_TEST_FILESYSTEM_PATH OR NOT CMake_HAVE_CXX_FILESYSTEM) list(APPEND CMakeLib_TESTS testCMFilesystemPath.cxx) diff --git a/Tests/CMakeLib/testCMExtEnumSet.cxx b/Tests/CMakeLib/testCMExtEnumSet.cxx new file mode 100644 index 0000000..64c437b --- /dev/null +++ b/Tests/CMakeLib/testCMExtEnumSet.cxx @@ -0,0 +1,204 @@ + +#include <cstdint> +#include <initializer_list> +#include <iostream> +#include <iterator> +#include <set> +#include <utility> + +#include <cmext/enum_set> + +namespace { + +int failed = 0; + +void testDeclaration() +{ + std::cout << "testDeclaration()" << std::endl; + + enum class Test : std::uint8_t + { + A, + B, + C, + D + }; + cm::enum_set<Test> testSet1; + cm::enum_set<Test> testSet2{ Test::A, Test::C }; + cm::enum_set<Test> testSet3 = testSet2; + + if (!testSet1.empty()) { + ++failed; + } + if (testSet2.size() != 2) { + ++failed; + } + if (testSet3.size() != 2) { + ++failed; + } +} + +void testIteration() +{ + std::cout << "testIteration()" << std::endl; + + enum class Test : std::uint8_t + { + A, + B, + C, + D + }; + cm::enum_set<Test> testSet{ Test::A, Test::C, Test::B }; + + if (testSet.size() != 3) { + ++failed; + } + + std::set<std::uint8_t> reference{ static_cast<std::uint8_t>(Test::A), + static_cast<std::uint8_t>(Test::B), + static_cast<std::uint8_t>(Test::C) }; + std::set<std::uint8_t> s; + + for (auto e : testSet) { + s.insert(static_cast<std::uint8_t>(e)); + } + if (s != reference) { + ++failed; + } + + s.clear(); + for (auto rit = testSet.rbegin(); rit != testSet.rend(); rit++) { + s.insert(static_cast<std::uint8_t>(*rit)); + } + if (s != reference) { + ++failed; + } +} + +void testEdition() +{ + std::cout << "testEdition()" << std::endl; + + enum class Test : std::uint8_t + { + A, + B, + C, + D, + E + }; + + { + cm::enum_set<Test> testSet{ Test::A, Test::C, Test::B }; + + auto pos = testSet.insert(Test::E); + if (!pos.second || testSet.size() != 4 || *(pos.first) != Test::E || + testSet.find(Test::E) == testSet.end()) { + ++failed; + } + testSet.insert(Test::E); + if (testSet.size() != 4 || testSet.find(Test::E) == testSet.end()) { + ++failed; + } + + testSet.erase(Test::A); + if (testSet.size() != 3 || testSet.find(Test::A) != testSet.end()) { + ++failed; + } + testSet.erase(Test::A); + if (testSet.size() != 3 || testSet.find(Test::A) != testSet.end()) { + ++failed; + } + } + { + cm::enum_set<Test> testSet{ Test::A, Test::C, Test::B }; + + testSet += { Test::D, Test::E }; + + std::set<std::uint8_t> reference{ static_cast<std::uint8_t>(Test::A), + static_cast<std::uint8_t>(Test::B), + static_cast<std::uint8_t>(Test::C), + static_cast<std::uint8_t>(Test::D), + static_cast<std::uint8_t>(Test::E) }; + std::set<std::uint8_t> s; + for (auto e : testSet) { + s.insert(static_cast<std::uint8_t>(e)); + } + if (s != reference) { + ++failed; + } + + testSet -= { Test::D, Test::B }; + reference.erase(static_cast<std::uint8_t>(Test::D)); + reference.erase(static_cast<std::uint8_t>(Test::B)); + s.clear(); + for (auto e : testSet) { + s.insert(static_cast<std::uint8_t>(e)); + } + if (s != reference) { + ++failed; + } + } + { + cm::enum_set<Test> testSet1{ Test::A, Test::C, Test::B }; + cm::enum_set<Test> testSet2{ Test::A, Test::D, Test::E }; + testSet1.insert(testSet2.cbegin(), testSet2.cend()); + + std::set<std::uint8_t> reference{ static_cast<std::uint8_t>(Test::A), + static_cast<std::uint8_t>(Test::B), + static_cast<std::uint8_t>(Test::C), + static_cast<std::uint8_t>(Test::D), + static_cast<std::uint8_t>(Test::E) }; + std::set<std::uint8_t> s; + for (auto e : testSet1) { + s.insert(static_cast<std::uint8_t>(e)); + } + if (s != reference) { + ++failed; + } + + testSet1.erase(testSet2); + + reference.erase(static_cast<std::uint8_t>(Test::A)); + reference.erase(static_cast<std::uint8_t>(Test::D)); + reference.erase(static_cast<std::uint8_t>(Test::E)); + s.clear(); + for (auto e : testSet1) { + s.insert(static_cast<std::uint8_t>(e)); + } + if (s != reference) { + ++failed; + } + } + { + cm::enum_set<Test> testSet1{ Test::A, Test::C, Test::B }; + cm::enum_set<Test> testSet2{ Test::C, Test::E }; + + testSet1.flip(Test::A); + if (testSet1.size() != 2 || testSet1.contains(Test::A)) { + ++failed; + } + + testSet1.flip(testSet2); + std::set<std::uint8_t> reference{ static_cast<std::uint8_t>(Test::B), + static_cast<std::uint8_t>(Test::E) }; + std::set<std::uint8_t> s; + for (auto e : testSet1) { + s.insert(static_cast<std::uint8_t>(e)); + } + if (s != reference) { + ++failed; + } + } +} +} + +int testCMExtEnumSet(int /*unused*/, char* /*unused*/ []) +{ + testDeclaration(); + testIteration(); + testEdition(); + + return failed; +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 6ceb832..9a4910f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -528,7 +528,7 @@ if(BUILD_TESTING) PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test") ADD_TEST_MACRO(CrossCompile CrossCompile) set_tests_properties(CrossCompile PROPERTIES - PASS_REGULAR_EXPRESSION "TRY_RUN.. invoked in cross-compiling mode") + PASS_REGULAR_EXPRESSION "try_run.. invoked in cross-compiling mode") if("${CMAKE_GENERATOR}" MATCHES "Make") ADD_TEST_MACRO(Policy0002 Policy0002) endif() diff --git a/Tests/CTestTestScheduler/sleep.c b/Tests/CTestTestScheduler/sleep.c index 327bff5..69a5797 100644 --- a/Tests/CTestTestScheduler/sleep.c +++ b/Tests/CTestTestScheduler/sleep.c @@ -1,3 +1,5 @@ +#include <stdlib.h> + #if defined(_WIN32) # include <windows.h> #else diff --git a/Tests/CTestTestStopTime/sleep.c b/Tests/CTestTestStopTime/sleep.c index b9b6e89..2d69f7f 100644 --- a/Tests/CTestTestStopTime/sleep.c +++ b/Tests/CTestTestStopTime/sleep.c @@ -1,3 +1,5 @@ +#include <stdlib.h> + #if defined(_WIN32) # include <windows.h> #else diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt index 9fd85be..5df22d2 100644 --- a/Tests/Complex/CMakeLists.txt +++ b/Tests/Complex/CMakeLists.txt @@ -432,21 +432,6 @@ if(NOT RESULT STREQUAL "a[b]c[d]e") endif() # -# This tests needs Ansi C++98 -# -set(CMAKE_CXX_STANDARD 98) -# -# GNU extensions are needed for stricmp() on Windows. -# -set(CMAKE_CXX_EXTENSIONS TRUE) - -# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND - CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - set(CMAKE_CXX_STANDARD 11) -endif() - -# # Create the libs and the main exe # add_subdirectory(Library) diff --git a/Tests/ComplexOneConfig/CMakeLists.txt b/Tests/ComplexOneConfig/CMakeLists.txt index 28b73af..5a4134d 100644 --- a/Tests/ComplexOneConfig/CMakeLists.txt +++ b/Tests/ComplexOneConfig/CMakeLists.txt @@ -389,21 +389,6 @@ if(NOT RESULT STREQUAL "a[b]c[d]e") endif() # -# This tests needs Ansi C++98 -# -set(CMAKE_CXX_STANDARD 98) -# -# GNU extensions are needed for stricmp() on Windows. -# -set(CMAKE_CXX_EXTENSIONS TRUE) - -# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND - CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - set(CMAKE_CXX_STANDARD 11) -endif() - -# # Create the libs and the main exe # add_subdirectory(Library) diff --git a/Tests/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt index 8b42296..4df29fa 100644 --- a/Tests/Cuda/Toolkit/CMakeLists.txt +++ b/Tests/Cuda/Toolkit/CMakeLists.txt @@ -54,3 +54,9 @@ endforeach() add_executable(Toolkit main.cpp) target_link_libraries(Toolkit PRIVATE CUDA::toolkit) + +# cupti is an optional component of the CUDA toolkit +if(TARGET CUDA::cupti) + add_executable(cupti cupti.cpp) + target_link_libraries(cupti PRIVATE CUDA::cupti) +endif() diff --git a/Tests/Cuda/Toolkit/cupti.cpp b/Tests/Cuda/Toolkit/cupti.cpp new file mode 100644 index 0000000..62f7f65 --- /dev/null +++ b/Tests/Cuda/Toolkit/cupti.cpp @@ -0,0 +1,7 @@ +// Only thing we care about is that these headers are found +#include <cupti.h> + +int main() +{ + return 0; +} diff --git a/Tests/Plugin/CMakeLists.txt b/Tests/Plugin/CMakeLists.txt index ec22bf4..c2f43cd 100644 --- a/Tests/Plugin/CMakeLists.txt +++ b/Tests/Plugin/CMakeLists.txt @@ -2,9 +2,6 @@ cmake_minimum_required (VERSION 2.8.12) cmake_policy(SET CMP0054 NEW) project(Plugin) -# We need proper C++98 support from the compiler -set(CMAKE_CXX_STANDARD 98) - # Test per-target output directory properties. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/plugin) @@ -21,12 +18,6 @@ include_directories( ${Plugin_SOURCE_DIR}/include ) -# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND - CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - set(CMAKE_CXX_STANDARD 11) -endif() - # Create an executable that exports an API for use by plugins. add_executable(example_exe src/example_exe.cxx src/DynamicLoader.cxx) set_target_properties(example_exe PROPERTIES diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-result.txt b/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt b/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt new file mode 100644 index 0000000..f6e2df5 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at ImportedTarget-TARGET_BUNDLE_DIR_NAME.cmake:[0-9]* \(add_custom_target\): + Error evaluating generator expression: + + \$<TARGET_BUNDLE_DIR_NAME:empty> + + TARGET_BUNDLE_DIR_NAME not allowed for IMPORTED targets. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]* \(include\) diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME.cmake b/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME.cmake new file mode 100644 index 0000000..f926f75 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME.cmake @@ -0,0 +1,2 @@ +add_library(empty UNKNOWN IMPORTED) +add_custom_target(custom COMMAND echo $<TARGET_BUNDLE_DIR_NAME:empty>) diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-result.txt b/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt b/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt new file mode 100644 index 0000000..dbbf63c --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at NonValidTarget-TARGET_BUNDLE_DIR_NAME.cmake:[0-9]* \(file\): + Error evaluating generator expression: + + \$<TARGET_BUNDLE_DIR_NAME:empty> + + TARGET_BUNDLE_DIR_NAME is allowed only for Bundle targets. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]* \(include\) diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME.cmake b/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME.cmake new file mode 100644 index 0000000..05b8e18 --- /dev/null +++ b/Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME.cmake @@ -0,0 +1,9 @@ + +enable_language(C) + +add_library(empty STATIC empty.c) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt" + CONTENT "[$<TARGET_BUNDLE_DIR_NAME:empty>]" +) diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake index 55b0f9b..148baac 100644 --- a/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake +++ b/Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake @@ -17,8 +17,10 @@ run_cmake_with_options(TARGET_FILE_BASE_NAME-imported-target -DCMAKE_BUILD_TYPE: run_cmake(TARGET_FILE_BASE_NAME-non-valid-target) run_cmake(TARGET_LINKER_FILE_BASE_NAME-non-valid-target) run_cmake(NonValidTarget-TARGET_BUNDLE_DIR) +run_cmake(NonValidTarget-TARGET_BUNDLE_DIR_NAME) run_cmake(NonValidTarget-TARGET_BUNDLE_CONTENT_DIR) run_cmake(ImportedTarget-TARGET_BUNDLE_DIR) +run_cmake(ImportedTarget-TARGET_BUNDLE_DIR_NAME) run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR) run_cmake(ImportedTarget-TARGET_PDB_FILE) run_cmake(ImportedTarget-TARGET_PDB_FILE_BASE_NAME) diff --git a/Tests/RunCMake/GenerateExportHeader/GEH.cmake b/Tests/RunCMake/GenerateExportHeader/GEH.cmake index 431d1ce..bf9c302 100644 --- a/Tests/RunCMake/GenerateExportHeader/GEH.cmake +++ b/Tests/RunCMake/GenerateExportHeader/GEH.cmake @@ -43,14 +43,6 @@ endif() include(GenerateExportHeader) -set(CMAKE_CXX_STANDARD 98) - -# Clang/C2 in C++98 mode cannot properly handle some of MSVC headers -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND - CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") - set(CMAKE_CXX_STANDARD 11) -endif() - add_subdirectory(lib_shared_and_static) if(CMAKE_SYSTEM_NAME MATCHES "AIX" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" diff --git a/Tests/RunCMake/target_sources/FileSetImport.cmake b/Tests/RunCMake/target_sources/FileSetImport.cmake index 8ef8e7d..db82ca8 100644 --- a/Tests/RunCMake/target_sources/FileSetImport.cmake +++ b/Tests/RunCMake/target_sources/FileSetImport.cmake @@ -17,12 +17,15 @@ include("${export_build_dir}/export.cmake") include("${export_build_dir}/install/lib/cmake/export.cmake") assert_prop_eq(export::lib1 HEADER_SETS "") -assert_prop_eq(export::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;dir3;e;f;g") +assert_prop_eq(export::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;e;f;g;dir3") assert_prop_eq(export::lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/error.c") +assert_prop_eq(export::lib1 HEADER_SET_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/error.c") if (_multi_config) assert_prop_eq(export::lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}") + assert_prop_eq(export::lib1 HEADER_DIRS_HEADERS "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}") else () assert_prop_eq(export::lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") + assert_prop_eq(export::lib1 HEADER_DIRS_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}") endif () assert_prop_eq(export::lib1 HEADER_SET_b "${CMAKE_CURRENT_SOURCE_DIR}/h2.h") if (_multi_config) @@ -69,9 +72,11 @@ else () endif () assert_prop_eq(install::lib1 HEADER_SETS "") -assert_prop_eq(install::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;dir3;e;f;g") +assert_prop_eq(install::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;e;f;g;dir3") assert_prop_eq(install::lib1 HEADER_SET "${export_build_dir}/install/include/error.c") assert_prop_eq(install::lib1 HEADER_DIRS "${export_build_dir}/install/include") +assert_prop_eq(install::lib1 HEADER_SET_HEADERS "${export_build_dir}/install/include/error.c") +assert_prop_eq(install::lib1 HEADER_DIRS_HEADERS "${export_build_dir}/install/include") assert_prop_eq(install::lib1 HEADER_SET_b "${export_build_dir}/install/include/h2.h") assert_prop_eq(install::lib1 HEADER_DIRS_b "${export_build_dir}/install/include") assert_prop_eq(install::lib1 HEADER_SET_c "${export_build_dir}/install/include/dir/dir.h") diff --git a/Tests/RunCMake/target_sources/FileSetProperties.cmake b/Tests/RunCMake/target_sources/FileSetProperties.cmake index 74487fe..56cce08 100644 --- a/Tests/RunCMake/target_sources/FileSetProperties.cmake +++ b/Tests/RunCMake/target_sources/FileSetProperties.cmake @@ -57,15 +57,19 @@ assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURC assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>") target_sources(lib1 PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" FILES h1.h) -assert_prop_eq(lib1 INTERFACE_HEADER_SETS "HEADERS;a;c;d") +assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d;HEADERS") assert_prop_eq(lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") assert_prop_eq(lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/h1.h") +assert_prop_eq(lib1 HEADER_DIRS_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}") +assert_prop_eq(lib1 HEADER_SET_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/h1.h") assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>") assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>") target_sources(lib1 PUBLIC FILE_SET HEADERS FILES h2.h) -assert_prop_eq(lib1 INTERFACE_HEADER_SETS "HEADERS;a;c;d") +assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d;HEADERS") assert_prop_eq(lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") assert_prop_eq(lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/h1.h;${CMAKE_CURRENT_SOURCE_DIR}/h2.h") +assert_prop_eq(lib1 HEADER_DIRS_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}") +assert_prop_eq(lib1 HEADER_SET_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/h1.h;${CMAKE_CURRENT_SOURCE_DIR}/h2.h") assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>") assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>") diff --git a/Tests/TryCompile/CMakeLists.txt b/Tests/TryCompile/CMakeLists.txt index 594f37a..000fd2c 100644 --- a/Tests/TryCompile/CMakeLists.txt +++ b/Tests/TryCompile/CMakeLists.txt @@ -201,7 +201,7 @@ add_executable(TryCompile pass.c) ###################################### -# now two tests for TRY_RUN +# now two tests for try_run() # try to run a file that should compile and run without error # also check that OUTPUT_VARIABLE contains both the compile output diff --git a/Utilities/std/cmext/enum_set b/Utilities/std/cmext/enum_set new file mode 100644 index 0000000..f97a04c --- /dev/null +++ b/Utilities/std/cmext/enum_set @@ -0,0 +1,393 @@ +// -*-c++-*- +// vim: set ft=cpp: + +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <bitset> +#include <cstddef> +#include <initializer_list> +#include <iterator> +#include <limits> +#include <utility> + +#include <cm/type_traits> + +// +// Class enum_set offers the capability to manage a set of enum values +// Only 'enum class' with unsigned base type are supported. +// +// The methods offered by 'enum_set' are close as possible to the 'std::set' +// container plus some useful methods from 'std::bitset' like 'flip'. +// +// Internally, this class use 'std::bitset' container to manage the +// set of enum. The size of the bitset is deduced from the underlying type of +// the enum. +// + +namespace cm { + +template <typename EnumSet> +class enum_set_iterator +{ +public: + enum_set_iterator() = default; + enum_set_iterator(const enum_set_iterator& other) = default; + + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename EnumSet::value_type; + using difference_type = typename EnumSet::difference_type; + using reference = typename EnumSet::reference; + using pointer = typename EnumSet::pointer; + + enum_set_iterator& operator++() + { + while (++this->Index < this->Set->max_size() && + !this->Set->test(this->Index)) + ; + + return *this; + } + enum_set_iterator operator++(int) + { + auto retval = *this; + ++(*this); + return retval; + } + + enum_set_iterator& operator--() + { + while (--this->Index >= 0 && !this->Set->test(this->Index)) + ; + + return *this; + } + enum_set_iterator operator--(int) + { + auto retval = *this; + --(*this); + return retval; + } + + reference operator*() const { return static_cast<reference>(this->Index); } + + bool operator==(enum_set_iterator other) const + { + return (this->Set == other.Set) && (this->Index == other.Index); + } + + bool operator!=(enum_set_iterator other) const { return !(*this == other); } + +private: + friend EnumSet; + + using size_type = typename EnumSet::size_type; + + enum_set_iterator(EnumSet* set, bool at_end = false) + : Set(set) + { + if (at_end || this->Set->empty()) { + this->Index = this->Set->max_size(); + } else { + while (!this->Set->test(this->Index) && + ++this->Index < this->Set->max_size()) + ; + } + } + enum_set_iterator(EnumSet* set, size_type pos) + : Index(pos) + , Set(set) + { + } + + std::size_t Index = 0; + EnumSet* Set = nullptr; +}; + +template < + typename Enum, + typename cm::enable_if_t< + std::is_enum<Enum>::value && + std::is_unsigned<typename std::underlying_type<Enum>::type>::value, + int> = 0> +class enum_set +{ +public: + using key_type = Enum; + using value_type = Enum; + using size_type = typename std::underlying_type<Enum>::type; + using difference_type = size_type; + using reference = Enum; + using const_reference = Enum; + using pointer = const Enum*; + using const_pointer = const Enum*; + + using iterator = enum_set_iterator<enum_set>; + using const_iterator = enum_set_iterator<const enum_set>; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + constexpr enum_set() noexcept = default; + enum_set(const enum_set& other) noexcept { this->insert(other); } + enum_set(std::initializer_list<value_type> list) { this->insert(list); } + + enum_set& operator=(const enum_set& other) noexcept + { + this->Set.reset(); + this->Set |= other.Set; + return *this; + } + enum_set& operator=(std::initializer_list<value_type> list) + { + this->Set.reset(); + this->insert(list); + } + + // Iterators + iterator begin() noexcept { return iterator(this); } + const_iterator begin() const noexcept { return const_iterator(this); } + const_iterator cbegin() const noexcept { return const_iterator(this); } + + iterator end() noexcept { return iterator(this, true); } + const_iterator end() const noexcept { return const_iterator(this, true); } + const_iterator cend() const noexcept { return const_iterator(this, true); } + + reverse_iterator rbegin() noexcept { return reverse_iterator(this->end()); } + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(this->end()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(this->cend()); + } + + reverse_iterator rend() noexcept { return reverse_iterator(this->begin()); } + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(this->begin()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(this->cbegin()); + } + + // Capacity + bool empty() const noexcept { return this->Set.none(); } + + size_type size() const noexcept { return this->Set.count(); } + + size_type max_size() const noexcept { return this->Set.size(); } + + // Modifiers + void clear() noexcept { this->Set.reset(); } + + enum_set& operator+=(key_type e) + { + this->insert(e); + return *this; + } + enum_set& operator+=(const enum_set& other) noexcept + { + this->erase(other); + return *this; + } + enum_set& operator+=(std::initializer_list<value_type> list) + { + this->insert(list); + return *this; + } + + enum_set& operator-=(key_type e) + { + this->erase(e); + return *this; + } + enum_set& operator-=(const enum_set& other) noexcept + { + this->erase(other); + return *this; + } + enum_set& operator-=(std::initializer_list<value_type> list) + { + this->erase(list); + return *this; + } + + std::pair<iterator, bool> insert(value_type value) + { + auto exist = this->contains(value); + if (!exist) { + this->Set.set(static_cast<size_type>(value)); + } + + return { iterator(this, static_cast<size_type>(value)), !exist }; + } + template <typename InputIt> + void insert(InputIt first, InputIt last) + { + for (auto i = first; i != last; i++) { + this->insert(*i); + } + } + void insert(const enum_set& other) noexcept { this->Set |= other.Set; } + void insert(std::initializer_list<value_type> list) + { + for (auto e : list) { + this->Set.set(static_cast<size_type>(e)); + } + } + + size_type erase(key_type key) + { + if (this->contains(key)) { + this->Set.reset(static_cast<size_type>(key)); + return 1; + } + + return 0; + } + iterator erase(iterator pos) + { + this->erase(*pos++); + return pos; + } + iterator erase(const_iterator pos) + { + this->erase(*pos++); + + return pos == this->cend() ? this->end() + : iterator(this, static_cast<size_type>(*pos)); + } + void erase(const enum_set& other) noexcept { this->Set &= ~other.Set; } + void erase(std::initializer_list<value_type> list) + { + for (auto e : list) { + this->Set.reset(static_cast<size_type>(e)); + } + } + + void swap(enum_set& other) noexcept + { + auto tmp = this->Set; + this->Set = other.Set; + other.Set = tmp; + } + + // toggle the specified enum + void flip(key_type key) { this->Set.flip(static_cast<size_type>(key)); } + // toggle all the enums stored in the other enum_set + void flip(const enum_set& other) noexcept { this->Set ^= other.Set; } + // toggle all the enums specified in the list + void flip(std::initializer_list<value_type> list) + { + for (auto e : list) { + this->Set.flip(static_cast<size_type>(e)); + } + } + + // Lookup + size_type count(key_type e) const { return this->contains(e) ? 1 : 0; } + + iterator find(key_type e) + { + if (this->contains(e)) { + return iterator(this, static_cast<size_type>(e)); + } else { + return this->end(); + } + } + const_iterator find(key_type e) const + { + if (this->contains(e)) { + return const_iterator(this, static_cast<size_type>(e)); + } else { + return this->end(); + } + } + + bool contains(key_type e) const + { + return this->Set.test(static_cast<size_type>(e)); + } + +private: + template <typename E, typename Predicate> + friend inline void erase_if(enum_set<E>& set, Predicate pred); + + friend class enum_set_iterator<enum_set>; + friend class enum_set_iterator<const enum_set>; + + bool test(size_type pos) const { return this->Set.test(pos); } + + std::bitset<std::numeric_limits<size_type>::digits> Set; +}; + +// non-member functions for enum_set +template <typename Enum> +inline enum_set<Enum> operator+(const enum_set<Enum>& lhs, Enum rhs) +{ + return enum_set<Enum>(lhs) += rhs; +} +template <typename Enum> +inline enum_set<Enum> operator+(const enum_set<Enum>& lhs, + const enum_set<Enum>& rhs) noexcept +{ + return enum_set<Enum>(lhs) += rhs; +} +template <typename Enum> +inline enum_set<Enum> operator+(const enum_set<Enum>& lhs, + const std::initializer_list<Enum> rhs) +{ + return enum_set<Enum>(lhs) += rhs; +} + +template <typename Enum> +inline enum_set<Enum> operator-(const enum_set<Enum>& lhs, Enum rhs) +{ + return enum_set<Enum>(lhs) -= rhs; +} +template <typename Enum> +inline enum_set<Enum> operator-(const enum_set<Enum>& lhs, + const enum_set<Enum>& rhs) noexcept +{ + return enum_set<Enum>(lhs) -= rhs; +} +template <typename Enum> +inline enum_set<Enum> operator-(const enum_set<Enum>& lhs, + const std::initializer_list<Enum> rhs) +{ + return enum_set<Enum>(lhs) -= rhs; +} + +template <typename Enum> +inline bool operator==(const enum_set<Enum>& lhs, + const enum_set<Enum>& rhs) noexcept +{ + return lhs == rhs; +} + +template <typename Enum> +inline bool operator!=(const enum_set<Enum>& lhs, + const enum_set<Enum>& rhs) noexcept +{ + return !(lhs == rhs); +} + +template <typename Enum> +inline void erase(enum_set<Enum>& set, Enum value) +{ + set.erase(value); +} + +template <typename Enum, typename Predicate> +inline void erase_if(enum_set<Enum>& set, Predicate pred) +{ + for (std::size_t index = 0; index < set.Set.size(); ++index) { + if (set.Set.test(index) && pred(static_cast<Enum>(index))) { + set.Set.reset(index); + } + } +} +} // namespace cm |