summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-09-14 19:02:47 (GMT)
committerBrad King <brad.king@kitware.com>2020-09-18 17:02:14 (GMT)
commit8d5f4c4db93959f77dc8fb185e4630df4ec26d98 (patch)
treed71f3fd9552500ecb52217bff53f4a7b37d6e18c
parent2db623f554d5522350214a7c5bacd5ec2dec1b34 (diff)
downloadCMake-8d5f4c4db93959f77dc8fb185e4630df4ec26d98.zip
CMake-8d5f4c4db93959f77dc8fb185e4630df4ec26d98.tar.gz
CMake-8d5f4c4db93959f77dc8fb185e4630df4ec26d98.tar.bz2
Xcode: Switch to the "new build system" for Xcode 12 and above
Provide an option to switch back to the original build system via `-T buildsystem=1`. Fixes: #18088
-rw-r--r--Help/generator/Xcode.rst3
-rw-r--r--Help/release/dev/xcode-12-new-build-system.rst7
-rw-r--r--Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst7
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx329
-rw-r--r--Source/cmGlobalXCodeGenerator.h16
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-stderr.txt2
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake15
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1.cmake8
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12.cmake8
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stderr.txt4
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12.cmake8
-rw-r--r--Tests/RunCMake/XcodeProject/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-result.txt1
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-stderr.txt13
-rw-r--r--Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand.cmake3
26 files changed, 423 insertions, 31 deletions
diff --git a/Help/generator/Xcode.rst b/Help/generator/Xcode.rst
index c0745dc..be03a22 100644
--- a/Help/generator/Xcode.rst
+++ b/Help/generator/Xcode.rst
@@ -30,3 +30,6 @@ Supported pairs are:
``buildsystem=<variant>``
Specify the buildsystem variant to use.
See the :variable:`CMAKE_XCODE_BUILD_SYSTEM` variable for allowed values.
+
+ For example, to select the original build system under Xcode 12,
+ run :manual:`cmake(1)` with the option ``-T buildsystem=1``.
diff --git a/Help/release/dev/xcode-12-new-build-system.rst b/Help/release/dev/xcode-12-new-build-system.rst
new file mode 100644
index 0000000..7a497b0
--- /dev/null
+++ b/Help/release/dev/xcode-12-new-build-system.rst
@@ -0,0 +1,7 @@
+xcode-12-new-build-system
+-------------------------
+
+* The :generator:`Xcode` generator now uses the Xcode "new build system"
+ when generating for Xcode 12.0 or higher.
+ See the :variable:`CMAKE_XCODE_BUILD_SYSTEM` variable.
+ One may use ``-T buildsystem=1`` to switch to the legacy build system.
diff --git a/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst b/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
index 8696bbf..587a5c9 100644
--- a/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
+++ b/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
@@ -10,7 +10,12 @@ mature enough for use by CMake. The possible values are:
``1``
The original Xcode build system.
- This is the default.
+ This is the default when using Xcode 11.x or below.
+
+``12``
+ The Xcode "new build system" introduced by Xcode 10.
+ It became mature enough for use by CMake in Xcode 12.
+ This is the default when using Xcode 12.x or above.
The ``CMAKE_XCODE_BUILD_SYSTEM`` variable is informational and should not
be modified by project code. See the :ref:`Xcode Build System Selection`
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index cceaea0..b2014e0 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -171,6 +171,11 @@ cmGlobalXCodeGenerator::cmGlobalXCodeGenerator(
{
this->VersionString = version_string;
this->XcodeVersion = version_number;
+ if (this->XcodeVersion >= 120) {
+ this->XcodeBuildSystem = BuildSystem::Twelve;
+ } else {
+ this->XcodeBuildSystem = BuildSystem::One;
+ }
this->RootObject = nullptr;
this->MainGroupChildren = nullptr;
@@ -287,6 +292,8 @@ cm::string_view cmXcodeBuildSystemString(cmGlobalXCodeGenerator::BuildSystem b)
switch (b) {
case cmGlobalXCodeGenerator::BuildSystem::One:
return "1"_s;
+ case cmGlobalXCodeGenerator::BuildSystem::Twelve:
+ return "12"_s;
}
return {};
}
@@ -371,6 +378,8 @@ bool cmGlobalXCodeGenerator::ProcessGeneratorToolsetField(
if (key == "buildsystem") {
if (value == "1"_s) {
this->XcodeBuildSystem = BuildSystem::One;
+ } else if (value == "12"_s) {
+ this->XcodeBuildSystem = BuildSystem::Twelve;
} else {
/* clang-format off */
std::string const& e = cmStrCat(
@@ -378,7 +387,21 @@ bool cmGlobalXCodeGenerator::ProcessGeneratorToolsetField(
" ", this->GetName(), "\n"
"toolset specification field\n"
" buildsystem=", value, "\n"
- "value is unkonwn. It must be '1'."
+ "value is unkonwn. It must be '1' or '12'."
+ );
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ if (this->XcodeBuildSystem == BuildSystem::Twelve &&
+ this->XcodeVersion < 120) {
+ /* clang-format off */
+ std::string const& e = cmStrCat(
+ "Generator\n"
+ " ", this->GetName(), "\n"
+ "toolset specification field\n"
+ " buildsystem=", value, "\n"
+ "is not allowed with Xcode ", this->VersionString, '.'
);
/* clang-format on */
mf->IssueMessage(MessageType::FATAL_ERROR, e);
@@ -479,6 +502,9 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
}
}
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ makeCommand.Add("-parallelizeTargets");
+ }
makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
@@ -499,8 +525,15 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
std::unique_ptr<cmLocalGenerator> cmGlobalXCodeGenerator::CreateLocalGenerator(
cmMakefile* mf)
{
- return std::unique_ptr<cmLocalGenerator>(
+ std::unique_ptr<cmLocalGenerator> lg(
cm::make_unique<cmLocalXCodeGenerator>(this, mf));
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ // For this build system variant we generate custom commands as
+ // shell scripts directly rather than inside Makefiles.
+ // FIXME: Rename or refactor this option for clarity.
+ lg->SetLinkScriptShell(true);
+ }
+ return lg;
}
void cmGlobalXCodeGenerator::AddExtraIDETargets()
@@ -1692,30 +1725,46 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
cmXCodeObject* preLinkPhase = nullptr;
cmXCodeObject* postBuildPhase = nullptr;
- std::vector<cmSourceFile*> classes;
- if (!gtgt->GetConfigCommonSourceFiles(classes)) {
- return;
- }
- // add all the sources
- std::vector<cmCustomCommand> commands;
- auto& visited = this->CommandsVisited[gtgt];
- for (auto sourceFile : classes) {
- if (sourceFile->GetCustomCommand() && visited.insert(sourceFile).second) {
- commands.push_back(*sourceFile->GetCustomCommand());
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ // create prebuild phase
+ preBuildPhase =
+ this->CreateRunScriptBuildPhase("CMake PreBuild Rules", prebuild);
+ // create prelink phase
+ preLinkPhase =
+ this->CreateRunScriptBuildPhase("CMake PreLink Rules", prelink);
+ // create postbuild phase
+ postBuildPhase =
+ this->CreateRunScriptBuildPhase("CMake PostBuild Rules", postbuild);
+ } else {
+ std::vector<cmSourceFile*> classes;
+ if (!gtgt->GetConfigCommonSourceFiles(classes)) {
+ return;
+ }
+ // add all the sources
+ std::vector<cmCustomCommand> commands;
+ auto& visited = this->CommandsVisited[gtgt];
+ for (auto sourceFile : classes) {
+ if (sourceFile->GetCustomCommand() &&
+ visited.insert(sourceFile).second) {
+ commands.push_back(*sourceFile->GetCustomCommand());
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ this->CustomCommandRoots[sourceFile].insert(gtgt);
+ }
+ }
}
+ // create custom commands phase
+ legacyCustomCommandsBuildPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake Rules", "cmakeRulesBuildPhase", gtgt, commands);
+ // create prebuild phase
+ preBuildPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake PreBuild Rules", "preBuildCommands", gtgt, prebuild);
+ // create prelink phase
+ preLinkPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake PreLink Rules", "preLinkCommands", gtgt, prelink);
+ // create postbuild phase
+ postBuildPhase = this->CreateLegacyRunScriptBuildPhase(
+ "CMake PostBuild Rules", "postBuildPhase", gtgt, postbuild);
}
- // create custom commands phase
- legacyCustomCommandsBuildPhase = this->CreateLegacyRunScriptBuildPhase(
- "CMake Rules", "cmakeRulesBuildPhase", gtgt, commands);
- // create prebuild phase
- preBuildPhase = this->CreateLegacyRunScriptBuildPhase(
- "CMake PreBuild Rules", "preBuildCommands", gtgt, prebuild);
- // create prelink phase
- preLinkPhase = this->CreateLegacyRunScriptBuildPhase(
- "CMake PreLink Rules", "preLinkCommands", gtgt, prelink);
- // create postbuild phase
- postBuildPhase = this->CreateLegacyRunScriptBuildPhase(
- "CMake PostBuild Rules", "postBuildPhase", gtgt, postbuild);
// The order here is the order they will be built in.
// The order "headers, resources, sources" mimics a native project generated
@@ -1727,6 +1776,9 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
if (legacyCustomCommandsBuildPhase) {
buildPhases->AddObject(legacyCustomCommandsBuildPhase);
}
+ if (this->XcodeBuildSystem >= BuildSystem::Twelve) {
+ this->CreateRunScriptBuildPhases(buildPhases, gtgt);
+ }
if (headerBuildPhase) {
buildPhases->AddObject(headerBuildPhase);
}
@@ -1750,6 +1802,199 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
}
}
+void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases(
+ cmXCodeObject* buildPhases, cmGeneratorTarget const* gt)
+{
+ std::vector<cmSourceFile*> sources;
+ if (!gt->GetConfigCommonSourceFiles(sources)) {
+ return;
+ }
+ auto& visited = this->CommandsVisited[gt];
+ for (auto sf : sources) {
+ this->CreateRunScriptBuildPhases(buildPhases, sf, gt, visited);
+ }
+}
+
+void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases(
+ cmXCodeObject* buildPhases, cmSourceFile const* sf,
+ cmGeneratorTarget const* gt, std::set<cmSourceFile const*>& visited)
+{
+ cmCustomCommand const* cc = sf->GetCustomCommand();
+ if (cc && visited.insert(sf).second) {
+ this->CustomCommandRoots[sf].insert(gt);
+ if (std::vector<cmSourceFile*> const* depends = gt->GetSourceDepends(sf)) {
+ for (cmSourceFile const* di : *depends) {
+ this->CreateRunScriptBuildPhases(buildPhases, di, gt, visited);
+ }
+ }
+ cmXCodeObject* buildPhase = this->CreateRunScriptBuildPhase(sf, gt, *cc);
+ buildPhases->AddObject(buildPhase);
+ }
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
+ cmSourceFile const* sf, cmGeneratorTarget const* gt,
+ cmCustomCommand const& cc)
+{
+ std::set<std::string> allConfigInputs;
+ std::set<std::string> allConfigOutputs;
+
+ std::string shellScript = "set -e\n";
+ for (std::string const& configName : this->CurrentConfigurationTypes) {
+ cmCustomCommandGenerator ccg(cc, configName, this->CurrentLocalGenerator);
+ std::vector<std::string> realDepends;
+ realDepends.reserve(ccg.GetDepends().size());
+ for (auto const& d : ccg.GetDepends()) {
+ std::string dep;
+ if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) {
+ realDepends.emplace_back(std::move(dep));
+ }
+ }
+
+ allConfigInputs.insert(realDepends.begin(), realDepends.end());
+ allConfigOutputs.insert(ccg.GetByproducts().begin(),
+ ccg.GetByproducts().end());
+ allConfigOutputs.insert(ccg.GetOutputs().begin(), ccg.GetOutputs().end());
+
+ shellScript =
+ cmStrCat(shellScript, R"(if test "$CONFIGURATION" = ")", configName,
+ "\"; then :\n", this->ConstructScript(ccg), "fi\n");
+ }
+
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
+ buildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ buildPhase->AddAttribute("files", buildFiles);
+ {
+ std::string name;
+ if (!allConfigOutputs.empty()) {
+ name = cmStrCat("Generate ",
+ this->RelativeToBinary(*allConfigOutputs.begin()));
+ } else {
+ name = sf->GetLocation().GetName();
+ }
+ buildPhase->AddAttribute("name", this->CreateString(name));
+ }
+ buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ buildPhase->AddAttribute("shellScript", this->CreateString(shellScript));
+ buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+
+ bool symbolic = false;
+ {
+ cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::string const& i : allConfigInputs) {
+ inputPaths->AddUniqueObject(this->CreateString(i));
+ if (!symbolic) {
+ if (cmSourceFile* isf =
+ gt->GetLocalGenerator()->GetMakefile()->GetSource(
+ i, cmSourceFileLocationKind::Known)) {
+ symbolic = isf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ }
+ buildPhase->AddAttribute("inputPaths", inputPaths);
+ }
+ {
+ cmXCodeObject* outputPaths =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::string const& o : allConfigOutputs) {
+ outputPaths->AddUniqueObject(this->CreateString(o));
+ if (!symbolic) {
+ if (cmSourceFile* osf =
+ gt->GetLocalGenerator()->GetMakefile()->GetSource(
+ o, cmSourceFileLocationKind::Known)) {
+ symbolic = osf->GetPropertyAsBool("SYMBOLIC");
+ }
+ }
+ }
+ buildPhase->AddAttribute("outputPaths", outputPaths);
+ }
+ if (symbolic) {
+ buildPhase->AddAttribute("alwaysOutOfDate", this->CreateString("1"));
+ }
+
+ return buildPhase;
+}
+
+cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
+ std::string const& name, std::vector<cmCustomCommand> const& commands)
+{
+ if (commands.empty()) {
+ return nullptr;
+ }
+
+ std::set<std::string> allConfigOutputs;
+
+ std::string shellScript = "set -e\n";
+ for (std::string const& configName : this->CurrentConfigurationTypes) {
+ shellScript = cmStrCat(shellScript, R"(if test "$CONFIGURATION" = ")",
+ configName, "\"; then :\n");
+ for (cmCustomCommand const& cc : commands) {
+ cmCustomCommandGenerator ccg(cc, configName,
+ this->CurrentLocalGenerator);
+ shellScript = cmStrCat(shellScript, this->ConstructScript(ccg));
+ allConfigOutputs.insert(ccg.GetByproducts().begin(),
+ ccg.GetByproducts().end());
+ }
+ shellScript = cmStrCat(shellScript, "fi\n");
+ }
+
+ cmXCodeObject* buildPhase =
+ this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
+ buildPhase->AddAttribute("buildActionMask",
+ this->CreateString("2147483647"));
+ cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ buildPhase->AddAttribute("files", buildFiles);
+ buildPhase->AddAttribute("name", this->CreateString(name));
+ buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
+ this->CreateString("0"));
+ buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
+ buildPhase->AddAttribute("shellScript", this->CreateString(shellScript));
+ buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+ {
+ cmXCodeObject* outputPaths =
+ this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::string const& o : allConfigOutputs) {
+ outputPaths->AddUniqueObject(this->CreateString(o));
+ }
+ buildPhase->AddAttribute("outputPaths", outputPaths);
+ }
+ buildPhase->AddAttribute("alwaysOutOfDate", this->CreateString("1"));
+
+ return buildPhase;
+}
+
+std::string cmGlobalXCodeGenerator::ConstructScript(
+ cmCustomCommandGenerator const& ccg)
+{
+ std::string script;
+ cmLocalGenerator* lg = this->CurrentLocalGenerator;
+ std::string wd = ccg.GetWorkingDirectory();
+ if (wd.empty()) {
+ wd = lg->GetCurrentBinaryDirectory();
+ }
+ wd = lg->ConvertToOutputFormat(wd, cmOutputConverter::SHELL);
+ script = cmStrCat(script, " cd ", wd, "\n");
+ for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
+ std::string cmd = ccg.GetCommand(c);
+ if (cmd.empty()) {
+ continue;
+ }
+ cmSystemTools::ReplaceString(cmd, "/./", "/");
+ cmd = lg->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL);
+ ccg.AppendArguments(c, cmd);
+ cmSystemTools::ReplaceString(cmd, "$(CONFIGURATION)", "$CONFIGURATION");
+ cmSystemTools::ReplaceString(cmd, "$(EFFECTIVE_PLATFORM_NAME)",
+ "$EFFECTIVE_PLATFORM_NAME");
+ script = cmStrCat(script, " ", cmd, '\n');
+ }
+ return script;
+}
+
// This function removes each occurrence of the flag and returns the last one
// (i.e., the dominant flag in GCC)
std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
@@ -3713,6 +3958,29 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
if (!this->CreateXCodeTargets(generator, targets)) {
return false;
}
+ for (auto const& ccRoot : this->CustomCommandRoots) {
+ if (ccRoot.second.size() > 1) {
+ std::string e = "The custom command ";
+ std::vector<std::string> const& outputs =
+ ccRoot.first->GetCustomCommand()->GetOutputs();
+ if (!outputs.empty()) {
+ e = cmStrCat(e, "generating\n ", outputs[0]);
+ } else {
+ e = cmStrCat(e, "driven by\n ", ccRoot.first->GetFullPath());
+ }
+ e = cmStrCat(e, "\nis attached to multiple targets:");
+ for (cmGeneratorTarget const* gt : ccRoot.second) {
+ e = cmStrCat(e, "\n ", gt->GetName());
+ }
+ e = cmStrCat(
+ e,
+ "\nbut none of these is a common dependency of the other(s). "
+ "This is not allowed by the Xcode \"new build system\".");
+ generator->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+ }
+ this->CustomCommandRoots.clear();
}
// loop over all targets and add link and depend info
for (auto t : targets) {
@@ -4007,9 +4275,16 @@ void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
xout.StartElement("dict");
if (this->XcodeVersion >= 100) {
xout.Element("key", "BuildSystemType");
- xout.Element("string", "Original");
- xout.Element("key", "DisableBuildSystemDeprecationWarning");
- xout.Element("true");
+ switch (this->XcodeBuildSystem) {
+ case BuildSystem::One:
+ xout.Element("string", "Original");
+ xout.Element("key", "DisableBuildSystemDeprecationWarning");
+ xout.Element("true");
+ break;
+ case BuildSystem::Twelve:
+ xout.Element("string", "Latest");
+ break;
+ }
}
if (hasGeneratedSchemes) {
xout.Element("key",
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index bbf3ee9..fca9c27 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -15,6 +15,7 @@
#include "cmXCodeObject.h"
class cmCustomCommand;
+class cmCustomCommandGenerator;
class cmGeneratorTarget;
class cmGlobalGeneratorFactory;
class cmLocalGenerator;
@@ -116,6 +117,7 @@ public:
enum class BuildSystem
{
One = 1,
+ Twelve = 12,
};
protected:
@@ -233,6 +235,18 @@ private:
cmXCodeObject* CreateLegacyRunScriptBuildPhase(
const char* name, const char* name2, cmGeneratorTarget* target,
const std::vector<cmCustomCommand>&);
+ void CreateRunScriptBuildPhases(cmXCodeObject* buildPhases,
+ cmGeneratorTarget const* gt);
+ void CreateRunScriptBuildPhases(cmXCodeObject* buildPhases,
+ cmSourceFile const* sf,
+ cmGeneratorTarget const* gt,
+ std::set<cmSourceFile const*>& visited);
+ cmXCodeObject* CreateRunScriptBuildPhase(cmSourceFile const* sf,
+ cmGeneratorTarget const* gt,
+ cmCustomCommand const& cc);
+ cmXCodeObject* CreateRunScriptBuildPhase(
+ std::string const& name, std::vector<cmCustomCommand> const& commands);
+ std::string ConstructScript(cmCustomCommandGenerator const& ccg);
void CreateReRunCMakeFile(cmLocalGenerator* root,
std::vector<cmLocalGenerator*> const& gens);
@@ -315,4 +329,6 @@ private:
std::vector<std::string> EnabledLangs;
std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>>
CommandsVisited;
+ std::map<cmSourceFile const*, std::set<cmGeneratorTarget const*>>
+ CustomCommandRoots;
};
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-stderr.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-stderr.txt
index 9ef6b20..5e88e3b 100644
--- a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-stderr.txt
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem-stderr.txt
@@ -7,4 +7,4 @@ CMake Error at CMakeLists.txt:[0-9]+ \(project\):
buildsystem=bad
- value is unkonwn. It must be '1'\.$
+ value is unkonwn. It must be '1' or '12'\.$
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-result.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-stderr.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-stderr.txt
new file mode 100644
index 0000000..cdfae3e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12-stderr.txt
@@ -0,0 +1,10 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Xcode
+
+ toolset specification field
+
+ buildsystem=12
+
+ is not allowed with Xcode [0-9.]+\.$
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12.cmake b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12.cmake
new file mode 100644
index 0000000..2fc38e5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem12.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
index af59019..5f12d79 100644
--- a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
@@ -56,8 +56,19 @@ elseif("${RunCMake_GENERATOR}" STREQUAL "Xcode")
run_cmake(BadToolsetHostArchXcode)
set(RunCMake_GENERATOR_TOOLSET "buildsystem=bad")
run_cmake(BadToolsetXcodeBuildSystem)
- set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
- run_cmake(TestToolsetXcodeBuildSystemDefault1)
+ if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
+ set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
+ run_cmake(TestToolsetXcodeBuildSystemDefault12)
+ set(RunCMake_GENERATOR_TOOLSET "Test Toolset,buildsystem=1")
+ run_cmake(TestToolsetXcodeBuildSystem1)
+ set(RunCMake_GENERATOR_TOOLSET "Test Toolset,buildsystem=12")
+ run_cmake(TestToolsetXcodeBuildSystem12)
+ else()
+ set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
+ run_cmake(TestToolsetXcodeBuildSystemDefault1)
+ set(RunCMake_GENERATOR_TOOLSET "buildsystem=12")
+ run_cmake(BadToolsetXcodeBuildSystem12)
+ endif()
else()
set(RunCMake_GENERATOR_TOOLSET "Bad Toolset")
run_cmake(BadToolset)
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-result.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stderr.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stderr.txt
new file mode 100644
index 0000000..817467b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TestToolsetXcodeBuildSystem1.cmake:[0-9]+ \(message\):
+ CMAKE_GENERATOR_TOOLSET is "Test Toolset,buildsystem=1" as expected.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stdout.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stdout.txt
new file mode 100644
index 0000000..cba95ce
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1-stdout.txt
@@ -0,0 +1 @@
+CMAKE_XCODE_BUILD_SYSTEM='1'
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1.cmake
new file mode 100644
index 0000000..550a6a1
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem1.cmake
@@ -0,0 +1,8 @@
+message(STATUS "CMAKE_XCODE_BUILD_SYSTEM='${CMAKE_XCODE_BUILD_SYSTEM}'")
+if(CMAKE_GENERATOR_TOOLSET STREQUAL "Test Toolset,buildsystem=1")
+ message(FATAL_ERROR "CMAKE_GENERATOR_TOOLSET is \"Test Toolset,buildsystem=1\" as expected.")
+else()
+ message(FATAL_ERROR
+ "CMAKE_GENERATOR_TOOLSET is \"${CMAKE_GENERATOR_TOOLSET}\" "
+ "but should be \"Test Toolset,buildsystem=1\"!")
+endif()
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-result.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stderr.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stderr.txt
new file mode 100644
index 0000000..9352faf
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TestToolsetXcodeBuildSystem12.cmake:[0-9]+ \(message\):
+ CMAKE_GENERATOR_TOOLSET is "Test Toolset,buildsystem=12" as expected.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stdout.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stdout.txt
new file mode 100644
index 0000000..df49a31
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12-stdout.txt
@@ -0,0 +1 @@
+CMAKE_XCODE_BUILD_SYSTEM='12'
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12.cmake
new file mode 100644
index 0000000..7e30e43
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystem12.cmake
@@ -0,0 +1,8 @@
+message(STATUS "CMAKE_XCODE_BUILD_SYSTEM='${CMAKE_XCODE_BUILD_SYSTEM}'")
+if(CMAKE_GENERATOR_TOOLSET STREQUAL "Test Toolset,buildsystem=12")
+ message(FATAL_ERROR "CMAKE_GENERATOR_TOOLSET is \"Test Toolset,buildsystem=12\" as expected.")
+else()
+ message(FATAL_ERROR
+ "CMAKE_GENERATOR_TOOLSET is \"${CMAKE_GENERATOR_TOOLSET}\" "
+ "but should be \"Test Toolset,buildsystem=12\"!")
+endif()
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-result.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stderr.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stderr.txt
new file mode 100644
index 0000000..1d43537
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TestToolsetXcodeBuildSystemDefault12.cmake:[0-9]+ \(message\):
+ CMAKE_GENERATOR_TOOLSET is "Test Toolset" as expected.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stdout.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stdout.txt
new file mode 100644
index 0000000..df49a31
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12-stdout.txt
@@ -0,0 +1 @@
+CMAKE_XCODE_BUILD_SYSTEM='12'
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12.cmake
new file mode 100644
index 0000000..645bb19
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetXcodeBuildSystemDefault12.cmake
@@ -0,0 +1,8 @@
+message(STATUS "CMAKE_XCODE_BUILD_SYSTEM='${CMAKE_XCODE_BUILD_SYSTEM}'")
+if(CMAKE_GENERATOR_TOOLSET STREQUAL "Test Toolset")
+ message(FATAL_ERROR "CMAKE_GENERATOR_TOOLSET is \"Test Toolset\" as expected.")
+else()
+ message(FATAL_ERROR
+ "CMAKE_GENERATOR_TOOLSET is \"${CMAKE_GENERATOR_TOOLSET}\" "
+ "but should be \"Test Toolset\"!")
+endif()
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index 70eaaeb..68de61c 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -10,6 +10,10 @@ run_cmake(XcodeAttributeGenex)
run_cmake(XcodeAttributeGenexError)
run_cmake(XcodeGenerateTopLevelProjectOnly)
+if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
+ run_cmake(XcodeDuplicateCustomCommand)
+endif()
+
function(XcodeGenerateTopLevelProjectOnlyWithObjectLibrary)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeGenerateTopLevelProjectOnlyWithObjectLibrary-build)
run_cmake(XcodeGenerateTopLevelProjectOnlyWithObjectLibrary)
diff --git a/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-result.txt b/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-stderr.txt b/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-stderr.txt
new file mode 100644
index 0000000..02af783
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Error in CMakeLists.txt:
+ The custom command generating
+
+ [^
+]*/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand-build/out.txt
+
+ is attached to multiple targets:
+
+ drive[0-9]
+ drive[0-9]
+
+ but none of these is a common dependency of the other\(s\). This is not
+ allowed by the Xcode "new build system".
diff --git a/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand.cmake b/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand.cmake
new file mode 100644
index 0000000..3ef1312
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/XcodeDuplicateCustomCommand.cmake
@@ -0,0 +1,3 @@
+add_custom_command(OUTPUT out.txt COMMAND false)
+add_custom_target(drive1 DEPENDS out.txt)
+add_custom_target(drive2 DEPENDS out.txt)