Explorar o código

Xcode: Use "Link Binary With Libraries" to link any library

Add external libraries as fileRefs to Xcode project and add those
references to Link Binary With Libraries build phase.  This allows
linking .a, .o, .dylib, .framework and .tbd libraries through "Link
Binary With Libraries" build phase, as opposed to `OTHER_LINKER_FLAGS`.

This improves on the approach added by commit 58c05e1c73 (Xcode: Use
"Link Binary With Libraries" build phase when possible, 2020-06-12).
Gusts Kaksis %!s(int64=6) %!d(string=hai) anos
pai
achega
e637744c51
Modificáronse 2 ficheiros con 148 adicións e 58 borrados
  1. 142 54
      Source/cmGlobalXCodeGenerator.cxx
  2. 6 4
      Source/cmGlobalXCodeGenerator.h

+ 142 - 54
Source/cmGlobalXCodeGenerator.cxx

@@ -172,6 +172,7 @@ cmGlobalXCodeGenerator::cmGlobalXCodeGenerator(
 
 
   this->RootObject = nullptr;
   this->RootObject = nullptr;
   this->MainGroupChildren = nullptr;
   this->MainGroupChildren = nullptr;
+  this->FrameworkGroup = nullptr;
   this->CurrentMakefile = nullptr;
   this->CurrentMakefile = nullptr;
   this->CurrentLocalGenerator = nullptr;
   this->CurrentLocalGenerator = nullptr;
   this->XcodeBuildCommandInitialized = false;
   this->XcodeBuildCommandInitialized = false;
@@ -668,6 +669,7 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects()
   this->GroupNameMap.clear();
   this->GroupNameMap.clear();
   this->TargetGroup.clear();
   this->TargetGroup.clear();
   this->FileRefs.clear();
   this->FileRefs.clear();
+  this->ExternalLibRefs.clear();
 }
 }
 
 
 void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj)
 void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj)
@@ -736,7 +738,7 @@ std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target,
   return key;
   return key;
 }
 }
 
 
-cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeBuildFileFromPath(
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& lang, cmSourceFile* sf)
   const std::string& lang, cmSourceFile* sf)
 {
 {
@@ -872,7 +874,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
   lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true));
   lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true));
 
 
   cmXCodeObject* buildFile =
   cmXCodeObject* buildFile =
-    this->CreateXCodeSourceFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
+    this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
 
 
   cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
   cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
   settings->AddAttributeIfNotEmpty("COMPILER_FLAGS",
   settings->AddAttributeIfNotEmpty("COMPILER_FLAGS",
@@ -925,6 +927,31 @@ void cmGlobalXCodeGenerator::AddXCodeProjBuildRule(
   }
   }
 }
 }
 
 
+bool IsLibraryExtension(const std::string& fileExt)
+{
+  return (fileExt == ".framework" || fileExt == ".a" || fileExt == ".o" ||
+          fileExt == ".dylib" || fileExt == ".tbd");
+}
+bool IsLibraryType(const std::string& fileType)
+{
+  return (fileType == "wrapper.framework" || fileType == "archive.ar" ||
+          fileType == "compiled.mach-o.objfile" ||
+          fileType == "compiled.mach-o.dylib" ||
+          fileType == "sourcecode.text-based-dylib-definition");
+}
+
+std::string GetDirectoryValueFromFileExtension(const std::string& dirExt)
+{
+  std::string ext = cmSystemTools::LowerCase(dirExt);
+  if (ext == "framework") {
+    return "wrapper.framework";
+  }
+  if (ext == "xcassets") {
+    return "folder.assetcatalog";
+  }
+  return "folder";
+}
+
 std::string GetSourcecodeValueFromFileExtension(
 std::string GetSourcecodeValueFromFileExtension(
   const std::string& _ext, const std::string& lang,
   const std::string& _ext, const std::string& lang,
   bool& keepLastKnownFileType, const std::vector<std::string>& enabled_langs)
   bool& keepLastKnownFileType, const std::vector<std::string>& enabled_langs)
