Browse Source

cmList: Add container conversion to string

Marc Chevrier 2 years ago
parent
commit
45f17e5a85

+ 2 - 2
Source/CPack/cmCPackGenerator.cxx

@@ -1119,8 +1119,8 @@ int cmCPackGenerator::DoPackage()
   // Run post-build actions
   cmValue postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS");
   if (postBuildScripts) {
-    this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES",
-                                     cmJoin(this->packageFileNames, ";"));
+    this->MakefileMap->AddDefinition(
+      "CPACK_PACKAGE_FILES", cmList::to_string(this->packageFileNames));
 
     const cmList scripts{ postBuildScripts };
     for (const auto& script : scripts) {

+ 5 - 5
Source/CPack/cmCPackNuGetGenerator.cxx

@@ -12,7 +12,7 @@
 
 #include "cmCPackComponentGroup.h"
 #include "cmCPackLog.h"
-#include "cmStringAlgorithms.h"
+#include "cmList.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -82,10 +82,10 @@ void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
                      std::back_inserter(components),
                      [](cmCPackComponent const* comp) { return comp->Name; });
       this->SetOption("CPACK_NUGET_" + compGUp + "_GROUP_COMPONENTS",
-                      cmJoin(components, ";"));
+                      cmList::to_string(components));
     }
     if (!groups.empty()) {
-      this->SetOption("CPACK_NUGET_GROUPS", cmJoin(groups, ";"));
+      this->SetOption("CPACK_NUGET_GROUPS", cmList::to_string(groups));
     }
 
     // Handle Orphan components (components not belonging to any groups)
@@ -103,7 +103,7 @@ void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
       }
     }
     if (!components.empty()) {
-      this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";"));
+      this->SetOption("CPACK_NUGET_COMPONENTS", cmList::to_string(components));
     }
 
   } else {
@@ -114,7 +114,7 @@ void cmCPackNuGetGenerator::SetupGroupComponentVariables(bool ignoreGroup)
                    [](std::pair<std::string, cmCPackComponent> const& comp) {
                      return comp.first;
                    });
-    this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";"));
+    this->SetOption("CPACK_NUGET_COMPONENTS", cmList::to_string(components));
   }
 }
 

+ 2 - 2
Source/CPack/cpack.cxx

@@ -363,11 +363,11 @@ int main(int argc, char const* const* argv)
     }
 
     if (!expandedPreset->Generators.empty() && generator.empty()) {
-      generator = cmJoin(expandedPreset->Generators, ";");
+      generator = cmList::to_string(expandedPreset->Generators);
     }
 
     if (!expandedPreset->Configurations.empty() && cpackBuildConfig.empty()) {
-      cpackBuildConfig = cmJoin(expandedPreset->Configurations, ";");
+      cpackBuildConfig = cmList::to_string(expandedPreset->Configurations);
     }
 
     definitions.insert(expandedPreset->Variables.begin(),

+ 2 - 1
Source/cmAuxSourceDirectoryCommand.cxx

@@ -11,6 +11,7 @@
 #include "cmsys/Directory.hxx"
 
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
@@ -67,7 +68,7 @@ bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args,
   if (!sourceListValue.empty()) {
     sourceListValue += ";";
   }
-  sourceListValue += cmJoin(files, ";");
+  sourceListValue += cmList::to_string(files);
   mf.AddDefinition(args[1], sourceListValue);
   return true;
 }

+ 2 - 2
Source/cmCMakeHostSystemInformationCommand.cxx

