From 024e3d2bf63c118f4a5da3ea872892ab274c697a Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 28 Oct 2022 10:29:46 -0400
Subject: Xcode: Put object files in a place that Xcode cleans

Since commit dc5fc898f6 (Xcode: Set object file locations using
TARGET_TEMP_DIR, 2022-09-29, v3.25.0-rc1~64^2~1), `xcodebuild clean`
does not remove the object files in our explicit `TARGET_TEMP_DIR`
because it is not under the `SYMROOT`.  Put it there.

Fixes: #24096
---
 Source/cmGlobalXCodeGenerator.cxx                  | 29 ++++++++++++++++------
 Source/cmGlobalXCodeGenerator.h                    |  4 +++
 .../codemodel-v2-data/targets/c_object_exe.json    |  4 +--
 .../codemodel-v2-data/targets/c_object_lib.json    |  2 +-
 .../codemodel-v2-data/targets/cxx_object_exe.json  |  4 +--
 .../codemodel-v2-data/targets/cxx_object_lib.json  |  2 +-
 .../RunCMake/XcodeProject/Clean-build-check.cmake  |  5 ++++
 .../RunCMake/XcodeProject/Clean-clean-check.cmake  |  5 ++++
 Tests/RunCMake/XcodeProject/RunCMakeTest.cmake     |  5 ++--
 9 files changed, 44 insertions(+), 16 deletions(-)
 create mode 100644 Tests/RunCMake/XcodeProject/Clean-build-check.cmake
 create mode 100644 Tests/RunCMake/XcodeProject/Clean-clean-check.cmake

diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index dd470f8..67b6e92 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2544,8 +2544,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
   }
 
   if (gtgt->CanCompileSources()) {
-    std::string tmpDir =
-      cmStrCat(gtgt->GetSupportDirectory(), '/', this->GetCMakeCFGIntDir());
+    std::string const tmpDir =
+      this->GetTargetTempDir(gtgt, this->GetCMakeCFGIntDir());
     buildSettings->AddAttribute("TARGET_TEMP_DIR", this->CreateString(tmpDir));
 
     std::string outDir;
@@ -4399,7 +4399,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
                                 this->CreateString(swiftVersion));
   }
 
-  std::string symroot = cmStrCat(root->GetCurrentBinaryDirectory(), "/build");
+  std::string const symroot = this->GetSymrootDir();
   buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot));
 
   // Inside a try_compile project, do not require signing on any platform.
@@ -4498,6 +4498,19 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
   return true;
 }
 
