1
0
Эх сурвалжийг харах

Xcode: Fix POST_BUILD order in bundle targets on Xcode 16+

XCode 16+ no longer delays our POST_BUILD phase until after bundle files
like `Info.plist` are generated.  Teach the Xcode generator to add
explicit dependencies to the POST_BUILD phase in bundle targets to
ensure the files are created before it runs.

Fixes: #26656
Alexandra Cherdantseva 8 сар өмнө
parent
commit
2dc8c1d45f

+ 38 - 2
Source/cmGlobalXCodeGenerator.cxx

@@ -1814,9 +1814,37 @@ void cmGlobalXCodeGenerator::CreateCustomCommands(
     // create prelink phase
     preLinkPhase =
       this->CreateRunScriptBuildPhase("CMake PreLink Rules", gtgt, prelink);
+
+    std::vector<std::string> depends;
+    if (gtgt->IsBundleOnApple()) {
+      // In Xcode 16+ the POST_BUILD phase needs explicit dependencies to
+      // ensure it runs after certain bundle files are generated.
+      depends = {
+        "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/"
+        "Contents/Resources/DWARF/${PRODUCT_NAME}",
+        "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/"
+        "Contents/Info.plist",
+        "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)",
+        "$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)",
+      };
+      if (resourceBuildPhase) {
+        auto resourceFiles = resourceBuildPhase->GetAttribute("files");
+        for (auto xsf : resourceFiles->GetObjectList()) {
+          auto fileRef = xsf->GetAttribute("fileRef");
+          auto fileObj = fileRef->GetObject();
+          auto path = fileObj->GetAttribute("path");
+          auto fileName = cmSystemTools::GetFilenameName(path->GetString());
+          if (cmSystemTools::GetFilenameLastExtension(fileName) == ".plist") {
+            depends.push_back(
+              "$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/" +
+              fileName);
+          }
+        }
+      }
+    }
     // create postbuild phase
     postBuildPhase = this->CreateRunScriptBuildPhase("CMake PostBuild Rules",
-                                                     gtgt, postbuild);
+                                                     gtgt, postbuild, depends);
   } else {
     std::vector<cmSourceFile*> classes;
     if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) {
@@ -2030,7 +2058,8 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
 
 cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
   std::string const& name, cmGeneratorTarget const* gt,
-  std::vector<cmCustomCommand> const& commands)
+  std::vector<cmCustomCommand> const& commands,
+  std::vector<std::string> const& depends)
 {
   if (commands.empty()) {
     return nullptr;
@@ -2065,6 +2094,13 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase(
   buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
   buildPhase->AddAttribute("shellScript", this->CreateString(shellScript));
   buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+  {
+    cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+    for (std::string const& s : depends) {
+      inputPaths->AddUniqueObject(this->CreateString(s));
+    }
+    buildPhase->AddAttribute("inputPaths", inputPaths);
+  }
   {
     cmXCodeObject* outputPaths =
       this->CreateObject(cmXCodeObject::OBJECT_LIST);

+ 2 - 1
Source/cmGlobalXCodeGenerator.h

@@ -296,7 +296,8 @@ private:
                                            cmCustomCommand const& cc);
   cmXCodeObject* CreateRunScriptBuildPhase(
     std::string const& name, cmGeneratorTarget const* gt,
-    std::vector<cmCustomCommand> const& commands);
+    std::vector<cmCustomCommand> const& commands,
+    std::vector<std::string> const& depends = {});
   std::string ConstructScript(cmCustomCommandGenerator const& ccg);
   void CreateReRunCMakeFile(cmLocalGenerator* root,
                             std::vector<cmLocalGenerator*> const& gens);

+ 15 - 0
Tests/RunCMake/XcodeProject/BundlePostBuild.cmake

@@ -0,0 +1,15 @@
+enable_language(CXX)
+add_executable(app MACOSX_BUNDLE app.cxx)
+add_library(fw SHARED fw.cxx)
+set_property(TARGET fw PROPERTY FRAMEWORK 1)
+foreach(target IN ITEMS app fw)
+  set_property(TARGET ${target} PROPERTY XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym)
+  add_custom_command(
+    TARGET ${target} POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E sha256sum
+    [["$DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME/Contents/Resources/DWARF/$PRODUCT_NAME"]]
+    [["$DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME/Contents/Info.plist"]]
+    [["$TARGET_BUILD_DIR/$EXECUTABLE_PATH"]]
+    [["$TARGET_BUILD_DIR/$INFOPLIST_PATH"]]
+  )
+endforeach()

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

@@ -91,6 +91,13 @@ if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
 
   XcodeObjectLibsInTwoProjectsMacOS()
 
+  block()
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/BundlePostBuild-build)
+    run_cmake(BundlePostBuild)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    run_cmake_command(BundlePostBuild-build ${CMAKE_COMMAND} --build . --config Debug)
+  endblock()
+
 endif()
 
 function(XcodeSchemaGeneration)

+ 4 - 0
Tests/RunCMake/XcodeProject/app.cxx

@@ -0,0 +1,4 @@
+int main()
+{
+  return 0;
+}

+ 4 - 0
Tests/RunCMake/XcodeProject/fw.cxx

@@ -0,0 +1,4 @@
+int fw()
+{
+  return 0;
+}