@@ -933,6 +960,7 @@ std::string GetSourcecodeValueFromFileExtension(
   std::string sourcecode = "sourcecode";
   std::string sourcecode = "sourcecode";
 
 
   if (ext == "o") {
   if (ext == "o") {
+    keepLastKnownFileType = true;
     sourcecode = "compiled.mach-o.objfile";
     sourcecode = "compiled.mach-o.objfile";
   } else if (ext == "xctest") {
   } else if (ext == "xctest") {
     sourcecode = "wrapper.cfbundle";
     sourcecode = "wrapper.cfbundle";
@@ -976,6 +1004,14 @@ std::string GetSourcecodeValueFromFileExtension(
     sourcecode += ".metal";
     sourcecode += ".metal";
   } else if (ext == "mig") {
   } else if (ext == "mig") {
     sourcecode += ".mig";
     sourcecode += ".mig";
+  } else if (ext == "tbd") {
+    sourcecode += ".text-based-dylib-definition";
+  } else if (ext == "a") {
+    keepLastKnownFileType = true;
+    sourcecode = "archive.ar";
+  } else if (ext == "dylib") {
+    keepLastKnownFileType = true;
+    sourcecode = "compiled.mach-o.dylib";
   }
   }
   // else
   // else
   //  {
   //  {
@@ -992,20 +1028,6 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& lang, cmSourceFile* sf)
   const std::string& lang, cmSourceFile* sf)
 {
 {
-  std::string key = GetGroupMapKeyFromPath(target, fullpath);
-  cmXCodeObject* fileRef = this->FileRefs[key];
-  if (!fileRef) {
-    fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
-    fileRef->SetComment(fullpath);
-    this->FileRefs[key] = fileRef;
-  }
-  cmXCodeObject* group = this->GroupMap[key];
-  cmXCodeObject* children = group->GetObject("children");
-  if (!children->HasObject(fileRef)) {
-    children->AddObject(fileRef);
-  }
-  fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
-
   bool useLastKnownFileType = false;
   bool useLastKnownFileType = false;
   std::string fileType;
   std::string fileType;
   if (sf) {
   if (sf) {
@@ -1016,19 +1038,18 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
       fileType = *l;
       fileType = *l;
     }
     }
   }
   }
+  // Compute the extension without leading '.'.
+  std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath);
+  if (!ext.empty()) {
+    ext = ext.substr(1);
+  }
   if (fileType.empty()) {
   if (fileType.empty()) {
-    // Compute the extension without leading '.'.
-    std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath);
-    if (!ext.empty()) {
-      ext = ext.substr(1);
-    }
-
     // If fullpath references a directory, then we need to specify
     // If fullpath references a directory, then we need to specify
     // lastKnownFileType as folder in order for Xcode to be able to
     // lastKnownFileType as folder in order for Xcode to be able to
     // open the contents of the folder.
     // open the contents of the folder.
     // (Xcode 4.6 does not like explicitFileType=folder).
     // (Xcode 4.6 does not like explicitFileType=folder).
     if (cmSystemTools::FileIsDirectory(fullpath)) {
     if (cmSystemTools::FileIsDirectory(fullpath)) {
-      fileType = (ext == "xcassets" ? "folder.assetcatalog" : "folder");
+      fileType = GetDirectoryValueFromFileExtension(ext);
       useLastKnownFileType = true;
       useLastKnownFileType = true;
     } else {
     } else {
       fileType = GetSourcecodeValueFromFileExtension(
       fileType = GetSourcecodeValueFromFileExtension(
@@ -1036,18 +1057,38 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
     }
     }
   }
   }
 
 
+  std::string key = GetGroupMapKeyFromPath(target, fullpath);
+  cmXCodeObject* fileRef = this->FileRefs[key];
+  if (!fileRef) {
+    fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+    fileRef->SetComment(fullpath);
+    this->FileRefs[key] = fileRef;
+  }
+  fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
   fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType"
   fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType"
                                              : "explicitFileType",
                                              : "explicitFileType",
                         this->CreateString(fileType));
                         this->CreateString(fileType));