+std::string cmGlobalXCodeGenerator::GetSymrootDir() const
+{
+  return cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/build");
+}
+
+std::string cmGlobalXCodeGenerator::GetTargetTempDir(
+  cmGeneratorTarget const* gt, std::string const& configName) const
+{
+  // Use a path inside the SYMROOT.
+  return cmStrCat(this->GetSymrootDir(), '/', gt->GetName(), ".build/",
+                  configName);
+}
+
 void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf)
 {
   this->Architectures.clear();
@@ -4621,8 +4634,8 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackMakefile(
         for (auto objLib : objlibs) {
 
           const std::string objLibName = objLib->GetName();
-          std::string d = cmStrCat(objLib->GetSupportDirectory(), '/',
-                                   configName, "/lib", objLibName, ".a");
+          std::string d = cmStrCat(this->GetTargetTempDir(gt, configName),
+                                   "/lib", objLibName, ".a");
 
           std::string dependency = this->ConvertToRelativeForMake(d);
           makefileStream << "\\\n\t" << dependency;
@@ -4636,8 +4649,8 @@ void cmGlobalXCodeGenerator::CreateXCodeDependHackMakefile(
         // if building for more than one architecture
         // then remove those executables as well
         if (this->Architectures.size() > 1) {
-          std::string universal = cmStrCat(gt->GetSupportDirectory(), '/',
-                                           configName, "/$(OBJDIR)/");
+          std::string universal =
+            cmStrCat(this->GetTargetTempDir(gt, configName), "/$(OBJDIR)/");
           for (const auto& architecture : this->Architectures) {
             std::string universalFile = cmStrCat(universal, architecture, '/',
                                                  gt->GetFullName(configName));
@@ -5036,7 +5049,7 @@ void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory(
 {
   auto objectDirArch = GetTargetObjectDirArch(*gt, this->ObjectDirArch);
   gt->ObjectDirectory =
-    cmStrCat(gt->GetSupportDirectory(), '/', this->GetCMakeCFGIntDir(),
+    cmStrCat(this->GetTargetTempDir(gt, this->GetCMakeCFGIntDir()),
              "/$(OBJECT_FILE_DIR_normal:base)/", objectDirArch, '/');
 }
 
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index e924169..9ae75fb 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -339,6 +339,10 @@ private:
 
   std::string GetLibraryOrFrameworkPath(const std::string& path) const;
 
+  std::string GetSymrootDir() const;
+  std::string GetTargetTempDir(cmGeneratorTarget const* gt,
+                               std::string const& configName) const;
+
   static std::string GetDeploymentPlatform(const cmMakefile* mf);
 
   void ComputeArchitectures(cmMakefile* mf);
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json
index 3c9ace3..3392404 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json
@@ -27,7 +27,7 @@
             ]
         },
         {
-            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/.*/empty(\\.c)?\\.o(bj)?$",
+            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(object|build/c_object_lib\\.build)/.*/empty(\\.c)?\\.o(bj)?$",
             "isGenerated": true,
             "sourceGroupName": "Object Libraries",
             "compileGroupLanguage": null,
@@ -57,7 +57,7 @@
         {
             "name": "Object Libraries",
             "sourcePaths": [
-                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/.*/empty(\\.c)?\\.o(bj)?$"
+                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(object|build/c_object_lib\\.build)/.*/empty(\\.c)?\\.o(bj)?$"
             ]
         }
     ],
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json
index e3a20df..1917f92 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json
@@ -64,7 +64,7 @@
     "nameOnDisk": null,
     "artifacts": [
         {
-            "path": "^object/.*/empty(\\.c)?\\.o(bj)?$",
+            "path": "^(object|build/c_object_lib\\.build)/.*/empty(\\.c)?\\.o(bj)?$",
             "_dllExtra": false
         }
     ],
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json
index 119c91d..e8d6218 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json
@@ -27,7 +27,7 @@
             ]
         },
         {
-            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/.*/empty(\\.cxx)?\\.o(bj)?$",
+            "path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(object|build/cxx_object_lib\\.build)/.*/empty(\\.cxx)?\\.o(bj)?$",
             "isGenerated": true,
             "sourceGroupName": "Object Libraries",
             "compileGroupLanguage": null,
@@ -57,7 +57,7 @@
         {
             "name": "Object Libraries",
             "sourcePaths": [
-                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/.*/empty(\\.cxx)?\\.o(bj)?$"
+                "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(object|build/cxx_object_lib\\.build)/.*/empty(\\.cxx)?\\.o(bj)?$"
             ]
         }
     ],
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json
index 8e99f7d..24b391b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json
@@ -64,7 +64,7 @@
     "nameOnDisk": null,
     "artifacts": [
         {
-            "path": "^object/.*/empty(\\.cxx)?\\.o(bj)?$",
+            "path": "^(object|build/cxx_object_lib\\.build)/.*/empty(\\.cxx)?\\.o(bj)?$",
             "_dllExtra": false
         }
     ],
diff --git a/Tests/RunCMake/XcodeProject/Clean-build-check.cmake b/Tests/RunCMake/XcodeProject/Clean-build-check.cmake
new file mode 100644
index 0000000..605881a
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/Clean-build-check.cmake
@@ -0,0 +1,5 @@
+set(pattern "${RunCMake_TEST_BINARY_DIR}/build/empty.build/Debug/Objects-normal/*/empty.o")
+file(GLOB objs "${pattern}")
+if(NOT objs)
+  set(RunCMake_TEST_FAILED "Expected object does not exist:\n ${pattern}")
+endif()
diff --git a/Tests/RunCMake/XcodeProject/Clean-clean-check.cmake b/Tests/RunCMake/XcodeProject/Clean-clean-check.cmake
new file mode 100644
index 0000000..76ea8a1
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/Clean-clean-check.cmake
@@ -0,0 +1,5 @@
+set(pattern "${RunCMake_TEST_BINARY_DIR}/build/empty.build/Debug/Objects-normal/*/empty.o")
+file(GLOB objs "${pattern}")
+if(objs)
+  set(RunCMake_TEST_FAILED "Object file(s) not cleaned:\n ${objs}")
+endif()
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index fdf4411..573d5f7 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -2,9 +2,10 @@ include(RunCMake)
 
 function(RunClean)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Clean-build)
-  run_cmake(Clean)
+  run_cmake(Clean -DCMAKE_CONFIGURATION_TYPES=Debug)
   set(RunCMake_TEST_NO_CLEAN 1)
-  run_cmake_command(Clean-build xcodebuild clean)
+  run_cmake_command(Clean-build xcodebuild)
+  run_cmake_command(Clean-clean xcodebuild clean)
 endfunction()
 RunClean()
 
-- 
cgit v0.12