summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/configure_windows_common.cmake1
-rw-r--r--.gitlab/os-macos.yml12
-rw-r--r--Auxiliary/vim/syntax/cmake.vim1
-rw-r--r--Help/dev/source.rst5
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst24
-rw-r--r--Help/policy/CMP0112.rst1
-rw-r--r--Help/release/dev/target-bundle-dir-name-genex.rst6
-rw-r--r--Modules/FindBoost.cmake3
-rw-r--r--Modules/FindCUDAToolkit.cmake27
-rw-r--r--Modules/FindThreads.cmake76
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmEnableTestingCommand.h4
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.h2
-rw-r--r--Source/cmExportBuildFileGenerator.h2
-rw-r--r--Source/cmGeneratorExpressionNode.cxx40
-rw-r--r--Source/cmQtAutoGen.cxx7
-rw-r--r--Source/cmQtAutoGen.h5
-rw-r--r--Source/cmQtAutoMocUic.cxx51
-rw-r--r--Source/cmTarget.cxx550
-rw-r--r--Source/cmTryCompileCommand.cxx2
-rw-r--r--Source/cmTryRunCommand.cxx20
-rw-r--r--Tests/AliasTarget/CMakeLists.txt8
-rw-r--r--Tests/CMakeLib/CMakeLists.txt1
-rw-r--r--Tests/CMakeLib/testCMExtEnumSet.cxx204
-rw-r--r--Tests/CMakeLists.txt2
-rw-r--r--Tests/CTestTestScheduler/sleep.c2
-rw-r--r--Tests/CTestTestStopTime/sleep.c2
-rw-r--r--Tests/Complex/CMakeLists.txt15
-rw-r--r--Tests/ComplexOneConfig/CMakeLists.txt15
-rw-r--r--Tests/Cuda/Toolkit/CMakeLists.txt6
-rw-r--r--Tests/Cuda/Toolkit/cupti.cpp7
-rw-r--r--Tests/Plugin/CMakeLists.txt9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/ImportedTarget-TARGET_BUNDLE_DIR_NAME.cmake2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-result.txt1
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME-stderr.txt8
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/NonValidTarget-TARGET_BUNDLE_DIR_NAME.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/GenerateExportHeader/GEH.cmake8
-rw-r--r--Tests/RunCMake/target_sources/FileSetImport.cmake9
-rw-r--r--Tests/RunCMake/target_sources/FileSetProperties.cmake8
-rw-r--r--Tests/TryCompile/CMakeLists.txt2
-rw-r--r--Utilities/std/cmext/enum_set393
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