-
   // Store the file path relative to the top of the source tree.
   // Store the file path relative to the top of the source tree.
-  std::string path = this->RelativeToSource(fullpath);
+  std::string path = fullpath;
+  if (!IsLibraryType(fileType)) {
+    path = this->RelativeToSource(fullpath);
+  }
   std::string name = cmSystemTools::GetFilenameName(path);
   std::string name = cmSystemTools::GetFilenameName(path);
   const char* sourceTree =
   const char* sourceTree =
     cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
     cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
   fileRef->AddAttribute("name", this->CreateString(name));
   fileRef->AddAttribute("name", this->CreateString(name));
   fileRef->AddAttribute("path", this->CreateString(path));
   fileRef->AddAttribute("path", this->CreateString(path));
   fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
   fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
+
+  cmXCodeObject* group = this->GroupMap[key];
+  if (!group && IsLibraryType(fileType)) {
+    group = this->FrameworkGroup;
+    this->GroupMap[key] = group;
+  }
+  cmXCodeObject* children = group->GetObject("children");
+  if (!children->HasObject(fileRef)) {
+    children->AddObject(fileRef);
+  }
   return fileRef;
   return fileRef;
 }
 }
 
 
@@ -1182,11 +1223,14 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget(
       this->CurrentLocalGenerator, sourceFile, gtgt);
       this->CurrentLocalGenerator, sourceFile, gtgt);
     cmXCodeObject* fr = xsf->GetObject("fileRef");
     cmXCodeObject* fr = xsf->GetObject("fileRef");
     cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType");
     cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType");
+    if (!filetype) {
+      filetype = fr->GetObject()->GetObject("lastKnownFileType");
+    }
 
 
     cmGeneratorTarget::SourceFileFlags tsFlags =
     cmGeneratorTarget::SourceFileFlags tsFlags =
       gtgt->GetTargetSourceFileFlags(sourceFile);
       gtgt->GetTargetSourceFileFlags(sourceFile);
 
 
