summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/ctest_exclusions.cmake3
-rw-r--r--Modules/CMakeMSYSFindMake.cmake11
-rw-r--r--Modules/FindCUDAToolkit.cmake35
-rw-r--r--Modules/FindMsys.cmake9
-rw-r--r--Modules/Platform/Windows-OpenWatcom.cmake47
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmDyndepCollation.cxx652
-rw-r--r--Source/cmDyndepCollation.h52
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx379
-rw-r--r--Source/cmGlobalNinjaGenerator.h4
-rw-r--r--Source/cmNinjaTargetGenerator.cxx224
-rw-r--r--Source/cmStringAlgorithms.cxx18
-rw-r--r--Source/cmStringAlgorithms.h43
-rw-r--r--Source/cmStringCommand.cxx64
-rw-r--r--Tests/CMakeLib/testStringAlgorithms.cxx14
-rw-r--r--Tests/Cuda/Toolkit/CMakeLists.txt5
-rw-r--r--Tests/CudaOnly/Toolkit/CMakeLists.txt6
18 files changed, 918 insertions, 652 deletions
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
index b29e785..a2789c3 100644
--- a/.gitlab/ci/ctest_exclusions.cmake
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -31,9 +31,6 @@ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "nvhpc_")
list(APPEND test_exclusions
# FIXME(#24187): This test fails with NVHPC as the CUDA host compiler.
"^CudaOnly.SeparateCompilationPTX$"
-
- # FIXME(#24188): FindCUDAToolkit breaks on some symlink layouts.
- "^Cuda.Toolkit$"
)
endif()
diff --git a/Modules/CMakeMSYSFindMake.cmake b/Modules/CMakeMSYSFindMake.cmake
index 33b02c9..96fdb37 100644
--- a/Modules/CMakeMSYSFindMake.cmake
+++ b/Modules/CMakeMSYSFindMake.cmake
@@ -3,8 +3,13 @@
find_program(CMAKE_MAKE_PROGRAM make
+ REGISTRY_VIEW 32
PATHS
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS-1.0_is1;Inno Setup: App Path]/bin"
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin"
- c:/msys/1.0/bin /msys/1.0/bin)
+ # Typical install path for 32-bit MSYS2 (https://repo.msys2.org/distrib/msys2-i686-latest.sfx.exe)
+ "C:/msys32/usr"
+ # Typical install path for MINGW32 (https://sourceforge.net/projects/mingw)
+ "C:/mingw/msys"
+ # Git for Windows 32-bit (https://gitforwindows.org/)
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GitForWindows;InstallPath]/usr")
+
mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index a4cebe4..5df31da 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -894,8 +894,25 @@ mark_as_advanced(CUDA_CUDART
if(CUDAToolkit_FOUND)
set(CUDAToolkit_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIR})
get_filename_component(CUDAToolkit_LIBRARY_DIR ${CUDA_CUDART} DIRECTORY ABSOLUTE)
+
+ # Build search paths without any symlinks
+ file(REAL_PATH "${CUDAToolkit_LIBRARY_DIR}" _cmake_search_dir)
+ set(CUDAToolkit_LIBRARY_SEARCH_DIRS "${_cmake_search_dir}")
+
+ # Detect we are in a splayed nvhpc toolkit layout and add extra
+ # search paths without symlinks
+ if(CUDAToolkit_LIBRARY_DIR MATCHES ".*/cuda/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64$")
+ # Search location for math_libs/
+ file(REAL_PATH "${CUDAToolkit_LIBRARY_DIR}/../../../" _cmake_search_dir)
+ list(APPEND CUDAToolkit_LIBRARY_SEARCH_DIRS "${_cmake_search_dir}")
+
+ # Search location for extras like cupti
+ file(REAL_PATH "${CUDAToolkit_LIBRARY_DIR}/../" _cmake_search_dir)
+ list(APPEND CUDAToolkit_LIBRARY_SEARCH_DIRS "${_cmake_search_dir}")
+ endif()
endif()
+
#-----------------------------------------------------------------------------
# Construct import targets
if(CUDAToolkit_FOUND)
@@ -907,21 +924,21 @@ if(CUDAToolkit_FOUND)
find_library(CUDA_${lib_name}_LIBRARY
NAMES ${search_names}
- HINTS ${CUDAToolkit_LIBRARY_DIR}
+ HINTS ${CUDAToolkit_LIBRARY_SEARCH_DIRS}
ENV CUDA_PATH
PATH_SUFFIXES nvidia/current lib64 lib/x64 lib
+ # Support NVHPC splayed math library layout
+ math_libs/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64
+ math_libs/lib64
${arg_EXTRA_PATH_SUFFIXES}
)
# Don't try any stub directories until we have exhausted all other
# search locations.
find_library(CUDA_${lib_name}_LIBRARY
NAMES ${search_names}
- HINTS ${CUDAToolkit_LIBRARY_DIR}
+ HINTS ${CUDAToolkit_LIBRARY_SEARCH_DIRS}
ENV CUDA_PATH
PATH_SUFFIXES lib64/stubs lib/x64/stubs lib/stubs stubs
- # Support NVHPC splayed math library layout
- ../../math_libs/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64
- ../../math_libs/lib64
)
mark_as_advanced(CUDA_${lib_name}_LIBRARY)
@@ -1054,11 +1071,15 @@ if(CUDAToolkit_FOUND)
if(CUDAToolkit_CUPTI_INCLUDE_DIR)
_CUDAToolkit_find_and_add_import_lib(cupti
- EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+ EXTRA_PATH_SUFFIXES extras/CUPTI/lib64/
+ extras/CUPTI/lib/
+ ../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/
+ EXTRA_PATH_SUFFIXES extras/CUPTI/lib64/
+ extras/CUPTI/lib/
+ ../extras/CUPTI/lib64/
../extras/CUPTI/lib/
EXTRA_INCLUDE_DIRS "${CUDAToolkit_CUPTI_INCLUDE_DIR}")
endif()
diff --git a/Modules/FindMsys.cmake b/Modules/FindMsys.cmake
index b4796d2..86597c2 100644
--- a/Modules/FindMsys.cmake
+++ b/Modules/FindMsys.cmake
@@ -19,11 +19,12 @@ if (WIN32)
find_program(MSYS_CMD
NAMES msys2_shell.cmd
PATHS
- "C:/msys64"
+ # Typical install path for MSYS2 (https://repo.msys2.org/distrib/msys2-i686-latest.sfx.exe)
"C:/msys32"
- "C:/MSYS"
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MSYS\\setup;rootdir]"
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Cygnus Solutions\\MSYS\\mounts v2\\/;native]"
+ # Typical install path for MSYS2 (https://repo.msys2.org/distrib/msys2-x86_64-latest.sfx.exe)
+ "C:/msys64"
+ # Git for Windows (https://gitforwindows.org/)
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GitForWindows;InstallPath]"
)
get_filename_component(MSYS_INSTALL_PATH "${MSYS_CMD}" DIRECTORY)
mark_as_advanced(MSYS_CMD)
diff --git a/Modules/Platform/Windows-OpenWatcom.cmake b/Modules/Platform/Windows-OpenWatcom.cmake
index 657a923..4e73160 100644
--- a/Modules/Platform/Windows-OpenWatcom.cmake
+++ b/Modules/Platform/Windows-OpenWatcom.cmake
@@ -6,8 +6,13 @@ include_guard()
set(CMAKE_BUILD_TYPE_INIT Debug)
-string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system nt_dll")
-string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system nt_dll")
+if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system windows")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system windows")
+else()
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system nt_dll")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system nt_dll")
+endif()
set(CMAKE_C_COMPILE_OPTIONS_DLL "-bd") # Note: This variable is a ';' separated list
set(CMAKE_SHARED_LIBRARY_C_FLAGS "-bd") # ... while this is a space separated string.
@@ -23,22 +28,45 @@ else()
set(_br_bm "-br -bm")
endif()
-string(APPEND CMAKE_C_FLAGS_INIT " -bt=nt -dWIN32 ${_br_bm}")
-string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=nt -xs -dWIN32 ${_br_bm}")
+if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ string(APPEND CMAKE_C_FLAGS_INIT " -bt=windows ")
+ string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=windows ")
+else()
+ string(APPEND CMAKE_C_FLAGS_INIT " -bt=nt -dWIN32 ${_br_bm}")
+ string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=nt -xs -dWIN32 ${_br_bm}")
+endif()
unset(__WINDOWS_WATCOM_CMP0136)
unset(_br_bm)
if(CMAKE_CROSSCOMPILING)
- if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
- set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
- endif()
- if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
- set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
+ if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/win)
+ endif()
+ if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/win)
+ endif()
+ else()
+ if(NOT CMAKE_C_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
+ endif()
+ if(NOT CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
+ endif()
endif()
endif()
macro(__windows_open_watcom lang)
+if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ set(CMAKE_${lang}_CREATE_WIN32_EXE "system windows")
+ set(CMAKE_${lang}_CREATE_CONSOLE_EXE "system windows")
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_SingleThreaded "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_SingleThreadedDLL "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_MultiThreaded "")
+ set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_MultiThreadedDLL "")
+else()
set(CMAKE_${lang}_CREATE_WIN32_EXE "system nt_win")
set(CMAKE_${lang}_CREATE_CONSOLE_EXE "system nt")
@@ -46,4 +74,5 @@ macro(__windows_open_watcom lang)
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_SingleThreadedDLL -br)
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_MultiThreaded -bm)
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_MultiThreadedDLL -bm -br)
+endif()
endmacro()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index c0709c6..41a901a 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -198,6 +198,8 @@ add_library(
cmDocumentationFormatter.cxx
cmDynamicLoader.cxx
cmDynamicLoader.h
+ cmDyndepCollation.cxx
+ cmDyndepCollation.h
cmELF.h
cmELF.cxx
cmExprParserHelper.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index d2236b1..c3c47ae 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 25)
-set(CMake_VERSION_PATCH 20221201)
+set(CMake_VERSION_PATCH 20221202)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx
new file mode 100644
index 0000000..2827659
--- /dev/null
+++ b/Source/cmDyndepCollation.cxx
@@ -0,0 +1,652 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmDyndepCollation.h"
+
+#include <algorithm>
+#include <map>
+#include <ostream>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportSet.h"
+#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h" // IWYU pragma: keep
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmScanDepFormat.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+namespace {
+
+Json::Value CollationInformationCxxModules(
+ cmGeneratorTarget const* gt, std::string const& config,
+ cmDyndepGeneratorCallbacks const& cb)
+{
+ cmTarget const* tgt = gt->Target;
+ auto all_file_sets = tgt->GetAllFileSetNames();
+ Json::Value tdi_cxx_module_info = Json::objectValue;
+ for (auto const& file_set_name : all_file_sets) {
+ auto const* file_set = tgt->GetFileSet(file_set_name);
+ if (!file_set) {
+ gt->Makefile->IssueMessage(MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"",
+ file_set_name,
+ "\", but it was not found."));
+ continue;
+ }
+ auto fs_type = file_set->GetType();
+ // We only care about C++ module sources here.
+ if (fs_type != "CXX_MODULES"_s) {
+ continue;
+ }
+
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, gt->LocalGenerator, config, gt);
+ std::map<std::string, std::vector<std::string>> files_per_dirs;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
+ gt->LocalGenerator, config, gt);
+ }
+
+ std::map<std::string, cmSourceFile const*> sf_map;
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(objectSources, config);
+ for (auto const* sf : objectSources) {
+ auto full_path = sf->GetFullPath();
+ if (full_path.empty()) {
+ gt->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" has a full path-less source file."));
+ continue;
+ }
+ sf_map[full_path] = sf;
+ }
+ }
+
+ Json::Value fs_dest = Json::nullValue;
+ for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
+ if (auto const* fsg =
+ dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
+ if (fsg->GetTarget() == gt && fsg->GetFileSet() == file_set) {
+ fs_dest = fsg->GetDestination(config);
+ continue;
+ }
+ }
+ }
+
+ for (auto const& files_per_dir : files_per_dirs) {
+ for (auto const& file : files_per_dir.second) {
+ auto lookup = sf_map.find(file);
+ if (lookup == sf_map.end()) {
+ gt->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file,
+ R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
+ continue;
+ }
+
+ auto const* sf = lookup->second;
+
+ if (!sf) {
+ gt->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file, "\" which has not been tracked properly."));
+ continue;
+ }
+
+ auto obj_path = cb.ObjectFilePath(sf, config);
+ Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
+ Json::objectValue;
+
+ tdi_module_info["source"] = file;
+ tdi_module_info["relative-directory"] = files_per_dir.first;
+ tdi_module_info["name"] = file_set->GetName();
+ tdi_module_info["type"] = file_set->GetType();
+ tdi_module_info["visibility"] =
+ std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
+ tdi_module_info["destination"] = fs_dest;
+ }
+ }
+ }
+
+ return tdi_cxx_module_info;
+}
+
+Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt,
+ std::string const& config)
+{
+ cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
+ for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
+ if (auto const* bmig =
+ dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
+ if (bmig->GetTarget() == gt) {
+ bmi_gen = bmig;
+ continue;
+ }
+ }
+ }
+ if (bmi_gen) {
+ Json::Value tdi_bmi_info = Json::objectValue;
+
+ tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
+ tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
+ const char* msg_level = "";
+ switch (bmi_gen->GetMessageLevel()) {
+ case cmInstallGenerator::MessageDefault:
+ break;
+ case cmInstallGenerator::MessageAlways:
+ msg_level = "MESSAGE_ALWAYS";
+ break;
+ case cmInstallGenerator::MessageLazy:
+ msg_level = "MESSAGE_LAZY";
+ break;
+ case cmInstallGenerator::MessageNever:
+ msg_level = "MESSAGE_NEVER";
+ break;
+ }
+ tdi_bmi_info["message-level"] = msg_level;
+ tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
+
+ return tdi_bmi_info;
+ }
+ return Json::nullValue;
+}
+
+Json::Value CollationInformationExports(cmGeneratorTarget const* gt)
+{
+ Json::Value tdi_exports = Json::arrayValue;
+ std::string export_name = gt->GetExportName();
+
+ auto const& all_install_exports = gt->GetGlobalGenerator()->GetExportSets();
+ for (auto const& exp : all_install_exports) {
+ // Ignore exports sets which are not for this target.
+ auto const& targets = exp.second.GetTargetExports();
+ auto tgt_export =
+ std::find_if(targets.begin(), targets.end(),
+ [gt](std::unique_ptr<cmTargetExport> const& te) {
+ return te->Target == gt;
+ });
+ if (tgt_export == targets.end()) {
+ continue;
+ }
+
+ auto const* installs = exp.second.GetInstallations();
+ for (auto const* install : *installs) {
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = install->GetNamespace();
+ auto const& dest = install->GetDestination();
+ auto const& cxxm_dir = install->GetCxxModuleDirectory();
+ auto const& export_prefix = install->GetTempDir();
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = true;
+
+ tdi_exports.append(tdi_export_info);
+ }
+ }
+
+ auto const& all_build_exports = gt->Makefile->GetExportBuildFileGenerators();
+ for (auto const& exp : all_build_exports) {
+ std::vector<std::string> targets;
+ exp->GetTargets(targets);
+
+ // Ignore exports sets which are not for this target.
+ auto const& name = gt->GetName();
+ bool has_current_target =
+ std::any_of(targets.begin(), targets.end(),
+ [name](std::string const& tname) { return tname == name; });
+ if (!has_current_target) {
+ continue;
+ }
+
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = exp->GetNamespace();
+ auto const& main_fn = exp->GetMainExportFileName();
+ auto const& cxxm_dir = exp->GetCxxModuleDirectory();
+ auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
+ auto const& export_prefix =
+ cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = false;
+
+ tdi_exports.append(tdi_export_info);
+ }
+
+ return tdi_exports;
+}
+}
+
+void cmDyndepCollation::AddCollationInformation(
+ Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config,
+ cmDyndepGeneratorCallbacks const& cb)
+{
+ tdi["cxx-modules"] = CollationInformationCxxModules(gt, config, cb);
+ tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config);
+ tdi["exports"] = CollationInformationExports(gt);
+ tdi["config"] = config;
+}
+
+struct CxxModuleFileSet
+{
+ std::string Name;
+ std::string RelativeDirectory;
+ std::string SourcePath;
+ std::string Type;
+ cmFileSetVisibility Visibility;
+ cm::optional<std::string> Destination;
+};
+
+struct CxxModuleBmiInstall
+{
+ std::string Component;
+ std::string Destination;
+ bool ExcludeFromAll;
+ bool Optional;
+ std::string Permissions;
+ std::string MessageLevel;
+ std::string ScriptLocation;
+};
+
+struct CxxModuleExport
+{
+ std::string Name;
+ std::string Destination;
+ std::string Prefix;
+ std::string CxxModuleInfoDir;
+ std::string Namespace;
+ bool Install;
+};
+
+struct cmCxxModuleExportInfo
+{
+ std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
+ cm::optional<CxxModuleBmiInstall> BmiInstallation;
+ std::vector<CxxModuleExport> Exports;
+ std::string Config;
+};
+
+void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const
+{
+ delete ei;
+}
+
+std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
+cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
+{
+ auto export_info =
+ std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>(
+ new cmCxxModuleExportInfo);
+
+ export_info->Config = tdi["config"].asString();
+ if (export_info->Config.empty()) {
+ export_info->Config = "noconfig";
+ }
+ Json::Value const& tdi_exports = tdi["exports"];
+ if (tdi_exports.isArray()) {
+ for (auto const& tdi_export : tdi_exports) {
+ CxxModuleExport exp;
+ exp.Install = tdi_export["install"].asBool();
+ exp.Name = tdi_export["export-name"].asString();
+ exp.Destination = tdi_export["destination"].asString();
+ exp.Prefix = tdi_export["export-prefix"].asString();
+ exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
+ exp.Namespace = tdi_export["namespace"].asString();
+
+ export_info->Exports.push_back(exp);
+ }
+ }
+ auto const& bmi_installation = tdi["bmi-installation"];
+ if (bmi_installation.isObject()) {
+ CxxModuleBmiInstall bmi_install;
+
+ bmi_install.Component = bmi_installation["component"].asString();
+ bmi_install.Destination = bmi_installation["destination"].asString();
+ bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
+ bmi_install.Optional = bmi_installation["optional"].asBool();
+ bmi_install.Permissions = bmi_installation["permissions"].asString();
+ bmi_install.MessageLevel = bmi_installation["message-level"].asString();
+ bmi_install.ScriptLocation =
+ bmi_installation["script-location"].asString();
+
+ export_info->BmiInstallation = bmi_install;
+ }
+ Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
+ if (tdi_cxx_modules.isObject()) {
+ for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
+ CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()];
+ auto const& tdi_cxx_module_info = *i;
+ fsi.Name = tdi_cxx_module_info["name"].asString();
+ fsi.RelativeDirectory =
+ tdi_cxx_module_info["relative-directory"].asString();
+ fsi.SourcePath = tdi_cxx_module_info["source"].asString();
+ fsi.Type = tdi_cxx_module_info["type"].asString();
+ fsi.Visibility = cmFileSetVisibilityFromName(
+ tdi_cxx_module_info["visibility"].asString(), nullptr);
+ auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
+ if (tdi_fs_dest.isString()) {
+ fsi.Destination = tdi_fs_dest.asString();
+ }
+ }
+ }
+
+ return export_info;
+}
+
+bool cmDyndepCollation::WriteDyndepMetadata(
+ std::string const& lang, std::vector<cmScanDepInfo> const& objects,
+ cmCxxModuleExportInfo const& export_info,
+ cmDyndepMetadataCallbacks const& cb)
+{
+ // Only C++ supports any of the file-set or BMI installation considered
+ // below.
+ if (lang != "CXX"_s) {
+ return true;
+ }
+
+ bool result = true;
+
+ // Prepare the export information blocks.
+ std::string const config_upper =
+ cmSystemTools::UpperCase(export_info.Config);
+ std::vector<
+ std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>>
+ exports;
+ for (auto const& exp : export_info.Exports) {
+ std::unique_ptr<cmGeneratedFileStream> properties;
+
+ std::string const export_dir =
+ cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
+ std::string const property_file_path = cmStrCat(
+ export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
+ properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
+
+ // Set up the preamble.
+ *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
+ << "\"\n"
+ << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n';
+
+ exports.emplace_back(std::move(properties), &exp);
+ }
+
+ std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
+ if (export_info.BmiInstallation) {
+ bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
+ export_info.BmiInstallation->ScriptLocation);
+ }
+
+ auto cmEscape = [](cm::string_view str) {
+ return cmOutputConverter::EscapeForCMake(
+ str, cmOutputConverter::WrapQuotes::NoWrap);
+ };
+ auto install_destination =
+ [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
+ if (cmSystemTools::FileIsFullPath(dest)) {
+ return std::make_pair(true, cmEscape(dest));
+ }
+ return std::make_pair(false,
+ cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
+ };
+
+ // public/private requirement tracking.
+ std::set<std::string> private_modules;
+ std::map<std::string, std::set<std::string>> public_source_requires;
+
+ for (cmScanDepInfo const& object : objects) {
+ // Convert to forward slashes.
+ auto output_path = object.PrimaryOutput;
+#ifdef _WIN32
+ cmSystemTools::ConvertToUnixSlashes(output_path);
+#endif
+ // Find the fileset for this object.
+ auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
+ bool const has_provides = !object.Provides.empty();
+ if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
+ // If it provides anything, it should have a `CXX_MODULES` or
+ // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
+ if (has_provides) {
+ // Take the first module provided to provide context.
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(cmStrCat(
+ "Output ", object.PrimaryOutput, " provides the `",
+ provides.LogicalName,
+ "` module but it is not found in a `FILE_SET` of type ", ok_types));
+ result = false;
+ }
+
+ // This object file does not provide anything, so nothing more needs to
+ // be done.
+ continue;
+ }
+
+ auto const& file_set = fileset_info_itr->second;
+
+ // Verify the fileset type for the object.
+ if (file_set.Type == "CXX_MODULES"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(
+ cmStrCat("Output ", object.PrimaryOutput,
+ " is of type `CXX_MODULES` but does not provide a module"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(
+ cmStrCat("Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module"));
+ result = false;
+ continue;
+ }
+ auto const& provides = object.Provides[0];
+ if (provides.LogicalName.find(':') == std::string::npos) {
+ cmSystemTools::Error(
+ cmStrCat("Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module partition"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
+ // TODO.
+ } else {
+ if (has_provides) {
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(
+ cmStrCat("Source ", file_set.SourcePath, " provides the `",
+ provides.LogicalName, "` C++ module but is of type `",
+ file_set.Type, "` module but must be of type ", ok_types));
+ result = false;
+ }
+
+ // Not a C++ module; ignore.
+ continue;
+ }
+
+ if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
+ // Nothing needs to be conveyed about non-`PUBLIC` modules.
+ for (auto const& p : object.Provides) {
+ private_modules.insert(p.LogicalName);
+ }
+ continue;
+ }
+
+ // The module is public. Record what it directly requires.
+ {
+ auto& reqs = public_source_requires[file_set.SourcePath];
+ for (auto const& r : object.Requires) {
+ reqs.insert(r.LogicalName);
+ }
+ }
+
+ // Write out properties and install rules for any exports.
+ for (auto const& p : object.Provides) {
+ bool bmi_dest_is_abs = false;
+ std::string bmi_destination;
+ if (export_info.BmiInstallation) {
+ auto dest =
+ install_destination(export_info.BmiInstallation->Destination);
+ bmi_dest_is_abs = dest.first;
+ bmi_destination = cmStrCat(dest.second, '/');
+ }
+
+ std::string install_bmi_path;
+ std::string build_bmi_path;
+ auto m = cb.ModuleFile(p.LogicalName);
+ if (m) {
+ install_bmi_path = cmStrCat(
+ bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m)));
+ build_bmi_path = cmEscape(*m);
+ }
+
+ for (auto const& exp : exports) {
+ std::string iface_source;
+ if (exp.second->Install && file_set.Destination) {
+ auto dest = install_destination(*file_set.Destination);
+ iface_source = cmStrCat(
+ dest.second, '/', cmEscape(file_set.RelativeDirectory),
+ cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
+ } else {
+ iface_source = cmEscape(file_set.SourcePath);
+ }
+
+ std::string bmi_path;
+ if (exp.second->Install && export_info.BmiInstallation) {
+ bmi_path = install_bmi_path;
+ } else if (!exp.second->Install) {
+ bmi_path = build_bmi_path;
+ }
+
+ if (iface_source.empty()) {
+ // No destination for the C++ module source; ignore this property
+ // value.
+ continue;
+ }
+
+ *exp.first << " \"" << cmEscape(p.LogicalName) << '='
+ << iface_source;
+ if (!bmi_path.empty()) {
+ *exp.first << ',' << bmi_path;
+ }
+ *exp.first << "\"\n";
+ }
+
+ if (bmi_install_script) {
+ auto const& bmi_install = *export_info.BmiInstallation;
+
+ *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
+ << cmEscape(bmi_install.Component) << '\"';
+ if (!bmi_install.ExcludeFromAll) {
+ *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
+ }
+ *bmi_install_script << ")\n";
+ *bmi_install_script << " file(INSTALL\n"
+ " DESTINATION \"";
+ if (!bmi_dest_is_abs) {
+ *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
+ }
+ *bmi_install_script << cmEscape(bmi_install.Destination)
+ << "\"\n"
+ " TYPE FILE\n";
+ if (bmi_install.Optional) {
+ *bmi_install_script << " OPTIONAL\n";
+ }
+ if (!bmi_install.MessageLevel.empty()) {
+ *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
+ }
+ if (!bmi_install.Permissions.empty()) {
+ *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
+ << "\n";
+ }
+ *bmi_install_script << " FILES \"" << *m << "\")\n";
+ if (bmi_dest_is_abs) {
+ *bmi_install_script
+ << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
+ " \""
+ << cmEscape(cmSystemTools::GetFilenameName(*m))
+ << "\")\n"
+ " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(WARNING\n"
+ " \"ABSOLUTE path INSTALL DESTINATION : "
+ "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n"
+ " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(FATAL_ERROR\n"
+ " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
+ "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n";
+ }
+ *bmi_install_script << "endif ()\n";
+ }
+ }
+ }
+
+ // Add trailing parenthesis for the `set_property` call.
+ for (auto const& exp : exports) {
+ *exp.first << ")\n";
+ }
+
+ // Check that public sources only require public modules.
+ for (auto const& pub_reqs : public_source_requires) {
+ for (auto const& req : pub_reqs.second) {
+ if (private_modules.count(req)) {
+ cmSystemTools::Error(cmStrCat(
+ "Public C++ module source `", pub_reqs.first, "` requires the `",
+ req, "` C++ module which is provided by a private source"));
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/Source/cmDyndepCollation.h b/Source/cmDyndepCollation.h
new file mode 100644
index 0000000..e70ac09
--- /dev/null
+++ b/Source/cmDyndepCollation.h
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+class cmGeneratorTarget;
+struct cmScanDepInfo;
+class cmSourceFile;
+
+namespace Json {
+class Value;
+}
+
+struct cmDyndepGeneratorCallbacks
+{
+ std::function<std::string(cmSourceFile const* sf, std::string const& config)>
+ ObjectFilePath;
+};
+
+struct cmDyndepMetadataCallbacks
+{
+ std::function<cm::optional<std::string>(std::string const& name)> ModuleFile;
+};
+
+struct cmCxxModuleExportInfo;
+struct cmCxxModuleExportInfoDeleter
+{
+ void operator()(cmCxxModuleExportInfo* ei) const;
+};
+
+struct cmDyndepCollation
+{
+ static void AddCollationInformation(Json::Value& tdi,
+ cmGeneratorTarget const* gt,
+ std::string const& config,
+ cmDyndepGeneratorCallbacks const& cb);
+
+ static std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
+ ParseExportInfo(Json::Value const& tdi);
+ static bool WriteDyndepMetadata(std::string const& lang,
+ std::vector<cmScanDepInfo> const& objects,
+ cmCxxModuleExportInfo const& export_info,
+ cmDyndepMetadataCallbacks const& cb);
+};
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 618dfb7..4500f33 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -25,7 +25,7 @@
#include "cmsys/FStream.hxx"
#include "cmCxxModuleMapper.h"
-#include "cmFileSet.h"
+#include "cmDyndepCollation.h"
#include "cmFortranParser.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpressionEvaluationFile.h"
@@ -2468,45 +2468,6 @@ cm::optional<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
}
}
-struct CxxModuleFileSet
-{
- std::string Name;
- std::string RelativeDirectory;
- std::string SourcePath;
- std::string Type;
- cmFileSetVisibility Visibility;
- cm::optional<std::string> Destination;
-};
-
-struct CxxModuleBmiInstall
-{
- std::string Component;
- std::string Destination;
- bool ExcludeFromAll;
- bool Optional;
- std::string Permissions;
- std::string MessageLevel;
- std::string ScriptLocation;
-};
-
-struct CxxModuleExport
-{
- std::string Name;
- std::string Destination;
- std::string Prefix;
- std::string CxxModuleInfoDir;
- std::string Namespace;
- bool Install;
-};
-
-struct cmGlobalNinjaGenerator::CxxModuleExportInfo
-{
- std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
- cm::optional<CxxModuleBmiInstall> BmiInstallation;
- std::vector<CxxModuleExport> Exports;
- std::string Config;
-};
-
bool cmGlobalNinjaGenerator::WriteDyndepFile(
std::string const& dir_top_src, std::string const& dir_top_bld,
std::string const& dir_cur_src, std::string const& dir_cur_bld,
@@ -2514,7 +2475,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
std::string const& module_dir,
std::vector<std::string> const& linked_target_dirs,
std::string const& arg_lang, std::string const& arg_modmapfmt,
- CxxModuleExportInfo const& export_info)
+ cmCxxModuleExportInfo const& export_info)
{
// Setup path conversions.
{
@@ -2749,279 +2710,18 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmGeneratedFileStream tmf(target_mods_file);
tmf << target_module_info;
- bool result = true;
-
- // Fortran doesn't support any of the file-set or BMI installation considered
- // below.
- if (arg_lang != "Fortran"_s) {
- // Prepare the export information blocks.
- std::string const config_upper =
- cmSystemTools::UpperCase(export_info.Config);
- std::vector<std::pair<std::unique_ptr<cmGeneratedFileStream>,
- CxxModuleExport const*>>
- exports;
- for (auto const& exp : export_info.Exports) {
- std::unique_ptr<cmGeneratedFileStream> properties;
-
- std::string const export_dir =
- cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
- std::string const property_file_path = cmStrCat(
- export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
- properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
-
- // Set up the preamble.
- *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
- << "\"\n"
- << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper
- << '\n';
-
- exports.emplace_back(std::move(properties), &exp);
- }
-
- std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
- if (export_info.BmiInstallation) {
- bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
- export_info.BmiInstallation->ScriptLocation);
- }
-
- auto cmEscape = [](cm::string_view str) {
- return cmOutputConverter::EscapeForCMake(
- str, cmOutputConverter::WrapQuotes::NoWrap);
- };
- auto install_destination =
- [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
- if (cmSystemTools::FileIsFullPath(dest)) {
- return std::make_pair(true, cmEscape(dest));
- }
- return std::make_pair(false,
- cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
- };
-
- // public/private requirement tracking.
- std::set<std::string> private_modules;
- std::map<std::string, std::set<std::string>> public_source_requires;
-
- for (cmScanDepInfo const& object : objects) {
- // Convert to forward slashes.
- auto output_path = object.PrimaryOutput;
-# ifdef _WIN32
- cmSystemTools::ConvertToUnixSlashes(output_path);
-# endif
- // Find the fileset for this object.
- auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
- bool const has_provides = !object.Provides.empty();
- if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
- // If it provides anything, it should have a `CXX_MODULES` or
- // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
- if (has_provides) {
- // Take the first module provided to provide context.
- auto const& provides = object.Provides[0];
- char const* ok_types = "`CXX_MODULES`";
- if (provides.LogicalName.find(':') != std::string::npos) {
- ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
- "it is not `export`ed)";
- }
- cmSystemTools::Error(
- cmStrCat("Output ", object.PrimaryOutput, " provides the `",
- provides.LogicalName,
- "` module but it is not found in a `FILE_SET` of type ",
- ok_types));
- result = false;
- }
-
- // This object file does not provide anything, so nothing more needs to
- // be done.
- continue;
- }
-
- auto const& file_set = fileset_info_itr->second;
-
- // Verify the fileset type for the object.
- if (file_set.Type == "CXX_MODULES"_s) {
- if (!has_provides) {
- cmSystemTools::Error(cmStrCat(
- "Output ", object.PrimaryOutput,
- " is of type `CXX_MODULES` but does not provide a module"));
- result = false;
- continue;
- }
- } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
- if (!has_provides) {
- cmSystemTools::Error(cmStrCat(
- "Source ", file_set.SourcePath,
- " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
- "provide a module"));
- result = false;
- continue;
- }
- auto const& provides = object.Provides[0];
- if (provides.LogicalName.find(':') == std::string::npos) {
- cmSystemTools::Error(cmStrCat(
- "Source ", file_set.SourcePath,
- " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
- "provide a module partition"));
- result = false;
- continue;
- }
- } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
- // TODO.
- } else {
- if (has_provides) {
- auto const& provides = object.Provides[0];
- char const* ok_types = "`CXX_MODULES`";
- if (provides.LogicalName.find(':') != std::string::npos) {
- ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
- "it is not `export`ed)";
- }
- cmSystemTools::Error(cmStrCat(
- "Source ", file_set.SourcePath, " provides the `",
- provides.LogicalName, "` C++ module but is of type `",
- file_set.Type, "` module but must be of type ", ok_types));
- result = false;
- }
-
- // Not a C++ module; ignore.
- continue;
- }
-
- if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
- // Nothing needs to be conveyed about non-`PUBLIC` modules.
- for (auto const& p : object.Provides) {
- private_modules.insert(p.LogicalName);
- }
- continue;
- }
-
- // The module is public. Record what it directly requires.
- {
- auto& reqs = public_source_requires[file_set.SourcePath];
- for (auto const& r : object.Requires) {
- reqs.insert(r.LogicalName);
- }
- }
-
- // Write out properties and install rules for any exports.
- for (auto const& p : object.Provides) {
- bool bmi_dest_is_abs = false;
- std::string bmi_destination;
- if (export_info.BmiInstallation) {
- auto dest =
- install_destination(export_info.BmiInstallation->Destination);
- bmi_dest_is_abs = dest.first;
- bmi_destination = cmStrCat(dest.second, '/');
- }
-
- std::string install_bmi_path;
- std::string build_bmi_path;
- auto m = mod_files.find(p.LogicalName);
- if (m != mod_files.end()) {
- install_bmi_path =
- cmStrCat(bmi_destination,
- cmEscape(cmSystemTools::GetFilenameName(m->second)));
- build_bmi_path = cmEscape(m->second);
- }
-
- for (auto const& exp : exports) {
- std::string iface_source;
- if (exp.second->Install && file_set.Destination) {
- auto dest = install_destination(*file_set.Destination);
- iface_source = cmStrCat(
- dest.second, '/', cmEscape(file_set.RelativeDirectory),
- cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
- } else {
- iface_source = cmEscape(file_set.SourcePath);
- }
-
- std::string bmi_path;
- if (exp.second->Install && export_info.BmiInstallation) {
- bmi_path = install_bmi_path;
- } else if (!exp.second->Install) {
- bmi_path = build_bmi_path;
- }
-
- if (iface_source.empty()) {
- // No destination for the C++ module source; ignore this property
- // value.
- continue;
- }
-
- *exp.first << " \"" << cmEscape(p.LogicalName) << '='
- << iface_source;
- if (!bmi_path.empty()) {
- *exp.first << ',' << bmi_path;
- }
- *exp.first << "\"\n";
- }
-
- if (bmi_install_script) {
- auto const& bmi_install = *export_info.BmiInstallation;
-
- *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
- << cmEscape(bmi_install.Component) << '\"';
- if (!bmi_install.ExcludeFromAll) {
- *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
- }
- *bmi_install_script << ")\n";
- *bmi_install_script << " file(INSTALL\n"
- " DESTINATION \"";
- if (!bmi_dest_is_abs) {
- *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
- }
- *bmi_install_script << cmEscape(bmi_install.Destination)
- << "\"\n"
- " TYPE FILE\n";
- if (bmi_install.Optional) {
- *bmi_install_script << " OPTIONAL\n";
- }
- if (!bmi_install.MessageLevel.empty()) {
- *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
- }
- if (!bmi_install.Permissions.empty()) {
- *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
- << "\n";
- }
- *bmi_install_script << " FILES \"" << m->second << "\")\n";
- if (bmi_dest_is_abs) {
- *bmi_install_script
- << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
- " \""
- << cmEscape(cmSystemTools::GetFilenameName(m->second))
- << "\")\n"
- " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
- " message(WARNING\n"
- " \"ABSOLUTE path INSTALL DESTINATION : "
- "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
- " endif ()\n"
- " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
- " message(FATAL_ERROR\n"
- " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
- "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
- " endif ()\n";
- }
- *bmi_install_script << "endif ()\n";
- }
- }
- }
-
- // Add trailing parenthesis for the `set_property` call.
- for (auto const& exp : exports) {
- *exp.first << ")\n";
- }
-
- // Check that public sources only require public modules.
- for (auto const& pub_reqs : public_source_requires) {
- for (auto const& req : pub_reqs.second) {
- if (private_modules.count(req)) {
- cmSystemTools::Error(cmStrCat(
- "Public C++ module source `", pub_reqs.first, "` requires the `",
- req, "` C++ module which is provided by a private source"));
- result = false;
- }
- }
+ cmDyndepMetadataCallbacks cb;
+ cb.ModuleFile =
+ [mod_files](std::string const& name) -> cm::optional<std::string> {
+ auto m = mod_files.find(name);
+ if (m != mod_files.end()) {
+ return m->second;
}
- }
+ return {};
+ };
- return result;
+ return cmDyndepCollation::WriteDyndepMetadata(arg_lang, objects, export_info,
+ cb);
}
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
@@ -3095,58 +2795,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
}
}
- cmGlobalNinjaGenerator::CxxModuleExportInfo export_info;
- export_info.Config = tdi["config"].asString();
- if (export_info.Config.empty()) {
- export_info.Config = "noconfig";
- }
- Json::Value const& tdi_exports = tdi["exports"];
- if (tdi_exports.isArray()) {
- for (auto const& tdi_export : tdi_exports) {
- CxxModuleExport exp;
- exp.Install = tdi_export["install"].asBool();
- exp.Name = tdi_export["export-name"].asString();
- exp.Destination = tdi_export["destination"].asString();
- exp.Prefix = tdi_export["export-prefix"].asString();
- exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
- exp.Namespace = tdi_export["namespace"].asString();
-
- export_info.Exports.push_back(exp);
- }
- }
- auto const& bmi_installation = tdi["bmi-installation"];
- if (bmi_installation.isObject()) {
- CxxModuleBmiInstall bmi_install;
-
- bmi_install.Component = bmi_installation["component"].asString();
- bmi_install.Destination = bmi_installation["destination"].asString();
- bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
- bmi_install.Optional = bmi_installation["optional"].asBool();
- bmi_install.Permissions = bmi_installation["permissions"].asString();
- bmi_install.MessageLevel = bmi_installation["message-level"].asString();
- bmi_install.ScriptLocation =
- bmi_installation["script-location"].asString();
-
- export_info.BmiInstallation = bmi_install;
- }
- Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
- if (tdi_cxx_modules.isObject()) {
- for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
- CxxModuleFileSet& fsi = export_info.ObjectToFileSet[i.key().asString()];
- auto const& tdi_cxx_module_info = *i;
- fsi.Name = tdi_cxx_module_info["name"].asString();
- fsi.RelativeDirectory =
- tdi_cxx_module_info["relative-directory"].asString();
- fsi.SourcePath = tdi_cxx_module_info["source"].asString();
- fsi.Type = tdi_cxx_module_info["type"].asString();
- fsi.Visibility = cmFileSetVisibilityFromName(
- tdi_cxx_module_info["visibility"].asString(), nullptr);
- auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
- if (tdi_fs_dest.isString()) {
- fsi.Destination = tdi_fs_dest.asString();
- }
- }
- }
+ auto export_info = cmDyndepCollation::ParseExportInfo(tdi);
cmake cm(cmake::RoleInternal, cmState::Unknown);
cm.SetHomeDirectory(dir_top_src);
@@ -3156,7 +2805,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
!cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile(
dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis,
module_dir, linked_target_dirs, arg_lang, arg_modmapfmt,
- export_info)) {
+ *export_info)) {
return 1;
}
return 0;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 6f654f6..775e792 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -35,6 +35,7 @@ class cmMakefile;
class cmOutputConverter;
class cmStateDirectory;
class cmake;
+struct cmCxxModuleExportInfo;
/**
* \class cmGlobalNinjaGenerator
@@ -417,7 +418,6 @@ public:
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
- struct CxxModuleExportInfo;
bool WriteDyndepFile(
std::string const& dir_top_src, std::string const& dir_top_bld,
std::string const& dir_cur_src, std::string const& dir_cur_bld,
@@ -425,7 +425,7 @@ public:
std::string const& module_dir,
std::vector<std::string> const& linked_target_dirs,
std::string const& arg_lang, std::string const& arg_modmapfmt,
- CxxModuleExportInfo const& export_info);
+ cmCxxModuleExportInfo const& export_info);
virtual std::string BuildAlias(const std::string& alias,
const std::string& /*config*/) const
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 095bf40..85a6fc2 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -4,6 +4,7 @@
#include <algorithm>
#include <cassert>
+#include <functional>
#include <iterator>
#include <map>
#include <ostream>
@@ -21,17 +22,12 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
-#include "cmExportBuildFileGenerator.h"
-#include "cmExportSet.h"
+#include "cmDyndepCollation.h"
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h"
-#include "cmInstallCxxModuleBmiGenerator.h"
-#include "cmInstallExportGenerator.h"
-#include "cmInstallFileSetGenerator.h"
-#include "cmInstallGenerator.h"
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
@@ -47,7 +43,6 @@
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
-#include "cmTargetExport.h"
#include "cmValue.h"
#include "cmake.h"
@@ -1637,214 +1632,15 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
tdi_linked_target_dirs.append(l);
}
- cmTarget* tgt = this->GeneratorTarget->Target;
- auto all_file_sets = tgt->GetAllFileSetNames();
- Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue;
- for (auto const& file_set_name : all_file_sets) {
- auto* file_set = tgt->GetFileSet(file_set_name);
- if (!file_set) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(),
- "\" is tracked to have file set \"", file_set_name,
- "\", but it was not found."));
- continue;
- }
- auto fs_type = file_set->GetType();
- // We only care about C++ module sources here.
- if (fs_type != "CXX_MODULES"_s) {
- continue;
- }
-
- auto fileEntries = file_set->CompileFileEntries();
- auto directoryEntries = file_set->CompileDirectoryEntries();
-
- auto directories = file_set->EvaluateDirectoryEntries(
- directoryEntries, this->GeneratorTarget->LocalGenerator, config,
- this->GeneratorTarget);
- std::map<std::string, std::vector<std::string>> files_per_dirs;
- for (auto const& entry : fileEntries) {
- file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
- this->GeneratorTarget->LocalGenerator,
- config, this->GeneratorTarget);
- }
-
- std::map<std::string, cmSourceFile const*> sf_map;
- {
- std::vector<cmSourceFile const*> objectSources;
- this->GeneratorTarget->GetObjectSources(objectSources, config);
- for (auto const* sf : objectSources) {
- auto full_path = sf->GetFullPath();
- if (full_path.empty()) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(),
- "\" has a full path-less source file."));
- continue;
- }
- sf_map[full_path] = sf;
- }
- }
-
- Json::Value fs_dest = Json::nullValue;
- for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
- if (auto const* fsg =
- dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
- if (fsg->GetTarget() == this->GeneratorTarget &&
- fsg->GetFileSet() == file_set) {
- fs_dest = fsg->GetDestination(config);
- continue;
- }
- }
- }
-
- for (auto const& files_per_dir : files_per_dirs) {
- for (auto const& file : files_per_dir.second) {
- auto lookup = sf_map.find(file);
- if (lookup == sf_map.end()) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
- file,
- R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
- continue;
- }
-
- auto const* sf = lookup->second;
-
- if (!sf) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
- file, "\" which has not been tracked properly."));
- continue;
- }
-
- auto obj_path = this->GetObjectFilePath(sf, config);
- Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
- Json::objectValue;
-
- tdi_module_info["source"] = file;
- tdi_module_info["relative-directory"] = files_per_dir.first;
- tdi_module_info["name"] = file_set->GetName();
- tdi_module_info["type"] = file_set->GetType();
- tdi_module_info["visibility"] =
- std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
- tdi_module_info["destination"] = fs_dest;
- }
- }
- }
-
- tdi["config"] = config;
+ cmDyndepGeneratorCallbacks cb;
+ cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) {
+ return this->GetObjectFilePath(sf, cnf);
+ };
- // Add information about the export sets that this target is a member of.
- Json::Value& tdi_exports = tdi["exports"] = Json::arrayValue;
- std::string export_name = this->GeneratorTarget->GetExportName();
-
- cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
- for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
- if (auto const* bmig =
- dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
- if (bmig->GetTarget() == this->GeneratorTarget) {
- bmi_gen = bmig;
- continue;
- }
- }
- }
- if (bmi_gen) {
- Json::Value tdi_bmi_info = Json::objectValue;
-
- tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
- tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
- const char* msg_level = "";
- switch (bmi_gen->GetMessageLevel()) {
- case cmInstallGenerator::MessageDefault:
- break;
- case cmInstallGenerator::MessageAlways:
- msg_level = "MESSAGE_ALWAYS";
- break;
- case cmInstallGenerator::MessageLazy:
- msg_level = "MESSAGE_LAZY";
- break;
- case cmInstallGenerator::MessageNever:
- msg_level = "MESSAGE_NEVER";
- break;
- }
- tdi_bmi_info["message-level"] = msg_level;
- tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
-
- tdi["bmi-installation"] = tdi_bmi_info;
- } else {
- tdi["bmi-installation"] = Json::nullValue;
- }
-
- auto const& all_install_exports =
- this->GetGlobalGenerator()->GetExportSets();
- for (auto const& exp : all_install_exports) {
- // Ignore exports sets which are not for this target.
- auto const& targets = exp.second.GetTargetExports();
- auto tgt_export =
- std::find_if(targets.begin(), targets.end(),
- [this](std::unique_ptr<cmTargetExport> const& te) {
- return te->Target == this->GeneratorTarget;
- });
- if (tgt_export == targets.end()) {
- continue;
- }
-
- auto const* installs = exp.second.GetInstallations();
- for (auto const* install : *installs) {
- Json::Value tdi_export_info = Json::objectValue;
-
- auto const& ns = install->GetNamespace();
- auto const& dest = install->GetDestination();
- auto const& cxxm_dir = install->GetCxxModuleDirectory();
- auto const& export_prefix = install->GetTempDir();
-
- tdi_export_info["namespace"] = ns;
- tdi_export_info["export-name"] = export_name;
- tdi_export_info["destination"] = dest;
- tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
- tdi_export_info["export-prefix"] = export_prefix;
- tdi_export_info["install"] = true;
-
- tdi_exports.append(tdi_export_info);
- }
- }
-
- auto const& all_build_exports =
- this->GetMakefile()->GetExportBuildFileGenerators();
- for (auto const& exp : all_build_exports) {
- std::vector<std::string> targets;
- exp->GetTargets(targets);
-
- // Ignore exports sets which are not for this target.
- auto const& name = this->GeneratorTarget->GetName();
- bool has_current_target =
- std::any_of(targets.begin(), targets.end(),
- [name](std::string const& tname) { return tname == name; });
- if (!has_current_target) {
- continue;
- }
-
- Json::Value tdi_export_info = Json::objectValue;
-
- auto const& ns = exp->GetNamespace();
- auto const& main_fn = exp->GetMainExportFileName();
- auto const& cxxm_dir = exp->GetCxxModuleDirectory();
- auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
- auto const& export_prefix =
- cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
-
- tdi_export_info["namespace"] = ns;
- tdi_export_info["export-name"] = export_name;
- tdi_export_info["destination"] = dest;
- tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
- tdi_export_info["export-prefix"] = export_prefix;
- tdi_export_info["install"] = false;
-
- tdi_exports.append(tdi_export_info);
- }
+#if !defined(CMAKE_BOOTSTRAP)
+ cmDyndepCollation::AddCollationInformation(tdi, this->GeneratorTarget,
+ config, cb);
+#endif
std::string const tdin = this->GetTargetDependInfoPath(lang, config);
cmGeneratedFileStream tdif(tdin);
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index f73c854..e559cfa 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -203,15 +203,23 @@ cmAlphaNum::cmAlphaNum(double val)
MakeDigits(this->View_, this->Digits_, "%g", val);
}
-std::string cmCatViews(std::initializer_list<cm::string_view> views)
+std::string cmCatViews(cm::optional<std::string>&& first,
+ std::initializer_list<cm::string_view> views)
{
- std::size_t total_size = 0;
+ std::size_t totalSize = 0;
for (cm::string_view const& view : views) {
- total_size += view.size();
+ totalSize += view.size();
}
- std::string result(total_size, '\0');
- std::string::iterator sit = result.begin();
+ std::string result;
+ std::string::size_type initialLen = 0;
+ if (first) {
+ totalSize += first->length();
+ initialLen = first->length();
+ result = std::move(*first);
+ }
+ result.resize(totalSize);
+ std::string::iterator sit = result.begin() + initialLen;
for (cm::string_view const& view : views) {
sit = std::copy_n(view.data(), view.size(), sit);
}
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 83938bc..bff2eda 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -12,6 +12,7 @@
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cm/string_view>
#include "cmRange.h"
@@ -146,7 +147,8 @@ std::vector<std::string> cmExpandedLists(InputIt first, InputIt last)
}
/** Concatenate string pieces into a single string. */
-std::string cmCatViews(std::initializer_list<cm::string_view> views);
+std::string cmCatViews(cm::optional<std::string>&& first,
+ std::initializer_list<cm::string_view> views);
/** Utility class for cmStrCat. */
class cmAlphaNum
@@ -189,13 +191,38 @@ private:
char Digits_[32];
};
+template <typename A, typename B, typename... AV>
+class cmStrCatHelper
+{
+public:
+ static std::string Compute(cmAlphaNum const& a, cmAlphaNum const& b,
+ AV const&... args)
+ {
+ return cmCatViews(
+ cm::nullopt,
+ { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ }
+};
+
+template <typename B, typename... AV>
+class cmStrCatHelper<std::string, B, AV...>
+{
+public:
+ static std::string Compute(std::string&& a, cmAlphaNum const& b,
+ AV const&... args)
+ {
+ return cmCatViews(
+ std::move(a),
+ { b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ }
+};
+
/** Concatenate string pieces and numbers into a single string. */
-template <typename... AV>
-inline std::string cmStrCat(cmAlphaNum const& a, cmAlphaNum const& b,
- AV const&... args)
+template <typename A, typename B, typename... AV>
+inline std::string cmStrCat(A&& a, B&& b, AV&&... args)
{
- return cmCatViews(
- { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ return cmStrCatHelper<A, B, AV...>::Compute(
+ std::forward<A>(a), std::forward<B>(b), std::forward<AV>(args)...);
}
/** Joins wrapped elements of a range with separator into a single string. */
@@ -207,7 +234,9 @@ std::string cmWrap(cm::string_view prefix, Range const& rng,
return std::string();
}
return cmCatViews(
- { prefix, cmJoin(rng, cmCatViews({ suffix, sep, prefix })), suffix });
+ cm::nullopt,
+ { prefix, cmJoin(rng, cmCatViews(cm::nullopt, { suffix, sep, prefix })),
+ suffix });
}
/** Joins wrapped elements of a range with separator into a single string. */
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index c12d1fe..5a64588 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -9,7 +9,6 @@
#include <cctype>
#include <cstdio>
#include <cstdlib>
-#include <initializer_list>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -950,9 +949,9 @@ struct Args : cmRange<typename std::vector<std::string>::const_iterator>
class json_error : public std::runtime_error
{
public:
- json_error(std::initializer_list<cm::string_view> message,
+ json_error(const std::string& message,
cm::optional<Args> errorPath = cm::nullopt)
- : std::runtime_error(cmCatViews(message))
+ : std::runtime_error(message)
, ErrorPath{
std::move(errorPath) // NOLINT(performance-move-const-arg)
}
@@ -964,7 +963,7 @@ public:
const std::string& Args::PopFront(cm::string_view error)
{
if (this->empty()) {
- throw json_error({ error });
+ throw json_error(std::string(error));
}
const std::string& res = *this->begin();
this->advance(1);
@@ -974,7 +973,7 @@ const std::string& Args::PopFront(cm::string_view error)
const std::string& Args::PopBack(cm::string_view error)
{
if (this->empty()) {
- throw json_error({ error });
+ throw json_error(std::string(error));
}
const std::string& res = *(this->end() - 1);
this->retreat(1);
@@ -999,7 +998,7 @@ cm::string_view JsonTypeToString(Json::ValueType type)
case Json::ValueType::objectValue:
return "OBJECT"_s;
}
- throw json_error({ "invalid JSON type found"_s });
+ throw json_error("invalid JSON type found");
}
int ParseIndex(
@@ -1008,14 +1007,14 @@ int ParseIndex(
{
unsigned long lindex;
if (!cmStrToULong(str, &lindex)) {
- throw json_error({ "expected an array index, got: '"_s, str, "'"_s },
+ throw json_error(cmStrCat("expected an array index, got: '"_s, str, "'"_s),
progress);
}
Json::ArrayIndex index = static_cast<Json::ArrayIndex>(lindex);
if (index >= max) {
cmAlphaNum sizeStr{ max };
- throw json_error({ "expected an index less than "_s, sizeStr.View(),
- " got '"_s, str, "'"_s },
+ throw json_error(cmStrCat("expected an index less than "_s, sizeStr.View(),
+ " got '"_s, str, "'"_s),
progress);
}
return index;
@@ -1036,16 +1035,16 @@ Json::Value& ResolvePath(Json::Value& json, Args path)
} else if (search->isObject()) {
if (!search->isMember(field)) {
const auto progressStr = cmJoin(progress, " "_s);
- throw json_error({ "member '"_s, progressStr, "' not found"_s },
+ throw json_error(cmStrCat("member '"_s, progressStr, "' not found"_s),
progress);
}
search = &(*search)[field];
} else {
const auto progressStr = cmJoin(progress, " "_s);
throw json_error(
- { "invalid path '"_s, progressStr,
- "', need element of OBJECT or ARRAY type to lookup '"_s, field,
- "' got "_s, JsonTypeToString(search->type()) },
+ cmStrCat("invalid path '"_s, progressStr,
+ "', need element of OBJECT or ARRAY type to lookup '"_s,
+ field, "' got "_s, JsonTypeToString(search->type())),
progress);
}
}
@@ -1061,7 +1060,7 @@ Json::Value ReadJson(const std::string& jsonstr)
std::string error;
if (!jsonReader->parse(jsonstr.data(), jsonstr.data() + jsonstr.size(),
&json, &error)) {
- throw json_error({ "failed parsing json string: "_s, error });
+ throw json_error(cmStrCat("failed parsing json string: "_s, error));
}
return json;
}
@@ -1101,9 +1100,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
mode != "LENGTH"_s && mode != "REMOVE"_s && mode != "SET"_s &&
mode != "EQUAL"_s) {
throw json_error(
- { "got an invalid mode '"_s, mode,
- "', expected one of GET, TYPE, MEMBER, LENGTH, REMOVE, SET, "
- " EQUAL"_s });
+ cmStrCat("got an invalid mode '"_s, mode,
+ "', expected one of GET, TYPE, MEMBER, LENGTH, REMOVE, SET, "
+ " EQUAL"_s));
}
const auto& jsonstr = args.PopFront("missing json string argument"_s);
@@ -1127,10 +1126,11 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
const auto& indexStr = args.PopBack("missing member index"_s);
const auto& value = ResolvePath(json, args);
if (!value.isObject()) {
- throw json_error({ "MEMBER needs to be called with an element of "
- "type OBJECT, got "_s,
- JsonTypeToString(value.type()) },
- args);
+ throw json_error(
+ cmStrCat("MEMBER needs to be called with an element of "
+ "type OBJECT, got "_s,
+ JsonTypeToString(value.type())),
+ args);
}
const auto index = ParseIndex(
indexStr, Args{ args.begin(), args.end() + 1 }, value.size());
@@ -1140,9 +1140,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
} else if (mode == "LENGTH"_s) {
const auto& value = ResolvePath(json, args);
if (!value.isArray() && !value.isObject()) {
- throw json_error({ "LENGTH needs to be called with an "
- "element of type ARRAY or OBJECT, got "_s,
- JsonTypeToString(value.type()) },
+ throw json_error(cmStrCat("LENGTH needs to be called with an "
+ "element of type ARRAY or OBJECT, got "_s,
+ JsonTypeToString(value.type())),
args);
}
@@ -1165,9 +1165,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
value.removeMember(toRemove, &removed);
} else {
- throw json_error({ "REMOVE needs to be called with an "
- "element of type ARRAY or OBJECT, got "_s,
- JsonTypeToString(value.type()) },
+ throw json_error(cmStrCat("REMOVE needs to be called with an "
+ "element of type ARRAY or OBJECT, got "_s,
+ JsonTypeToString(value.type())),
args);
}
makefile.AddDefinition(*outputVariable, WriteJson(json));
@@ -1189,9 +1189,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
value.append(newValue);
}
} else {
- throw json_error({ "SET needs to be called with an "
- "element of type OBJECT or ARRAY, got "_s,
- JsonTypeToString(value.type()) });
+ throw json_error(cmStrCat("SET needs to be called with an "
+ "element of type OBJECT or ARRAY, got "_s,
+ JsonTypeToString(value.type())));
}
makefile.AddDefinition(*outputVariable, WriteJson(json));
@@ -1207,7 +1207,7 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
if (outputVariable && e.ErrorPath) {
const auto errorPath = cmJoin(*e.ErrorPath, "-");
makefile.AddDefinition(*outputVariable,
- cmCatViews({ errorPath, "-NOTFOUND"_s }));
+ cmStrCat(errorPath, "-NOTFOUND"_s));
} else if (outputVariable) {
makefile.AddDefinition(*outputVariable, "NOTFOUND"_s);
}
@@ -1215,7 +1215,7 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
if (errorVariable) {
makefile.AddDefinition(*errorVariable, e.what());
} else {
- status.SetError(cmCatViews({ "sub-command JSON "_s, e.what(), "."_s }));
+ status.SetError(cmStrCat("sub-command JSON "_s, e.what(), "."_s));
success = false;
}
}
diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx
index 1e6b611..f73e62a 100644
--- a/Tests/CMakeLib/testStringAlgorithms.cxx
+++ b/Tests/CMakeLib/testStringAlgorithms.cxx
@@ -6,6 +6,8 @@
#include <iostream>
#include <sstream>
#include <string>
+#include <type_traits>
+#include <utility>
#include <vector>
#include <cm/string_view>
@@ -144,6 +146,18 @@ int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
d -= val;
assert_ok((d < div) && (d > -div), "cmStrCat double");
}
+ {
+ std::string val;
+ std::string expect;
+ val.reserve(120 * cmStrLen("cmStrCat move"));
+ auto data = val.data();
+ for (int i = 0; i < 100; i++) {
+ val = cmStrCat(std::move(val), "cmStrCat move");
+ expect += "cmStrCat move";
+ }
+ assert_ok((val.data() == data), "cmStrCat move");
+ assert_string(val, expect, "cmStrCat move");
+ }
// ----------------------------------------------------------------------
// Test cmWrap
diff --git a/Tests/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt
index 4df29fa..e6b298d 100644
--- a/Tests/Cuda/Toolkit/CMakeLists.txt
+++ b/Tests/Cuda/Toolkit/CMakeLists.txt
@@ -30,6 +30,8 @@ endif()
foreach (cuda_lib IN LISTS cuda_libs)
if(NOT CUDA_${cuda_lib}_LIBRARY)
message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
@@ -41,6 +43,9 @@ if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
list(APPEND npp_libs nppicom)
endif()
foreach (cuda_lib IN LISTS npp_libs)
+ if(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
+ endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
endif()
diff --git a/Tests/CudaOnly/Toolkit/CMakeLists.txt b/Tests/CudaOnly/Toolkit/CMakeLists.txt
index 1486c1a..ddf940b 100644
--- a/Tests/CudaOnly/Toolkit/CMakeLists.txt
+++ b/Tests/CudaOnly/Toolkit/CMakeLists.txt
@@ -28,6 +28,8 @@ endif()
foreach (cuda_lib IN LISTS cuda_libs)
if(NOT CUDA_${cuda_lib}_LIBRARY)
message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
@@ -41,6 +43,8 @@ endif()
foreach (cuda_lib )
if(NOT CUDA_${cuda_lib}_LIBRARY)
message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
@@ -50,6 +54,8 @@ endforeach()
foreach (cuda_lib nvrtc nvToolsExt OpenCL)
if(NOT CUDA_${cuda_lib}_LIBRARY)
message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})