Browse Source

cmGlobalGenerator: Add helper to split framework path

cmComputeLinkInformation and cmGlobalXCodeGenerator now rely on
this method to handle framework paths.
Marc Chevrier 3 years ago
parent
commit
40178f3c90

+ 5 - 6
Source/cmComputeLinkInformation.cxx

@@ -8,6 +8,7 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/optional>
 #include <cmext/algorithm>
 
 #include "cmComputeLinkDepends.h"
@@ -1679,7 +1680,8 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
   std::string const& item = entry.Item.Value;
 
   // Try to separate the framework name and path.
-  if (!this->SplitFramework.find(item)) {
+  auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item);
+  if (!fwItems) {
     std::ostringstream e;
     e << "Could not parse framework path \"" << item << "\" "
       << "linked by target " << this->Target->GetName() << ".";
@@ -1687,8 +1689,8 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
     return;
   }
 
-  std::string fw_path = this->SplitFramework.match(1);
-  std::string fw = this->SplitFramework.match(2);
+  std::string fw_path = std::move(fwItems->first);
+  std::string fw = std::move(fwItems->second);
   std::string full_fw = cmStrCat(fw_path, '/', fw, ".framework/", fw);
 
   // Add the directory portion to the framework search path.
@@ -1739,9 +1741,6 @@ void cmComputeLinkInformation::ComputeFrameworkInfo()
 
   this->FrameworkPathsEmitted.insert(implicitDirVec.begin(),
                                      implicitDirVec.end());
-
-  // Regular expression to extract a framework path and name.
-  this->SplitFramework.compile("(.*)/(.*)\\.framework$");
 }
 
 void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)

+ 0 - 1
Source/cmComputeLinkInformation.h

@@ -205,7 +205,6 @@ private:
   void ComputeFrameworkInfo();
   void AddFrameworkPath(std::string const& p);
   std::set<std::string> FrameworkPathsEmitted;
-  cmsys::RegularExpression SplitFramework;
 
   // Linker search path computation.
   std::unique_ptr<cmOrderDirectories> OrderLinkerSearchPath;

+ 31 - 0
Source/cmGlobalGenerator.cxx

@@ -19,6 +19,7 @@
 
 #include "cmsys/Directory.hxx"
 #include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #  include <windows.h>
@@ -2522,6 +2523,36 @@ bool cmGlobalGenerator::NameResolvesToFramework(
   return false;
 }
 