-    if (filetype && filetype->GetString() == "compiled.mach-o.objfile") {
+    if (filetype && IsLibraryType(filetype->GetString())) {
       if (sourceFile->GetObjectLibrary().empty()) {
       if (sourceFile->GetObjectLibrary().empty()) {
         externalObjFiles.push_back(xsf);
         externalObjFiles.push_back(xsf);
       }
       }
@@ -2800,21 +2844,30 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
       continue;
       continue;
     }
     }
     for (auto const& libItem : cli->GetItems()) {
     for (auto const& libItem : cli->GetItems()) {
-      // TODO: Drop this check once we have option to add outside libraries to
-      // Xcode project
-      auto* libTarget = FindXCodeTarget(libItem.Target);
       if (gt->IsBundleOnApple() &&
       if (gt->IsBundleOnApple() &&
           (gt->GetType() == cmStateEnums::EXECUTABLE ||
           (gt->GetType() == cmStateEnums::EXECUTABLE ||
            gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
            gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
            gt->GetType() == cmStateEnums::MODULE_LIBRARY ||
            gt->GetType() == cmStateEnums::MODULE_LIBRARY ||
            gt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) &&
            gt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) &&
-          (libTarget && libItem.Target &&
-           (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
-            libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
-            libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY))) {
+          ((libItem.Target &&
+            (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+             libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+             libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY)) ||
+           (!libItem.Target && libItem.IsPath))) {
         // Add unique configuration name to target-config map for later
         // Add unique configuration name to target-config map for later
         // checks
         // checks
-        std::string libName = libItem.Target->GetName();
+        std::string libName;
+        if (libItem.Target) {
+          libName = libItem.Target->GetName();
+        } else {
+          libName = cmSystemTools::GetFilenameName(libItem.Value.Value);
+          const auto libExt = cmSystemTools::GetFilenameExtension(libName);
+          if (!IsLibraryExtension(libExt)) {
+            // Add this library item to a regular linker flag list
+            addToLinkerArguments(configName, &libItem);
+            continue;
+          }
+        }
         auto& configVector = targetConfigMap[libName];
         auto& configVector = targetConfigMap[libName];
         if (std::find(configVector.begin(), configVector.end(), configName) ==
         if (std::find(configVector.begin(), configVector.end(), configName) ==
             configVector.end()) {
             configVector.end()) {
@@ -2865,38 +2918,63 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
   std::vector<std::string> linkSearchPaths;
   std::vector<std::string> linkSearchPaths;
   for (auto const& libItem : linkPhaseTargetVector) {
   for (auto const& libItem : linkPhaseTargetVector) {
     // Add target output directory as a library search path
     // Add target output directory as a library search path
-    std::string linkDir = cmSystemTools::GetParentDirectory(
-      libItem->Target->GetLocationForBuild());
+    std::string linkDir;
+    if (libItem->Target) {
+      linkDir = cmSystemTools::GetParentDirectory(
+        libItem->Target->GetLocationForBuild());
+    } else {
+      linkDir = cmSystemTools::GetParentDirectory(libItem->Value.Value);
+    }
     if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) ==
     if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) ==
         linkSearchPaths.end()) {
         linkSearchPaths.end()) {
       linkSearchPaths.push_back(linkDir);
       linkSearchPaths.push_back(linkDir);
     }
     }
     // Add target dependency
     // Add target dependency
-    auto const& libName = *libItem;
-    if (!libName.Target->IsImported()) {
+    if (libItem->Target && !libItem->Target->IsImported()) {
       for (auto const& configName : this->CurrentConfigurationTypes) {
       for (auto const& configName : this->CurrentConfigurationTypes) {
-        target->AddDependTarget(configName, libName.Target->GetName());
+        target->AddDependTarget(configName, libItem->Target->GetName());
       }
       }
     }
     }
     // Get the library target
     // Get the library target
     auto* libTarget = FindXCodeTarget(libItem->Target);
     auto* libTarget = FindXCodeTarget(libItem->Target);
-    if (!libTarget) {
-      continue;
-    }
-    // Add the target output file as a build reference for other targets
-    // to link against
-    auto* fileRefObject = libTarget->GetObject("productReference");
-    if (!fileRefObject) {
-      continue;
-    }
     cmXCodeObject* buildFile;
     cmXCodeObject* buildFile;
-    auto it = FileRefToBuildFileMap.find(fileRefObject);
-    if (it == FileRefToBuildFileMap.end()) {
-      buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
-      buildFile->AddAttribute("fileRef", fileRefObject);
-      FileRefToBuildFileMap[fileRefObject] = buildFile;
+    if (!libTarget) {
+      if (libItem->IsPath) {
+        // Get or create a direct file ref in the root project
+        auto it = this->ExternalLibRefs.find(libItem->Value.Value);
+        if (it == this->ExternalLibRefs.end()) {
+          buildFile = CreateXCodeBuildFileFromPath(libItem->Value.Value, gt,
+                                                   "", nullptr);
+          this->ExternalLibRefs.emplace(libItem->Value.Value, buildFile);
+        } else {
+          buildFile = it->second;
+        }
+      } else {
+        // Add this library item back to a regular linker flag list
+        for (const auto& conf : configItemMap) {
+          addToLinkerArguments(conf.first, libItem);
+        }
+        continue;
+      }
     } else {
     } else {
-      buildFile = it->second;
+      // Add the target output file as a build reference for other targets
+      // to link against
+      auto* fileRefObject = libTarget->GetObject("productReference");
+      if (!fileRefObject) {
+        // Add this library item back to a regular linker flag list
+        for (const auto& conf : configItemMap) {
+          addToLinkerArguments(conf.first, libItem);
+        }
+        continue;
+      }
+      auto it = FileRefToBuildFileMap.find(fileRefObject);
+      if (it == FileRefToBuildFileMap.end()) {
+        buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+        buildFile->AddAttribute("fileRef", fileRefObject);
+        FileRefToBuildFileMap[fileRefObject] = buildFile;
+      } else {
+        buildFile = it->second;
+      }
     }
     }
     // Add this reference to current target
     // Add this reference to current target
     auto* buildPhases = target->GetObject("buildPhases");
     auto* buildPhases = target->GetObject("buildPhases");
@@ -3164,6 +3242,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
   this->ClearXCodeObjects();
   this->ClearXCodeObjects();
   this->RootObject = nullptr;
   this->RootObject = nullptr;
   this->MainGroupChildren = nullptr;
   this->MainGroupChildren = nullptr;
+  this->FrameworkGroup = nullptr;
   cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
   cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
   group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
   group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
   cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
   cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
@@ -3198,6 +3277,15 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
   productGroup->AddAttribute("children", productGroupChildren);
   productGroup->AddAttribute("children", productGroupChildren);
   this->MainGroupChildren->AddObject(productGroup);
   this->MainGroupChildren->AddObject(productGroup);
 
 
+  this->FrameworkGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+  this->FrameworkGroup->AddAttribute("name", this->CreateString("Frameworks"));
+  this->FrameworkGroup->AddAttribute("sourceTree",
+                                     this->CreateString("<group>"));
+  cmXCodeObject* frameworkGroupChildren =
+    this->CreateObject(cmXCodeObject::OBJECT_LIST);
+  this->FrameworkGroup->AddAttribute("children", frameworkGroupChildren);
+  this->MainGroupChildren->AddObject(this->FrameworkGroup);
+
   this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
   this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
   this->RootObject->SetComment("Project object");
   this->RootObject->SetComment("Project object");
 
 

+ 6 - 4
Source/cmGlobalXCodeGenerator.h

@@ -203,10 +203,10 @@ private:
                                                   cmGeneratorTarget* target,
                                                   cmGeneratorTarget* target,
                                                   const std::string& lang,
                                                   const std::string& lang,
                                                   cmSourceFile* sf);
                                                   cmSourceFile* sf);
-  cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string& fullpath,
-                                               cmGeneratorTarget* target,
-                                               const std::string& lang,
-                                               cmSourceFile* sf);
+  cmXCodeObject* CreateXCodeBuildFileFromPath(const std::string& fullpath,
+                                              cmGeneratorTarget* target,
+                                              const std::string& lang,
+                                              cmSourceFile* sf);
   cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
   cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
                                           cmGeneratorTarget* target);
                                           cmGeneratorTarget* target);
   cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf,
   cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf,