@@ -529,12 +529,12 @@ bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
   if (arguments.ValueNames) {
     auto result = registry.GetValueNames(key, view);
     if (result) {
-      makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
+      makefile.AddDefinition(variable, cmList::to_string(*result));
     }
   } else if (arguments.SubKeys) {
     auto result = registry.GetSubKeys(key, view);
     if (result) {
-      makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
+      makefile.AddDefinition(variable, cmList::to_string(*result));
     }
   } else {
     auto result =

+ 2 - 1
Source/cmExecuteProcessCommand.cxx

@@ -20,6 +20,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmProcessOutput.h"
@@ -356,7 +357,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
           }
         }
         status.GetMakefile().AddDefinition(arguments.ResultsVariable,
-                                           cmJoin(res, ";"));
+                                           cmList::to_string(res));
       } break;
       case cmsysProcess_State_Exception:
         status.GetMakefile().AddDefinition(

+ 2 - 1
Source/cmExportBuildFileGenerator.cxx

@@ -19,6 +19,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -237,7 +238,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
     }
 
     // Store the property.
-    properties[prop] = cmJoin(objects, ";");
+    properties[prop] = cmList::to_string(objects);
   } else {
     // Add the main target file.
     {

+ 1 - 1
Source/cmExportFileGenerator.cxx

@@ -383,7 +383,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
   cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance());
 
   std::string dirs = cmGeneratorExpression::Preprocess(
-    cmJoin(target->Target->GetInstallIncludeDirectoriesEntries(te), ";"),
+    cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)),
     preprocessRule, true);
   this->ReplaceInstallPrefix(dirs);
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);

+ 2 - 1
Source/cmExportInstallFileGenerator.cxx

@@ -19,6 +19,7 @@
 #include "cmInstallExportGenerator.h"
 #include "cmInstallFileSetGenerator.h"
 #include "cmInstallTargetGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -430,7 +431,7 @@ void cmExportInstallFileGenerator::SetImportLocationProperty(
     }
 
     // Store the property.
-    properties[prop] = cmJoin(objects, ";");
+    properties[prop] = cmList::to_string(objects);
     importedLocations.insert(prop);
   } else {
     if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) {

+ 2 - 2
Source/cmExportTryCompileFileGenerator.cxx

@@ -156,12 +156,12 @@ std::string cmExportTryCompileFileGenerator::GetFileSetDirectories(
   cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
 {
   return cmOutputConverter::EscapeForCMake(
-    cmJoin(fileSet->GetDirectoryEntries(), ";"));
+    cmList::to_string(fileSet->GetDirectoryEntries()));
 }
 
 std::string cmExportTryCompileFileGenerator::GetFileSetFiles(
   cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
 {
   return cmOutputConverter::EscapeForCMake(
-    cmJoin(fileSet->GetFileEntries(), ";"));
+    cmList::to_string(fileSet->GetFileEntries()));
 }

+ 8 - 7
Source/cmFileCommand.cxx

@@ -42,6 +42,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
 #include "cmHexFileConverter.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -805,7 +806,7 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
 
   std::sort(files.begin(), files.end());
   files.erase(std::unique(files.begin(), files.end()), files.end());
-  status.GetMakefile().AddDefinition(variable, cmJoin(files, ";"));
+  status.GetMakefile().AddDefinition(variable, cmList::to_string(files));
   return true;
 }
 
@@ -1556,7 +1557,7 @@ bool HandlePathCommand(std::vector<std::string> const& args,
 #endif
   std::vector<std::string> path = cmSystemTools::SplitString(args[1], pathSep);
 
-  std::string value = cmJoin(cmMakeRange(path).transform(convert), ";");
+  std::string value = cmList::to_string(cmMakeRange(path).transform(convert));
   status.GetMakefile().AddDefinition(args[2], value);
   return true;
 }
@@ -3157,7 +3158,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
       if (!parsedArgs.RPathPrefix.empty()) {
         status.GetMakefile().AddDefinition(
           parsedArgs.RPathPrefix + "_" + firstPath,
-          cmJoin(archive.GetRPaths().at(firstPath), ";"));
+          cmList::to_string(archive.GetRPaths().at(firstPath)));
       }
     } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
       conflictingDeps.push_back(val.first);
@@ -3165,7 +3166,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
       paths.insert(paths.begin(), val.second.begin(), val.second.end());
       std::string varName =
         parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
