diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index f8a2b58c86..60377329f7 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1814,9 +1814,37 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( // create prelink phase preLinkPhase = this->CreateRunScriptBuildPhase("CMake PreLink Rules", gtgt, prelink); + + std::vector 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 classes; if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) { @@ -2030,7 +2058,8 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase( cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase( std::string const& name, cmGeneratorTarget const* gt, - std::vector const& commands) + std::vector const& commands, + std::vector 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); diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index dff8520ad2..3282e0bfee 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -296,7 +296,8 @@ private: cmCustomCommand const& cc); cmXCodeObject* CreateRunScriptBuildPhase( std::string const& name, cmGeneratorTarget const* gt, - std::vector const& commands); + std::vector const& commands, + std::vector const& depends = {}); std::string ConstructScript(cmCustomCommandGenerator const& ccg); void CreateReRunCMakeFile(cmLocalGenerator* root, std::vector const& gens); diff --git a/Tests/RunCMake/XcodeProject/BundlePostBuild.cmake b/Tests/RunCMake/XcodeProject/BundlePostBuild.cmake new file mode 100644 index 0000000000..fb5c48b745 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index 5e2266633b..0515ec331e 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/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) diff --git a/Tests/RunCMake/XcodeProject/app.cxx b/Tests/RunCMake/XcodeProject/app.cxx new file mode 100644 index 0000000000..f8b643afbf --- /dev/null +++ b/Tests/RunCMake/XcodeProject/app.cxx @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/Tests/RunCMake/XcodeProject/fw.cxx b/Tests/RunCMake/XcodeProject/fw.cxx new file mode 100644 index 0000000000..e08ce0282e --- /dev/null +++ b/Tests/RunCMake/XcodeProject/fw.cxx @@ -0,0 +1,4 @@ +int fw() +{ + return 0; +}