@@ -281,6 +281,7 @@ private:
   std::string PostBuildMakeTarget(std::string const& tName,
   std::string PostBuildMakeTarget(std::string const& tName,
                                   std::string const& configName);
                                   std::string const& configName);
   cmXCodeObject* MainGroupChildren;
   cmXCodeObject* MainGroupChildren;
+  cmXCodeObject* FrameworkGroup;
   cmMakefile* CurrentMakefile;
   cmMakefile* CurrentMakefile;
   cmLocalGenerator* CurrentLocalGenerator;
   cmLocalGenerator* CurrentLocalGenerator;
   std::vector<std::string> CurrentConfigurationTypes;
   std::vector<std::string> CurrentConfigurationTypes;
@@ -294,6 +295,7 @@ private:
   std::map<std::string, cmXCodeObject*> GroupNameMap;
   std::map<std::string, cmXCodeObject*> GroupNameMap;
   std::map<std::string, cmXCodeObject*> TargetGroup;
   std::map<std::string, cmXCodeObject*> TargetGroup;
   std::map<std::string, cmXCodeObject*> FileRefs;
   std::map<std::string, cmXCodeObject*> FileRefs;
+  std::map<std::string, cmXCodeObject*> ExternalLibRefs;
   std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
   std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
   std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap;
   std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap;
   std::vector<std::string> Architectures;
   std::vector<std::string> Architectures;