-      std::string pathsStr = cmJoin(paths, ";");
+      std::string pathsStr = cmList::to_string(paths);
       status.GetMakefile().AddDefinition(varName, pathsStr);
     } else {
       std::ostringstream e;
@@ -3196,17 +3197,17 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
   }
 
   if (!parsedArgs.ResolvedDependenciesVar.empty()) {
-    std::string val = cmJoin(deps, ";");
+    std::string val = cmList::to_string(deps);
     status.GetMakefile().AddDefinition(parsedArgs.ResolvedDependenciesVar,
                                        val);
   }
   if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
-    std::string val = cmJoin(unresolvedDeps, ";");
+    std::string val = cmList::to_string(unresolvedDeps);
     status.GetMakefile().AddDefinition(parsedArgs.UnresolvedDependenciesVar,
                                        val);
   }
   if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
-    std::string val = cmJoin(conflictingDeps, ";");
+    std::string val = cmList::to_string(conflictingDeps);
     status.GetMakefile().AddDefinition(
       parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val);
   }

+ 3 - 2
Source/cmFunctionCommand.cxx

@@ -11,6 +11,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmFunctionBlocker.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
@@ -89,9 +90,9 @@ bool cmFunctionHelperCommand::operator()(
   }
 
   // define ARGV and ARGN
-  auto const argvDef = cmJoin(expandedArgs, ";");
+  auto const argvDef = cmList::to_string(expandedArgs);
   auto const eit = expandedArgs.begin() + (this->Args.size() - 1);
-  auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+  auto const argnDef = cmList::to_string(cmMakeRange(eit, expandedArgs.end()));
   makefile.AddDefinition(ARGV, argvDef);
   makefile.MarkVariableAsUsed(ARGV);
   makefile.AddDefinition(ARGN, argnDef);

+ 7 - 7
Source/cmGeneratorExpressionNode.cxx

@@ -2538,7 +2538,7 @@ static const struct LinkLibraryNode : public cmGeneratorExpressionNode
     list.front() = LL_BEGIN;
     list.push_back(LL_END);
 
-    return cmJoin(list, ";"_s);
+    return list.to_string();
   }
 } linkLibraryNode;
 
@@ -2607,7 +2607,7 @@ static const struct LinkGroupNode : public cmGeneratorExpressionNode
     list.front() = LG_BEGIN;
     list.push_back(LG_END);
 
-    return cmJoin(list, ";"_s);
+    return list.to_string();
   }
 } linkGroupNode;
 
@@ -2632,7 +2632,7 @@ static const struct HostLinkNode : public cmGeneratorExpressionNode
     }
 
     return context->HeadTarget->IsDeviceLink() ? std::string()
-                                               : cmJoin(parameters, ";");
+                                               : cmList::to_string(parameters);
   }
 } hostLinkNode;
 
@@ -2667,7 +2667,7 @@ static const struct DeviceLinkNode : public cmGeneratorExpressionNode
       list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
       list.push_back(static_cast<std::string>(DL_END));
 
-      return cmJoin(list, ";");
+      return list.to_string();
     }
 
     return std::string();
@@ -3104,7 +3104,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
       mf->AddTargetObject(tgtName, o);
     }
 
-    return cmJoin(objects, ";");
+    return objects.to_string();
   }
 } targetObjectsNode;
 
@@ -3164,7 +3164,7 @@ static const struct TargetRuntimeDllsNode : public TargetRuntimeDllsBaseNode
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
     std::vector<std::string> dlls = CollectDlls(parameters, context, content);
-    return cmJoin(dlls, ";");
+    return cmList::to_string(dlls);
   }
 } targetRuntimeDllsNode;
 
@@ -3187,7 +3187,7 @@ static const struct TargetRuntimeDllDirsNode : public TargetRuntimeDllsBaseNode
         dllDirs.push_back(directory);
       }
     }
-    return cmJoin(dllDirs, ";");
+    return cmList::to_string(dllDirs);
   }
 } targetRuntimeDllDirsNode;
 