+// If the file has no extension it's either a raw executable or might
+// be a direct reference to a binary within a framework (bad practice!).
+// This is where we change the path to point to the framework directory.
+// .tbd files also can be located in SDK frameworks (they are
+// placeholders for actual libraries shipped with the OS)
+cm::optional<std::pair<std::string, std::string>>
+cmGlobalGenerator::SplitFrameworkPath(const std::string& path) const
+{
+  // Check for framework structure:
+  //    (/path/to/)?FwName.framework
+  // or (/path/to/)?FwName.framework/FwName(.tbd)?
+  // or (/path/to/)?FwName.framework/Versions/*/FwName(.tbd)?
+  static cmsys::RegularExpression frameworkPath(
+    "((.+)/)?(.+)\\.framework(/Versions/[^/]+)?(/(.+))?$");
+
+  auto ext = cmSystemTools::GetFilenameLastExtension(path);
+  if ((ext.empty() || ext == ".tbd" || ext == ".framework") &&
+      frameworkPath.find(path)) {
+    auto name = frameworkPath.match(3);
+    auto libname =
+      cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(6));
+    if (!libname.empty() && name != libname) {
+      return cm::nullopt;
+    }
+    return std::pair<std::string, std::string>{ frameworkPath.match(2), name };
+  }
+
+  return cm::nullopt;
+}
+
 bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
                                      std::string const& reason) const
 {

+ 4 - 0
Source/cmGlobalGenerator.h

@@ -367,6 +367,10 @@ public:
   /** Determine if a name resolves to a framework on disk or a built target
       that is a framework. */
   bool NameResolvesToFramework(const std::string& libname) const;
+  /** Split a framework path to the directory and name of the framework
+   * returns std::nullopt if the path does not match with framework format */
+  cm::optional<std::pair<std::string, std::string>> SplitFrameworkPath(
+    const std::string& path) const;
 
   cmMakefile* FindMakefile(const std::string& start_dir) const;
   cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;

+ 16 - 38
Source/cmGlobalXCodeGenerator.cxx

@@ -1154,47 +1154,25 @@ std::string GetSourcecodeValueFromFileExtension(
   return sourcecode;
 }
 
-// If the file has no extension it's either a raw executable or might
-// be a direct reference to a binary within a framework (bad practice!).
-// This is where we change the path to point to the framework directory.
-// .tbd files also can be located in SDK frameworks (they are
-// placeholders for actual libraries shipped with the OS)
-std::string GetLibraryOrFrameworkPath(const std::string& path)
+} // anonymous
+
+// Extracts the framework directory, if path matches the framework syntax
+// otherwise returns the path untouched
+std::string cmGlobalXCodeGenerator::GetLibraryOrFrameworkPath(
+  const std::string& path) const
 {
-  auto ext = cmSystemTools::GetFilenameLastExtension(path);
-  if (ext.empty() || ext == ".tbd") {
-    auto name = cmSystemTools::GetFilenameWithoutExtension(path);
-    // Check for iOS framework structure:
-    //    FwName.framework/FwName (and also on macOS where FwName lib is a
-    //    symlink)
-    auto parentDir = cmSystemTools::GetParentDirectory(path);
-    auto parentName = cmSystemTools::GetFilenameWithoutExtension(parentDir);
-    ext = cmSystemTools::GetFilenameLastExtension(parentDir);
-    if (ext == ".framework" && name == parentName) {
-      return parentDir;
-    }
-    // Check for macOS framework structure:
-    //    FwName.framework/Versions/*/FwName
-    std::vector<std::string> components;
-    cmSystemTools::SplitPath(path, components);
-    if (components.size() > 3 &&
-        components[components.size() - 3] == "Versions") {
-      ext = cmSystemTools::GetFilenameLastExtension(
-        components[components.size() - 4]);
-      parentName = cmSystemTools::GetFilenameWithoutExtension(
-        components[components.size() - 4]);
-      if (ext == ".framework" && name == parentName) {
-        components.erase(components.begin() + components.size() - 3,
-                         components.end());
-        return cmSystemTools::JoinPath(components);
-      }
+  auto fwItems = this->SplitFrameworkPath(path);
+  if (fwItems) {
+    if (fwItems->first.empty()) {
+      return cmStrCat(fwItems->second, ".framework");
+    } else {
+      return cmStrCat(fwItems->first, '/', fwItems->second, ".framework");
     }
   }
+
   return path;
 }
 
-} // anonymous
-
 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& lang, cmSourceFile* sf)
@@ -1217,7 +1195,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
     ext = ext.substr(1);
   }
   if (fileType.empty()) {
-    path = GetLibraryOrFrameworkPath(path);
+    path = this->GetLibraryOrFrameworkPath(path);
     ext = cmSystemTools::GetFilenameLastExtension(path);
     if (!ext.empty()) {
       ext = ext.substr(1);
@@ -3541,7 +3519,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
     } else {
       linkDir = libItem->Value.Value;
     }
-    linkDir = GetLibraryOrFrameworkPath(linkDir);
+    linkDir = this->GetLibraryOrFrameworkPath(linkDir);
     bool isFramework = cmSystemTools::IsPathToFramework(linkDir);
     linkDir = cmSystemTools::GetParentDirectory(linkDir);
     if (isFramework) {
@@ -3729,7 +3707,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
           if (cmSystemTools::FileIsFullPath(cleanPath)) {
             cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
           }
-          const auto libPath = GetLibraryOrFrameworkPath(cleanPath);
+          const auto libPath = this->GetLibraryOrFrameworkPath(cleanPath);
           if (cmSystemTools::StringEndsWith(libPath.c_str(), ".framework")) {
             const auto fwName =
               cmSystemTools::GetFilenameWithoutExtension(libPath);

+ 2 - 0
Source/cmGlobalXCodeGenerator.h

@@ -330,6 +330,8 @@ private:
   {
   }
 
+  std::string GetLibraryOrFrameworkPath(const std::string& path) const;
+
   std::string GetObjectsDirectory(const std::string& projName,
                                   const std::string& configName,
                                   const cmGeneratorTarget* t,