Browse Source

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
Aleksei Sapitskii 11 months ago
parent
commit
0282429c5a

+ 12 - 19
Source/cmGlobalXCodeGenerator.cxx

@@ -810,7 +810,6 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects()
   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 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects(
                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) {

+ 0 - 1
Source/cmGlobalXCodeGenerator.h

@@ -372,7 +372,6 @@ private:
   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;

+ 9 - 0
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()

+ 27 - 0
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
+)

+ 12 - 0
Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake

@@ -45,6 +45,18 @@ foreach(dependency ${externalFramework} ${externalDylib})
 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")

+ 7 - 0
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
+  )

+ 3 - 0
Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.c

@@ -0,0 +1,3 @@
+void TestLib(void)
+{
+}

+ 1 - 0
Tests/RunCMake/XcodeProject-Embed/TestLib/TestLib.h

@@ -0,0 +1 @@
+extern void TestLib(void);