Browse Source

Merge topic 'xcode-build-workspace'

26869fb4ba cmake --build: Fix building multiple targets in Xcode workspace

Acked-by: Kitware Robot <[email protected]>
Merge-request: !10875
Brad King 5 months ago
parent
commit
68eb6fb683

+ 64 - 34
Source/cmGlobalXCodeGenerator.cxx

@@ -548,62 +548,92 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
   int jobs, bool /*verbose*/, cmBuildOptions const& /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
 {
+  std::string const xcodebuild =
+    this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand());
+
+  std::string const workspacePath = cmStrCat(projectName, ".xcworkspace");
+  std::string const projectPath = cmStrCat(projectName, ".xcodeproj");
+
   // If an external tool created a workspace then build it instead.
-  std::string projectPath = cmStrCat(projectName, ".xcworkspace");
-  bool const isWorkspace = cmSystemTools::FileIsDirectory(projectPath);
-  if (!isWorkspace) {
-    projectPath = cmStrCat(projectName, ".xcodeproj");
-  }
+  bool const isWorkspace = cmSystemTools::FileIsDirectory(workspacePath);
 
   std::string const targetFlag = isWorkspace ? "-scheme" : "-target";
-  std::string const projectFlag = isWorkspace ? "-workspace" : "-project";
 
-  GeneratedMakeCommand makeCommand;
-  // now build the test
-  makeCommand.Add(
-    this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
+  std::vector<std::string> requiredArgs;
 
-  if (!projectName.empty()) {
-    makeCommand.Add(projectFlag, projectPath);
+  if (isWorkspace) {
+    requiredArgs.insert(requiredArgs.end(), { "-workspace", workspacePath });
+  } else {
+    requiredArgs.insert(requiredArgs.end(), { "-project", projectPath });
   }
-  if (cm::contains(targetNames, "clean")) {
-    makeCommand.Add("clean");
-    makeCommand.Add(targetFlag, "ALL_BUILD");
+
+  bool const isCleanBuild = cm::contains(targetNames, "clean");
+  bool const isTargetEmpty = targetNames.empty() ||
+    ((targetNames.size() == 1) && targetNames.front().empty());
+
+  if (isCleanBuild) {
+    requiredArgs.push_back("clean");
   } else {
-    makeCommand.Add("build");
-    if (targetNames.empty() ||
-        ((targetNames.size() == 1) && targetNames.front().empty())) {
-      makeCommand.Add(targetFlag, "ALL_BUILD");
-    } else {
-      for (auto const& tname : targetNames) {
-        if (!tname.empty()) {
-          makeCommand.Add(targetFlag, tname);
-        }
-      }
-    }
+    requiredArgs.push_back("build");
   }
 
+  requiredArgs.insert(requiredArgs.end(),
+                      { "-configuration", config.empty() ? "Debug" : config });
+
   if (isWorkspace) {
-    makeCommand.Add(
-      "-destination",
-      cmStrCat("generic/platform=", this->GetAppleSpecificPlatformName()));
+    requiredArgs.insert(
+      requiredArgs.end(),
+      { "-destination",
+        cmStrCat("generic/platform=", this->GetAppleSpecificPlatformName()) });
   }
 
   if ((this->XcodeBuildSystem >= BuildSystem::Twelve) ||
       (jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) {
-    makeCommand.Add("-parallelizeTargets");
+    requiredArgs.push_back("-parallelizeTargets");
   }
-  makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
 
   if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
       (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
-    makeCommand.Add("-jobs", std::to_string(jobs));
+    requiredArgs.insert(requiredArgs.end(), { "-jobs", std::to_string(jobs) });
   }
 
   if (this->XcodeVersion >= 70) {
-    makeCommand.Add("-hideShellScriptEnvironment");
+    requiredArgs.push_back("-hideShellScriptEnvironment");
   }
-  makeCommand.Add(makeOptions.begin(), makeOptions.end());
+
+  requiredArgs.insert(requiredArgs.end(), makeOptions.begin(),
+                      makeOptions.end());
+
+  if (isWorkspace && !isCleanBuild && targetNames.size() > 1) {
+    // For workspaces we need a separate command for each target,
+    // because xcodebuild can pass only one -scheme arg
+    std::vector<GeneratedMakeCommand> makeCommands;
+    for (auto const& target : targetNames) {
+      if (target.empty()) {
+        continue;
+      }
+      GeneratedMakeCommand makeCommand;
+      makeCommand.Add(xcodebuild);
+      makeCommand.Add(requiredArgs.cbegin(), requiredArgs.cend());
+      makeCommand.Add(targetFlag, target);
+      makeCommands.emplace_back(std::move(makeCommand));
+    }
+    return makeCommands;
+  }
+
+  if (isTargetEmpty || isCleanBuild) {
+    requiredArgs.insert(requiredArgs.end(), { targetFlag, "ALL_BUILD" });
+  } else {
+    for (auto const& target : targetNames) {
+      if (target.empty()) {
+        continue;
+      }
+      requiredArgs.insert(requiredArgs.end(), { targetFlag, target });
+    }
+  }
+  GeneratedMakeCommand makeCommand;
+  makeCommand.Add(xcodebuild);
+  makeCommand.Add(requiredArgs.cbegin(), requiredArgs.cend());
   return { std::move(makeCommand) };
 }
 

+ 1 - 0
Tests/RunCMake/XcodeProject/RunCMakeTest.cmake

@@ -184,6 +184,7 @@ if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
     run_cmake(XcodeWorkspace)
     set(RunCMake_TEST_NO_CLEAN 1)
     run_cmake_command(XcodeWorkspace-build ${CMAKE_COMMAND} --build . --config Debug)
+    run_cmake_command(XcodeWorkspace-build2 ${CMAKE_COMMAND} --build . --config Debug --target custom1 custom2)
   endblock()
 endif()
 

+ 1 - 1
Tests/RunCMake/XcodeProject/XcodeWorkspace-build-stdout.txt

@@ -1 +1 @@
-xcodebuild -workspace XcodeWorkspace\.xcworkspace build -scheme ALL_BUILD -destination generic/platform=MacOS
+xcodebuild -workspace XcodeWorkspace\.xcworkspace build -configuration Debug -destination generic/platform=MacOS -parallelizeTargets -hideShellScriptEnvironment -scheme ALL_BUILD

+ 4 - 0
Tests/RunCMake/XcodeProject/XcodeWorkspace-build2-stdout.txt

@@ -0,0 +1,4 @@
+.*xcodebuild -workspace XcodeWorkspace\.xcworkspace build -configuration Debug -destination generic/platform=MacOS -parallelizeTargets -hideShellScriptEnvironment -scheme custom1[^
+]*
+.*xcodebuild -workspace XcodeWorkspace\.xcworkspace build -configuration Debug -destination generic/platform=MacOS -parallelizeTargets -hideShellScriptEnvironment -scheme custom2[^
+]*

+ 2 - 0
Tests/RunCMake/XcodeProject/XcodeWorkspace.cmake

@@ -1,5 +1,7 @@
 enable_language(C)
 add_executable(main main.c)
+add_custom_target(custom1)
+add_custom_target(custom2)
 file(WRITE "${CMAKE_BINARY_DIR}/XcodeWorkspace.xcworkspace/contents.xcworkspacedata" [[
 <?xml version="1.0" encoding="UTF-8"?>
 <Workspace version = "1.0">