Browse Source

Merge topic 'XCode-XCODE_LINK_BUILD_PHASE_MODE-and-LINK_LIBRARY-genex' into release-3.25

61075d2d7b XCode: ensure LINK_LIBRARY genex is usable with XCODE_LINK_BUILD_PHASE_MODE

Acked-by: Kitware Robot <[email protected]>
Merge-request: !7947
Brad King 3 years ago
parent
commit
3bb47e43f0

+ 53 - 21
Source/cmGlobalXCodeGenerator.cxx

@@ -3581,28 +3581,37 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
             libItem.IsPath == cmComputeLinkInformation::ItemIsPath::Yes &&
             forceLinkPhase))) {
         std::string libName;
-        bool canUseLinkPhase = true;
-        if (libItem.Target) {
-          if (libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
-            canUseLinkPhase = canUseLinkPhase && forceLinkPhase;
+        bool canUseLinkPhase = !libItem.HasFeature() ||
+          libItem.GetFeatureName() == "__CMAKE_LINK_FRAMEWORK"_s ||
+          libItem.GetFeatureName() == "FRAMEWORK"_s ||
+          libItem.GetFeatureName() == "WEAK_FRAMEWORK"_s ||
+          libItem.GetFeatureName() == "WEAK_LIBRARY"_s;
+        if (canUseLinkPhase) {
+          if (libItem.Target) {
+            if (libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
+              canUseLinkPhase = canUseLinkPhase && forceLinkPhase;
+            } else {
+              // If a library target uses custom build output directory Xcode
+              // won't pick it up so we have to resort back to linker flags,
+              // but that's OK as long as the custom output dir is absolute
+              // path.
+              for (auto const& libConfigName :
+                   this->CurrentConfigurationTypes) {
+                canUseLinkPhase = canUseLinkPhase &&
+                  libItem.Target->UsesDefaultOutputDir(
+                    libConfigName, cmStateEnums::RuntimeBinaryArtifact);
+              }
+            }
+            libName = libItem.Target->GetName();
           } else {
-            // If a library target uses custom build output directory Xcode
-            // won't pick it up so we have to resort back to linker flags, but
-            // that's OK as long as the custom output dir is absolute path.
-            for (auto const& libConfigName : this->CurrentConfigurationTypes) {
-              canUseLinkPhase = canUseLinkPhase &&
-                libItem.Target->UsesDefaultOutputDir(
-                  libConfigName, cmStateEnums::RuntimeBinaryArtifact);
+            libName = cmSystemTools::GetFilenameName(libItem.Value.Value);
+            // We don't want all the possible files here, just standard
+            // libraries
+            const auto libExt = cmSystemTools::GetFilenameExtension(libName);
+            if (!IsLinkPhaseLibraryExtension(libExt)) {
+              canUseLinkPhase = false;
             }
           }
-          libName = libItem.Target->GetName();
-        } else {
-          libName = cmSystemTools::GetFilenameName(libItem.Value.Value);
-          // We don't want all the possible files here, just standard libraries
-          const auto libExt = cmSystemTools::GetFilenameExtension(libName);
-          if (!IsLinkPhaseLibraryExtension(libExt)) {
-            canUseLinkPhase = false;
-          }
         }
         if (canUseLinkPhase) {
           // Add unique configuration name to target-config map for later
@@ -3658,6 +3667,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
   // separately.
   std::vector<std::string> linkSearchPaths;
   std::vector<std::string> frameworkSearchPaths;
+  std::set<std::pair<cmXCodeObject*, std::string>> linkBuildFileSet;
   for (auto const& libItem : linkPhaseTargetVector) {
     // Add target output directory as a library search path
     std::string linkDir;
@@ -3760,8 +3770,30 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
       cmSystemTools::Error("Missing files of PBXFrameworksBuildPhase");
       continue;
     }
-    if (buildFile && !buildFiles->HasObject(buildFile)) {
-      buildFiles->AddObject(buildFile);
+    if (buildFile) {
+      if (cmHasPrefix(libItem->GetFeatureName(), "WEAK_"_s)) {
+        auto key = std::make_pair(buildFile->GetAttribute("fileRef"),
+                                  libItem->GetFeatureName());
+        if (linkBuildFileSet.find(key) != linkBuildFileSet.end()) {
+          continue;
+        }
+        linkBuildFileSet.insert(key);
+
+        cmXCodeObject* buildObject =
+          this->CreateObject(cmXCodeObject::PBXBuildFile);
+        buildObject->AddAttribute("fileRef", key.first);
+        // Add settings, ATTRIBUTES, Weak flag
+        cmXCodeObject* settings =
+          this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
+        cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+        attrs->AddObject(this->CreateString("Weak"));
+        settings->AddAttribute("ATTRIBUTES", attrs);
+        buildObject->AddAttribute("settings", settings);
+        buildFile = buildObject;
+      }
+      if (!buildFiles->HasObject(buildFile)) {
+        buildFiles->AddObject(buildFile);
+      }
     }
   }
 

+ 57 - 5
Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase.cmake

@@ -65,8 +65,12 @@ add_custom_target(prebuildDependencies ALL
     COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/ExternalFrameworks/build --target staticFrameworkExt sharedFrameworkExt --config Debug
 )
 add_executable(app1 mainOuter.m)
+add_executable(app2 mainOuter.m)
+add_executable(app3 mainOuter.m)
 add_library(static1 STATIC funcOuter.c)
 add_library(shared1 SHARED funcOuter.c)
+add_library(shared3 SHARED funcOuter.c)
+add_library(shared4 SHARED funcOuter.c)
 add_library(module1 MODULE funcOuter.c)
 add_library(obj1    OBJECT funcOuter.c)
 add_library(staticFramework1 STATIC funcOuter.c)
@@ -74,8 +78,12 @@ add_library(sharedFramework1 SHARED funcOuter.c)
 set_target_properties(staticFramework1 PROPERTIES FRAMEWORK TRUE)
 set_target_properties(sharedFramework1 PROPERTIES FRAMEWORK TRUE)
 add_dependencies(app1 prebuildDependencies)
+add_dependencies(app2 prebuildDependencies)
+add_dependencies(app3 prebuildDependencies)
 add_dependencies(static1 prebuildDependencies)
 add_dependencies(shared1 prebuildDependencies)
+add_dependencies(shared3 prebuildDependencies)
+add_dependencies(shared4 prebuildDependencies)
 add_dependencies(module1 prebuildDependencies)
 add_dependencies(obj1 prebuildDependencies)
 add_dependencies(staticFramework1 prebuildDependencies)
@@ -103,6 +111,14 @@ set(libresolv \"${libresolv}\")
 set(CoreFoundation \"${CoreFoundation}\")
 ")
 
+macro(SET_LINK_LIBRARIES)
+  foreach(mainTarget IN LISTS mainTargets)
+    foreach(linkTo IN LISTS linkToThings)
+      target_link_libraries(${mainTarget} PRIVATE ${linkTo})
+    endforeach()
+  endforeach()
+endmacro()
+
 set(mainTargets
     app1
     static1
@@ -125,8 +141,44 @@ set(linkToThings
     "${CMAKE_CURRENT_BINARY_DIR}/ExternalFrameworks/build/Debug/staticFrameworkExt.framework"
 )
 
-foreach(mainTarget IN LISTS mainTargets)
-  foreach(linkTo IN LISTS linkToThings)
-    target_link_libraries(${mainTarget} PRIVATE ${linkTo})
-  endforeach()
-endforeach()
+set_link_libraries()
+
+set(mainTargets
+    app2
+    shared3
+)
+
+set(linkToThings
+    static2
+    "$<LINK_LIBRARY:WEAK_LIBRARY,shared2>"
+    obj2
+    staticFramework2
+    "$<LINK_LIBRARY:WEAK_FRAMEWORK,sharedFramework2>"
+    imported2
+    ${libresolv}
+    ${CoreFoundation}
+    "$<LINK_LIBRARY:WEAK_FRAMEWORK,${CMAKE_CURRENT_BINARY_DIR}/ExternalFrameworks/build/Debug/sharedFrameworkExt.framework>"
+    "${CMAKE_CURRENT_BINARY_DIR}/ExternalFrameworks/build/Debug/staticFrameworkExt.framework"
+)
+
+set_link_libraries()
+
+set(mainTargets
+    app3
+    shared4
+)
+
+set(linkToThings
+    static2
+    "$<LINK_LIBRARY:REEXPORT_LIBRARY,shared2>"
+    obj2
+    staticFramework2
+    "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,sharedFramework2>"
+    imported2
+    ${libresolv}
+    ${CoreFoundation}
+    "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,${CMAKE_CURRENT_BINARY_DIR}/ExternalFrameworks/build/Debug/sharedFrameworkExt.framework>"
+    "${CMAKE_CURRENT_BINARY_DIR}/ExternalFrameworks/build/Debug/staticFrameworkExt.framework"
+)
+
+set_link_libraries()

+ 8 - 1
Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_BUILT_ONLY-check.cmake

@@ -4,13 +4,20 @@ include(${RunCMake_TEST_BINARY_DIR}/foundLibs.cmake)
 # obj2    --> Embeds func3.o in the link flags, but obj2 is part of the path
 # ${libz} --> This is for imported2
 
-foreach(mainTarget IN ITEMS app1 shared1 module1 sharedFramework1)
+foreach(mainTarget IN ITEMS app1 app2 shared1 shared3 module1 sharedFramework1)
   checkFlags(OTHER_LDFLAGS ${mainTarget}
     "obj2;${libz};${libresolv};CoreFoundation;sharedFrameworkExt;staticFrameworkExt"
     "static2;shared2;staticFramework2;sharedFramework2"
   )
 endforeach()
 
+foreach(mainTarget IN ITEMS app3 shared4)
+  checkFlags(OTHER_LDFLAGS ${mainTarget}
+    "obj2;${libz};${libresolv};CoreFoundation;sharedFrameworkExt;staticFrameworkExt;shared2;sharedFramework2"
+    "static2;staticFramework2"
+  )
+endforeach()
+
 foreach(mainTarget IN ITEMS static1 staticFramework1)
   checkFlags(OTHER_LIBTOOLFLAGS ${mainTarget}
     "obj2"

+ 8 - 1
Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_KNOWN_LOCATION-check.cmake

@@ -4,13 +4,20 @@ include(${RunCMake_TEST_BINARY_DIR}/foundLibs.cmake)
 # obj2    --> Embeds func3.o in the link flags, but obj2 is part of the path
 # ${libz} --> This is for imported2
 
-foreach(mainTarget IN ITEMS app1 shared1 module1 sharedFramework1)
+foreach(mainTarget IN ITEMS app1 app2 shared1 shared3 module1 sharedFramework1)
   checkFlags(OTHER_LDFLAGS ${mainTarget}
     "obj2"
     "static2;shared2;staticFramework2;sharedFramework2;${libz};${libresolv};CoreFoundation;sharedFrameworkExt;staticFrameworkExt"
   )
 endforeach()
 
+foreach(mainTarget IN ITEMS app3 shared4)
+  checkFlags(OTHER_LDFLAGS ${mainTarget}
+    "obj2;shared2;sharedFramework2;sharedFrameworkExt"
+    "static2;staticFramework2;${libz};${libresolv};CoreFoundation;staticFrameworkExt"
+  )
+endforeach()
+
 foreach(mainTarget IN ITEMS static1 staticFramework1)
   checkFlags(OTHER_LIBTOOLFLAGS ${mainTarget}
     "obj2"

+ 1 - 1
Tests/RunCMake/XcodeProject/LinkBinariesBuildPhase_NONE-check.cmake

@@ -4,7 +4,7 @@ include(${RunCMake_TEST_BINARY_DIR}/foundLibs.cmake)
 # obj2    --> Embeds func3.o in the link flags, but obj2 is part of the path
 # ${libz} --> This is for imported2
 
-foreach(mainTarget IN ITEMS app1 shared1 module1 sharedFramework1)
+foreach(mainTarget IN ITEMS app1 app2 app3 shared1 shared3 shared4 module1 sharedFramework1)
   checkFlags(OTHER_LDFLAGS ${mainTarget}
     "static2;shared2;staticFramework2;sharedFramework2;obj2;${libz};${libresolv};CoreFoundation;sharedFrameworkExt;staticFrameworkExt"
     ""