+ 2 - 3
Source/cmGeneratorTarget.cxx

@@ -190,7 +190,7 @@ public:
     }
 
     static std::string filesStr;
-    filesStr = cmJoin(files, ";");
+    filesStr = cmList::to_string(files);
     return filesStr;
   }
 
@@ -322,8 +322,7 @@ cmValue cmGeneratorTarget::GetSourcesProperty() const
     values.push_back(se->GetInput());
   }
   static std::string value;
-  value.clear();
-  value = cmJoin(values, ";");
+  value = cmList::to_string(values);
   return cmValue(value);
 }
 

+ 2 - 2
Source/cmGetCMakePropertyCommand.cxx

@@ -6,9 +6,9 @@
 
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmState.h"
-#include "cmStringAlgorithms.h"
 #include "cmValue.h"
 
 // cmGetCMakePropertyCommand
@@ -35,7 +35,7 @@ bool cmGetCMakePropertyCommand(std::vector<std::string> const& args,
   } else if (args[1] == "COMPONENTS") {
     const std::set<std::string>* components =
       status.GetMakefile().GetGlobalGenerator()->GetInstallComponents();
-    output = cmJoin(*components, ";");
+    output = cmList::to_string(*components);
   } else {
     cmValue prop = nullptr;
     if (!args[1].empty()) {

+ 2 - 1
Source/cmLinkDirectoriesCommand.cxx

@@ -6,6 +6,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -39,7 +40,7 @@ bool cmLinkDirectoriesCommand(std::vector<std::string> const& args,
     AddLinkDir(mf, *i, directories);
   }
 
-  mf.AddLinkDirectory(cmJoin(directories, ";"), before);
+  mf.AddLinkDirectory(cmList::to_string(directories), before);
 
   return true;
 }

+ 6 - 5
Source/cmList.cxx

@@ -19,6 +19,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringReplaceHelper.h"
@@ -802,11 +803,6 @@ cmList& cmList::transform(TransformAction action,
   return *this;
 }
 
-std::string cmList::join(cm::string_view glue) const
-{
-  return cmJoin(this->Values, glue);
-}
-
 std::string& cmList::append(std::string& list, cm::string_view value)
 {
   if (list.empty()) {
@@ -1001,3 +997,8 @@ cmList::container_type::iterator cmList::Insert(
   }
   return container.begin() + delta;
 }
+
+std::string const& cmList::ToString(BT<std::string> const& s)
+{
+  return s.Value;
+}

+ 38 - 3
Source/cmList.h

@@ -22,6 +22,9 @@
 
 #include "cmValue.h"
 
+template <typename T>
+class BT;
+
 /**
  * CMake lists management
  * A CMake list is a string where list elements are separated by the ';'
@@ -936,7 +939,10 @@ public:
                     std::vector<std::string> const& args,
                     std::unique_ptr<TransformSelector> = {});
 
-  std::string join(cm::string_view glue) const;
+  std::string join(cm::string_view glue) const
+  {
+    return cmList::Join(this->Values, glue);
+  }
 
   void swap(cmList& other) noexcept { this->Values.swap(other.Values); }
 
@@ -1092,8 +1098,8 @@ public:
     return cmList::append(list,
                           cm::string_view{ std::accumulate(
                             std::next(first), last, *first,
-                            [](std::string a, const std::string& b) {
-                              return std::move(a) +
+                            [](const std::string& a, const std::string& b) {
+                              return a +
                                 std::string(cmList::element_separator) + b;
                             }) });
   }
@@ -1116,6 +1122,13 @@ public:
                              }) });
   }
 
+  template <typename Range,
+            cm::enable_if_t<cm::is_range<Range>::value, int> = 0>
+  static std::string to_string(Range const& r)
+  {
+    return cmList::Join(r, cmList::element_separator);
+  }
+
   // Non-members
   // ===========
   friend inline bool operator==(const cmList& lhs, const cmList& rhs) noexcept
@@ -1185,6 +1198,28 @@ private:
     return container.begin() + delta;
   }
 
+  static std::string const& ToString(std::string const& s) { return s; }
+  static std::string ToString(cm::string_view s) { return std::string{ s }; }
+  static std::string const& ToString(BT<std::string> const&);
+
+  template <typename Range>
+  static std::string Join(Range const& r, cm::string_view glue)
+  {
+    if (cm::size(r) == 0) {
+      return std::string{};
+    }
+
+    const auto sep = std::string{ glue };
+
+    return std::accumulate(
+      std::next(std::begin(r)), std::end(r), cmList::ToString(*std::begin(r)),
+      [&sep](std::string const& a,
+             typename std::iterator_traits<decltype(std::begin(
+               r))>::value_type const& b) -> std::string {
+        return a + sep + cmList::ToString(b);
+      });
+  }
+
   container_type Values;
 };
 

+ 4 - 2
Source/cmMacroCommand.cxx

@@ -12,6 +12,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmFunctionBlocker.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
@@ -66,8 +67,9 @@ bool cmMacroHelperCommand::operator()(
   std::string argcDef = std::to_string(expandedArgs.size());
 
   auto eit = expandedArgs.begin() + (this->Args.size() - 1);
-  std::string expandedArgn = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
-  std::string expandedArgv = cmJoin(expandedArgs, ";");
+  std::string expandedArgn =
+    cmList::to_string(cmMakeRange(eit, expandedArgs.end()));
+  std::string expandedArgv = cmList::to_string(expandedArgs);
   std::vector<std::string> variables;
   variables.reserve(this->Args.size() - 1);
   for (unsigned int j = 1; j < this->Args.size(); ++j) {

+ 4 - 5
Source/cmMakefile.cxx

@@ -1980,7 +1980,7 @@ void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs,
     return;
   }
 
-  std::string entryString = cmJoin(incs, ";");
+  std::string entryString = cmList::to_string(incs);
   if (before) {
     this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
       BT<std::string>(entryString, this->Backtrace));
@@ -3004,12 +3004,11 @@ cm::optional<std::string> cmMakefile::DeferGetCallIds() const
 {
   cm::optional<std::string> ids;
   if (this->Defer) {
-    ids = cmJoin(
+    ids = cmList::to_string(
       cmMakeRange(this->Defer->Commands)
         .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); })
         .transform(
-          [](DeferCommand const& dc) -> std::string const& { return dc.Id; }),
-      ";");
+          [](DeferCommand const& dc) -> std::string const& { return dc.Id; }));
   }
   return ids;
 }
@@ -4160,7 +4159,7 @@ cmValue cmMakefile::GetProperty(const std::string& prop) const
     std::transform(
       t->Tests.begin(), t->Tests.end(), std::back_inserter(keys),
       [](decltype(t->Tests)::value_type const& pair) { return pair.first; });
-    output = cmJoin(keys, ";");
+    output = cmList::to_string(keys);
     return cmValue(output);
   }
 

+ 9 - 8
Source/cmParseArgumentsCommand.cxx

@@ -20,7 +20,9 @@
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
-static std::string EscapeArg(const std::string& arg)
+namespace {
+
+std::string EscapeArg(const std::string& arg)
 {
   // replace ";" with "\;" so output argument lists will split correctly
   std::string escapedArg;
@@ -33,14 +35,12 @@ static std::string EscapeArg(const std::string& arg)
   return escapedArg;
 }
 
-static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+std::string JoinList(std::vector<std::string> const& arg, bool escape)
 {
-  return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
-                : cmJoin(cmMakeRange(arg), ";");
+  return escape ? cmList::to_string(cmMakeRange(arg).transform(EscapeArg))
+                : cmList::to_string(cmMakeRange(arg));
 }
 
-namespace {
-
 using options_map = std::map<std::string, bool>;
 using single_map = std::map<std::string, std::string>;
 using multi_map =
@@ -108,8 +108,9 @@ static void PassParsedArguments(
   }
 
   if (!keywordsMissingValues.empty()) {
-    makefile.AddDefinition(prefix + "KEYWORDS_MISSING_VALUES",
-                           cmJoin(cmMakeRange(keywordsMissingValues), ";"));
+    makefile.AddDefinition(
+      prefix + "KEYWORDS_MISSING_VALUES",
+      cmList::to_string(cmMakeRange(keywordsMissingValues)));
   } else {
     makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
   }

+ 2 - 1
Source/cmSeparateArgumentsCommand.cxx

@@ -9,6 +9,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
@@ -159,7 +160,7 @@ bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
       pos += 2;
     }
   });
-  auto value = cmJoin(values, ";");
+  auto value = cmList::to_string(values);
   status.GetMakefile().AddDefinition(var, value);
 
   return true;

+ 3 - 1
Source/cmSetCommand.cxx

@@ -3,6 +3,7 @@
 #include "cmSetCommand.h"
 
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmRange.h"
@@ -103,7 +104,8 @@ bool cmSetCommand(std::vector<std::string> const& args,
   }
 
   // collect any values into a single semi-colon separated value list
-  value = cmJoin(cmMakeRange(args).advance(1).retreat(ignoreLastArgs), ";");
+  value =
+    cmList::to_string(cmMakeRange(args).advance(1).retreat(ignoreLastArgs));
 
   if (parentScope) {
     status.GetMakefile().RaiseScope(variable, value.c_str());

+ 4 - 3
Source/cmSourceFile.cxx

@@ -8,6 +8,7 @@
 #include <cmext/string_view>
 
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -390,7 +391,7 @@ cmValue cmSourceFile::GetProperty(const std::string& prop) const
     }
 
     static std::string output;
-    output = cmJoin(this->IncludeDirectories, ";");
+    output = cmList::to_string(this->IncludeDirectories);
     return cmValue(output);
   }
 
@@ -400,7 +401,7 @@ cmValue cmSourceFile::GetProperty(const std::string& prop) const
     }
 
     static std::string output;
-    output = cmJoin(this->CompileOptions, ";");
+    output = cmList::to_string(this->CompileOptions);
     return cmValue(output);
   }
 
@@ -410,7 +411,7 @@ cmValue cmSourceFile::GetProperty(const std::string& prop) const
     }
 
     static std::string output;
-    output = cmJoin(this->CompileDefinitions, ";");
+    output = cmList::to_string(this->CompileDefinitions);
     return cmValue(output);
   }
 

+ 4 - 4
Source/cmState.cxx

@@ -17,6 +17,7 @@
 #include "cmDefinitions.h"
 #include "cmExecutionStatus.h"
 #include "cmGlobVerificationManager.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -584,10 +585,10 @@ cmValue cmState::GetGlobalProperty(const std::string& prop)
 {
   if (prop == "CACHE_VARIABLES") {
     std::vector<std::string> cacheKeys = this->GetCacheEntryKeys();
-    this->SetGlobalProperty("CACHE_VARIABLES", cmJoin(cacheKeys, ";"));
+    this->SetGlobalProperty("CACHE_VARIABLES", cmList::to_string(cacheKeys));
   } else if (prop == "COMMANDS") {
     std::vector<std::string> commands = this->GetCommandNames();
-    this->SetGlobalProperty("COMMANDS", cmJoin(commands, ";"));
+    this->SetGlobalProperty("COMMANDS", cmList::to_string(commands));
   } else if (prop == "IN_TRY_COMPILE") {
     this->SetGlobalProperty(
       "IN_TRY_COMPILE",
@@ -596,8 +597,7 @@ cmValue cmState::GetGlobalProperty(const std::string& prop)
     this->SetGlobalProperty("GENERATOR_IS_MULTI_CONFIG",
                             this->IsGeneratorMultiConfig ? "1" : "0");
   } else if (prop == "ENABLED_LANGUAGES") {
-    std::string langs;
-    langs = cmJoin(this->EnabledLanguages, ";");
+    auto langs = cmList::to_string(this->EnabledLanguages);
     this->SetGlobalProperty("ENABLED_LANGUAGES", langs);
   } else if (prop == "CMAKE_ROLE") {
     std::string mode = this->GetModeString();

+ 12 - 12
Source/cmStateDirectory.cxx

@@ -13,6 +13,7 @@
 #include <cmext/string_view>
 
 #include "cmAlgorithms.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmProperty.h"
 #include "cmPropertyMap.h"
@@ -20,7 +21,6 @@
 #include "cmState.h"
 #include "cmStatePrivate.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -381,15 +381,15 @@ cmValue cmStateDirectory::GetProperty(const std::string& prop,
     for (cmStateSnapshot const& ci : children) {
       child_dirs.push_back(ci.GetDirectory().GetCurrentSource());
     }
-    output = cmJoin(child_dirs, ";");
+    output = cmList::to_string(child_dirs);
     return cmValue(output);
   }
   if (prop == kBUILDSYSTEM_TARGETS) {
-    output = cmJoin(this->DirectoryState->NormalTargetNames, ";");
+    output = cmList::to_string(this->DirectoryState->NormalTargetNames);
     return cmValue(output);
   }
   if (prop == "IMPORTED_TARGETS"_s) {
-    output = cmJoin(this->DirectoryState->ImportedTargetNames, ";");
+    output = cmList::to_string(this->DirectoryState->ImportedTargetNames);
     return cmValue(output);
   }
 
@@ -401,38 +401,38 @@ cmValue cmStateDirectory::GetProperty(const std::string& prop,
       snp = snp.GetCallStackParent();
     }
     std::reverse(listFiles.begin(), listFiles.end());
-    output = cmJoin(listFiles, ";");
+    output = cmList::to_string(listFiles);
     return cmValue(output);
   }
   if (prop == "CACHE_VARIABLES") {
-    output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
+    output = cmList::to_string(this->Snapshot_.State->GetCacheEntryKeys());
     return cmValue(output);
   }
   if (prop == "VARIABLES") {
     std::vector<std::string> res = this->Snapshot_.ClosureKeys();
     cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
     std::sort(res.begin(), res.end());
-    output = cmJoin(res, ";");
+    output = cmList::to_string(res);
     return cmValue(output);
   }
   if (prop == "INCLUDE_DIRECTORIES") {
-    output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
+    output = cmList::to_string(this->GetIncludeDirectoriesEntries());
     return cmValue(output);
   }
   if (prop == "COMPILE_OPTIONS") {
-    output = cmJoin(this->GetCompileOptionsEntries(), ";");
+    output = cmList::to_string(this->GetCompileOptionsEntries());
     return cmValue(output);
   }
   if (prop == "COMPILE_DEFINITIONS") {
-    output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
+    output = cmList::to_string(this->GetCompileDefinitionsEntries());
     return cmValue(output);
   }
   if (prop == "LINK_OPTIONS") {
-    output = cmJoin(this->GetLinkOptionsEntries(), ";");
+    output = cmList::to_string(this->GetLinkOptionsEntries());
     return cmValue(output);
   }
   if (prop == "LINK_DIRECTORIES") {
-    output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
+    output = cmList::to_string(this->GetLinkDirectoriesEntries());
     return cmValue(output);
   }
 

+ 6 - 6
Source/cmTarget.cxx

@@ -811,12 +811,12 @@ std::pair<bool, cmValue> FileSetType::ReadProperties(
     did_read = true;
   } else if (prop == this->SelfEntries.PropertyName) {
     static std::string output;
-    output = cmJoin(this->SelfEntries.Entries, ";"_s);
+    output = cmList::to_string(this->SelfEntries.Entries);
     value = cmValue(output);
     did_read = true;
   } else if (prop == this->InterfaceEntries.PropertyName) {
     static std::string output;
-    output = cmJoin(this->InterfaceEntries.Entries, ";"_s);
+    output = cmList::to_string(this->InterfaceEntries.Entries);
     value = cmValue(output);
     did_read = true;
   } else if (cmHasPrefix(prop, this->DirectoryPrefix)) {
@@ -899,7 +899,7 @@ std::pair<bool, cmValue> UsageRequirementProperty::Read(
     if (!this->Entries.empty()) {
       // Storage to back the returned `cmValue`.
       static std::string output;
-      output = cmJoin(this->Entries, ";");
+      output = cmList::to_string(this->Entries);
       value = cmValue(output);
     }
     did_read = true;
@@ -2130,7 +2130,7 @@ cmValue cmTargetInternals::GetFileSetDirectories(
     return nullptr;
   }
   static std::string output;
-  output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
+  output = cmList::to_string(fileSet->GetDirectoryEntries());
   return cmValue(output);
 }
 
@@ -2150,7 +2150,7 @@ cmValue cmTargetInternals::GetFileSetPaths(cmTarget const* self,
     return nullptr;
   }
   static std::string output;
-  output = cmJoin(fileSet->GetFileEntries(), ";"_s);
+  output = cmList::to_string(fileSet->GetFileEntries());
   return cmValue(output);
 }
 
@@ -2495,7 +2495,7 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
         [](const BT<std::pair<std::string, bool>>& item) -> std::string {
           return item.Value.first;
         });
-      output = cmJoin(utilities, ";");
+      output = cmList::to_string(utilities);
       return cmValue(output);
     }
     if (prop == propIMPORTED) {

+ 2 - 1
Source/cmTargetCompileFeaturesCommand.cxx

@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmTargetCompileFeaturesCommand.h"
 
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmStandardLevelResolver.h"
@@ -43,7 +44,7 @@ private:
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 

+ 2 - 1
Source/cmTargetCompileOptionsCommand.cxx

@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmTargetCompileOptionsCommand.h"
 
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -44,7 +45,7 @@ private:
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 

+ 2 - 1
Source/cmTargetLinkDirectoriesCommand.cxx

@@ -3,6 +3,7 @@
 #include "cmTargetLinkDirectoriesCommand.h"
 
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -58,7 +59,7 @@ std::string TargetLinkDirectoriesImpl::Join(
     directories.push_back(unixPath);
   }
 
-  return cmJoin(directories, ";");
+  return cmList::to_string(directories);
 }
 
 } // namespace

+ 2 - 1
Source/cmTargetLinkOptionsCommand.cxx

@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmTargetLinkOptionsCommand.h"
 
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -36,7 +37,7 @@ private:
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 

+ 2 - 1
Source/cmTargetPrecompileHeadersCommand.cxx

@@ -5,6 +5,7 @@
 #include <utility>
 
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -73,7 +74,7 @@ private:
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 

+ 1 - 1
Source/cmTargetSourcesCommand.cxx

@@ -98,7 +98,7 @@ private:
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 
   enum class IsInterface

+ 12 - 3
Utilities/std/cmext/iterator

@@ -24,9 +24,18 @@ using is_input_iterator =
 
 // checks if a type is a range type: std::begin() and std::end() are supported
 template <typename Range>
-using is_range = cm::bool_constant<
-  cm::is_iterator<decltype(std::begin(std::declval<const Range>()))>::value &&
-  cm::is_iterator<decltype(std::end(std::declval<const Range>()))>::value>;
+using is_range =
+#if defined(_MSC_VER) && _MSC_VER < 1920
+  // MS C++ is not able to evaluate complex type introspection,
+  // so use a simplified version
+  cm::bool_constant<std::is_class<Range>::value ||
+                    std::is_array<Range>::value>;
+#else
+  cm::bool_constant<
+    cm::is_iterator<decltype(std::begin(
+      std::declval<const Range>()))>::value &&
+    cm::is_iterator<decltype(std::end(std::declval<const Range>()))>::value>;
+#endif
 
 // checks if a type is an input range type: std::begin() and std::end() are
 // returning an input iterator