Xcode: Fix XCODE_EMBED_FRAMEWORKS when settings differ across targets
In commit 5651901c54 (Xcode: add support for embedding frameworks,
2020-10-24, v3.20.0-rc1~402^2) we incorrectly reused `PBXBuildFile`
instances when the same framework is embedded in multiple targets,
causing target-specific settings to conflict.
Fixes: #26438
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index bb3f33a..8745d0f 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -810,7 +810,6 @@
this->TargetGroup.clear();
this->FileRefs.clear();
this->ExternalLibRefs.clear();
- this->EmbeddedLibRefs.clear();
this->FileRefToBuildFileMap.clear();
this->FileRefToEmbedBuildFileMap.clear();
this->CommandsVisited.clear();
@@ -4245,24 +4244,18 @@
cmSystemTools::IsPathToMacOSSharedLibrary(relFile) ||
cmSystemTools::FileIsDirectory(filePath)) {
// This is a regular string path - create file reference
- auto it = this->EmbeddedLibRefs.find(relFile);
- if (it == this->EmbeddedLibRefs.end()) {
- cmXCodeObject* fileRef =
- this->CreateXCodeFileReferenceFromPath(relFile, gt, "", nullptr);
- if (fileRef) {
- buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
- buildFile->SetComment(fileRef->GetComment());
- buildFile->AddAttribute("fileRef",
- this->CreateObjectReference(fileRef));
- }
- if (!buildFile) {
- cmSystemTools::Error(
- cmStrCat("Can't create build file for ", relFile));
- continue;
- }
- this->EmbeddedLibRefs.emplace(filePath, buildFile);
- } else {
- buildFile = it->second;
+ cmXCodeObject* fileRef =
+ this->CreateXCodeFileReferenceFromPath(relFile, gt, "", nullptr);
+ if (fileRef) {
+ buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+ buildFile->SetComment(fileRef->GetComment());
+ buildFile->AddAttribute("fileRef",
+ this->CreateObjectReference(fileRef));
+ }
+ if (!buildFile) {
+ cmSystemTools::Error(
+ cmStrCat("Can't create build file for ", relFile));
+ continue;
}
}
if (!buildFile) {
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 22743e5..9342ab0 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -372,7 +372,6 @@
std::map<std::string, cmXCodeObject*> TargetGroup;
std::map<std::string, cmXCodeObject*> FileRefs;
std::map<std::string, cmXCodeObject*> ExternalLibRefs;
- std::map<std::string, cmXCodeObject*> EmbeddedLibRefs;
std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap;
std::map<cmXCodeObject*, cmXCodeObject*> FileRefToEmbedBuildFileMap;
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOffAndOn-build-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOffAndOn-build-check.cmake
new file mode 100644
index 0000000..241ab68
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOffAndOn-build-check.cmake
@@ -0,0 +1,9 @@
+set(in_app1 "${RunCMake_TEST_BINARY_DIR}/Debug/app1.app/Contents/Frameworks/TestLib.framework/Headers")
+if(NOT EXISTS "${in_app1}")
+ string(APPEND RunCMake_TEST_FAILED "TestLib was embedded without Headers in:\n ${in_app1}\n")
+endif()
+
+set(in_app2 "${RunCMake_TEST_BINARY_DIR}/Debug/app2.app/Contents/Frameworks/TestLib.framework/Headers")
+if(EXISTS "${in_app2}")
+ string(APPEND RunCMake_TEST_FAILED "TestLib was embedded with Headers in:\n ${in_app2}\n")
+endif()
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOffAndOn.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOffAndOn.cmake
new file mode 100644
index 0000000..5faf3d9
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedFrameworksFlagsOffAndOn.cmake
@@ -0,0 +1,27 @@
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO")
+
+try_compile(TESTLIB_FRAMEWORK_COMPILED
+ PROJECT TestLib
+ SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/TestLib
+ BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestLib
+ )
+if(NOT TESTLIB_FRAMEWORK_COMPILED)
+ message(FATAL_ERROR "TestLib.framework did not compile")
+endif()
+set(TestLib_framework "${CMAKE_CURRENT_BINARY_DIR}/TestLib/Debug/TestLib.framework")
+if(NOT EXISTS "${TestLib_framework}/Headers/TestLib.h")
+ message(FATAL_ERROR "TestLib.framework did not build with header")
+endif()
+
+add_executable(app1 MACOSX_BUNDLE main.m)
+add_executable(app2 MACOSX_BUNDLE main.m)
+
+set_target_properties(app1 PROPERTIES
+ XCODE_EMBED_FRAMEWORKS "${CMAKE_CURRENT_BINARY_DIR}/TestLib/Debug/TestLib.framework"
+ XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY OFF
+)
+
+set_target_properties(app2 PROPERTIES
+ XCODE_EMBED_FRAMEWORKS "${CMAKE_CURRENT_BINARY_DIR}/TestLib/Debug/TestLib.framework"
+ XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY ON
+)
diff --git a/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
index 77ac63f..26749cd 100644
--- a/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
@@ -45,6 +45,18 @@
endforeach()
unset(RunCMake_TEST_OPTIONS)
+block()
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/EmbedFrameworksFlagsOffAndOn-build)
+ run_cmake(EmbedFrameworksFlagsOffAndOn)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(EmbedFrameworksFlagsOffAndOn-build
+ ${CMAKE_COMMAND} --build .
+ --config Debug
+ --target app1
+ --target app2
+ )
+endblock()
+
function(TestAppExtension platform)
set(testName EmbedAppExtensions-${platform})
if(NOT platform STREQUAL "macOS")
diff --git a/Tests/RunCMake/XcodeProject-Embed/TestLib/CMakeLists.txt b/Tests/RunCMake/XcodeProject-Embed/TestLib/CMakeLists.txt
new file mode 100644
index 0000000..eb651c2
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/TestLib/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.30)
+project(TestLib C)
+add_library(TestLib SHARED TestLib.c TestLib.h)
+set_target_properties(TestLib PROPERTIES
+ FRAMEWORK 1
+ PUBLIC_HEADER TestLib.h
+ )
diff --git a/Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.c b/Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.c
new file mode 100644
index 0000000..a39723a
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.c
@@ -0,0 +1,3 @@
+void TestLib(void)
+{
+}
diff --git a/Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.h b/Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.h
new file mode 100644
index 0000000..c9c0186
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.h
@@ -0,0 +1 @@
+extern void TestLib(void);