From de28f37ce4b8bc18e12d6fb3b52c2890e43d19f9 Mon Sep 17 00:00:00 2001 From: Anton Tokar Date: Wed, 1 Jul 2026 12:15:11 +0300 Subject: [PATCH] Xcode: Propagate add_custom_command COMMENT to generated projects Propagate the COMMENT section of add_custom_command(OUTPUT) as Xcode Build Phase, if present. Otherwise fallback to the current behavior Fixes: #27910 --- Source/cmGlobalXCodeGenerator.cxx | 10 ++++++++- .../EnvVars-build-stdout-windows.txt | 16 +++++++------- .../ExternalProject/EnvVars-build-stdout.txt | 22 +++++++++---------- .../RunCMake/XcodeProject/RunCMakeTest.cmake | 5 +++++ .../XcodeCustomCommandComment-check.cmake | 18 +++++++++++++++ .../XcodeCustomCommandComment.cmake | 6 +++++ 6 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 Tests/RunCMake/XcodeProject/XcodeCustomCommandComment-check.cmake create mode 100644 Tests/RunCMake/XcodeProject/XcodeCustomCommandComment.cmake diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 5fa411570e..882b33e549 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2122,11 +2122,17 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase( auto depfilesPrefix = cmStrCat(depfilesDirectory, buildPhase->GetId(), '.'); std::string shellScript = "set -e\n"; + // Use the comment from the first configuration; the Xcode build phase has a + // single name shared across all configurations. + cm::optional comment; for (std::string const& configName : this->CurrentConfigurationTypes) { cmCustomCommandGenerator ccg( cc, configName, this->CurrentLocalGenerator, true, {}, [&depfilesPrefix](std::string const& config, std::string const&) -> std::string { return cmStrCat(depfilesPrefix, config, ".d"); }); + if (!comment) { + comment = ccg.GetComment(); + } std::vector realDepends; realDepends.reserve(ccg.GetDepends().size()); for (auto const& d : ccg.GetDepends()) { @@ -2169,7 +2175,9 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase( buildPhase->AddAttribute("files", buildFiles); { std::string name; - if (!allConfigOutputs.empty()) { + if (comment && !comment->empty()) { + name = *comment; + } else if (!allConfigOutputs.empty()) { name = cmStrCat("Generate ", this->RelativeToBinary(*allConfigOutputs.begin())); } else { diff --git a/Tests/RunCMake/ExternalProject/EnvVars-build-stdout-windows.txt b/Tests/RunCMake/ExternalProject/EnvVars-build-stdout-windows.txt index 6dc6e3b70d..0477c90a9f 100644 --- a/Tests/RunCMake/ExternalProject/EnvVars-build-stdout-windows.txt +++ b/Tests/RunCMake/ExternalProject/EnvVars-build-stdout-windows.txt @@ -1,10 +1,10 @@ -.*(Performing custom step for 'CustomCommand'|CustomCommand-custom).* +.*Performing custom step for 'CustomCommand'.* *-- Variable - CustomVar: custom.* *-- Variable - CustomVar2: custom two.* *-- Stage: custom *-- Separator: ; *-- List: 1;2;3 -.*(Performing configure step for 'CustomCommand'|CustomCommand-configure).* +.*Performing configure step for 'CustomCommand'.* *-- Stage: config step *-- Separator: ; *-- List: 4;5;6 @@ -14,27 +14,27 @@ *-- -- c.* *-- Variable - Stage: config.* *-- Variable - ListVar: 4;5;6 -.*(Performing build step for 'CustomCommand'|CustomCommand-build).* +.*Performing build step for 'CustomCommand'.* *-- Stage: build step *-- Separator: ; *-- List: 4;5;6 -.*(Performing install step for 'CustomCommand'|CustomCommand-install).* +.*Performing install step for 'CustomCommand'.* *-- Stage: install step *-- Separator: ; *-- List: 4;5;6 -.*(Performing test step for 'CustomCommand'|CustomCommand-test).* +.*Performing test step for 'CustomCommand'.* *-- Stage: test step *-- Separator: ; *-- List: 4;5;6 -.*(Performing configure step for 'DefaultCommand'|DefaultCommand-configure).* +.*Performing configure step for 'DefaultCommand'.* *-- ConfigVar: config *-- Separator: , *-- List: 7,8,9 -.*(Performing build step for 'DefaultCommand'|DefaultCommand-build).* +.*Performing build step for 'DefaultCommand'.* *-- Stage: build *-- Separator: , *-- List: 7,8,9,10 -.*(Performing configure step for 'DefaultCommandListSep'|DefaultCommandListSep-configure).* +.*Performing configure step for 'DefaultCommandListSep'.* *-- ConfigVar: config *-- Separator: ; *-- List: 9;8;7 diff --git a/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt b/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt index 1e6d77143e..dcc8087113 100644 --- a/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt +++ b/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt @@ -1,10 +1,10 @@ -.*(Performing custom step for 'CustomCommand'|CustomCommand-custom).* +.*Performing\\? custom\\? step\\? for\\? \\?'CustomCommand\\?'.* *-- Variable - CustomVar: custom.* *-- Variable - CustomVar2: custom two.* *-- Stage: custom *-- Separator: ; *-- List: 1;2;3 -.*(Performing configure step for 'CustomCommand'|CustomCommand-configure).* +.*Performing\\? configure\\? step\\? for\\? \\?'CustomCommand\\?'.* *-- Stage: config step *-- Separator: ; *-- List: 4;5;6 @@ -14,27 +14,27 @@ *-- -- c.* *-- Variable - Stage: config.* *-- Variable - ListVar: 4;5;6 -.*(Performing build step for 'CustomCommand'|CustomCommand-build).* +.*Performing\\? build\\? step\\? for\\? \\?'CustomCommand\\?'.* *-- Stage: build step *-- Separator: ; *-- List: 4;5;6 -.*(Performing install step for 'CustomCommand'|CustomCommand-install).* +.*Performing\\? install\\? step\\? for\\? \\?'CustomCommand\\?'.* *-- Stage: install step *-- Separator: ; *-- List: 4;5;6 -.*(Performing test step for 'CustomCommand'|CustomCommand-test).* +.*Performing\\? test\\? step\\? for\\? \\?'CustomCommand\\?'.* *-- Stage: test step *-- Separator: ; *-- List: 4;5;6 -.*(Performing configure step for 'DefaultCommand'|DefaultCommand-configure).* +.*Performing\\? configure\\? step\\? for\\? \\?'DefaultCommand\\?'.* *-- ConfigVar: config *-- Separator: , *-- List: 7,8,9 -.*(Performing build step for 'DefaultCommand'|DefaultCommand-build).* +.*Performing\\? build\\? step\\? for\\? \\?'DefaultCommand\\?'.* *-- Stage: build *-- Separator: , *-- List: 7,8,9,10 -.*(Performing configure step for 'DefaultCommandListSep'|DefaultCommandListSep-configure).* +.*Performing\\? configure\\? step\\? for\\? \\?'DefaultCommandListSep\\?'.* *-- ConfigVar: config *-- Separator: ; *-- List: 9;8;7 @@ -43,15 +43,15 @@ *-- -- e *-- -- f *-- -- g -.*(Performing configure step for 'DefaultCommandListColon'|DefaultCommandListColon-configure).* +.*Performing\\? configure\\? step\\? for\\? \\?'DefaultCommandListColon\\?'.* *-- ConfigVar: config *-- Separator: ; *-- List: 10;11;12 -.*(Performing build step for 'DefaultCommandListColon'|DefaultCommandListColon-build).* +.*Performing\\? build\\? step\\? for\\? \\?'DefaultCommandListColon\\?'.* *-- Stage: build *-- Separator: ; *-- List: 10;11;12 -.*(Performing install step for 'DefaultCommandListColon'|DefaultCommandListColon-install).* +.*Performing\\? install\\? step\\? for\\? \\?'DefaultCommandListColon\\?'.* *-- Stage: install *-- Separator: ; *-- List: 10;11;12;13 diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index d5162b5db6..6b2d97f694 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake @@ -200,6 +200,11 @@ if(XCODE_VERSION VERSION_GREATER_EQUAL 12) run_cmake_command(XcodeWorkspace-build ${CMAKE_COMMAND} --build . --config Debug) run_cmake_command(XcodeWorkspace-build2 ${CMAKE_COMMAND} --build . --config Debug --target custom1 custom2) endblock() + + block() + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeCustomCommandComment-build) + run_cmake(XcodeCustomCommandComment) + endblock() endif() # Please add device-specific tests to '../XcodeProject-Device/RunCMakeTest.cmake'. diff --git a/Tests/RunCMake/XcodeProject/XcodeCustomCommandComment-check.cmake b/Tests/RunCMake/XcodeProject/XcodeCustomCommandComment-check.cmake new file mode 100644 index 0000000000..edbadadc1c --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodeCustomCommandComment-check.cmake @@ -0,0 +1,18 @@ +set(xcProjectFile "${RunCMake_TEST_BINARY_DIR}/XcodeCustomCommandComment.xcodeproj/project.pbxproj") +if(NOT EXISTS "${xcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${xcProjectFile} does not exist.") + return() +endif() + +set(foundComment 0) +file(STRINGS "${xcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES [[name = "My Custom Command Build Phase Name Debug";]]) + set(foundComment 1) + break() + endif() +endforeach() + +if(NOT foundComment) + set(RunCMake_TEST_FAILED "Did not find expected custom command comment in project.pbxproj") +endif() diff --git a/Tests/RunCMake/XcodeProject/XcodeCustomCommandComment.cmake b/Tests/RunCMake/XcodeProject/XcodeCustomCommandComment.cmake new file mode 100644 index 0000000000..792c8f2835 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodeCustomCommandComment.cmake @@ -0,0 +1,6 @@ +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/out.txt" + COMMAND ${CMAKE_COMMAND} -E echo "Generating out.txt" + COMMENT "My Custom Command Build Phase Name $" +) +add_custom_target(drive ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/out.txt")