cmGlobalGenerator: Add helper to split framework path

cmComputeLinkInformation and cmGlobalXCodeGenerator now rely on
this method to handle framework paths.
This commit is contained in:
Marc Chevrier
2022-02-10 19:16:18 +01:00
parent 350c1fd607
commit 40178f3c90
6 changed files with 58 additions and 45 deletions

View File

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

View File

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

View File

@@ -19,6 +19,7 @@
#include "cmsys/Directory.hxx" #include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx" #include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
# include <windows.h> # include <windows.h>
@@ -2522,6 +2523,36 @@ bool cmGlobalGenerator::NameResolvesToFramework(
return false; 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, bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
std::string const& reason) const std::string const& reason) const
{ {

View File

@@ -367,6 +367,10 @@ public:
/** Determine if a name resolves to a framework on disk or a built target /** Determine if a name resolves to a framework on disk or a built target
that is a framework. */ that is a framework. */
bool NameResolvesToFramework(const std::string& libname) const; 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; cmMakefile* FindMakefile(const std::string& start_dir) const;
cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const; cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;

View File

@@ -1154,47 +1154,25 @@ std::string GetSourcecodeValueFromFileExtension(
return sourcecode; return sourcecode;
} }
// If the file has no extension it's either a raw executable or might } // anonymous
// 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. // Extracts the framework directory, if path matches the framework syntax
// .tbd files also can be located in SDK frameworks (they are // otherwise returns the path untouched
// placeholders for actual libraries shipped with the OS) std::string cmGlobalXCodeGenerator::GetLibraryOrFrameworkPath(
std::string GetLibraryOrFrameworkPath(const std::string& path) const std::string& path) const
{ {
auto ext = cmSystemTools::GetFilenameLastExtension(path); auto fwItems = this->SplitFrameworkPath(path);
if (ext.empty() || ext == ".tbd") { if (fwItems) {
auto name = cmSystemTools::GetFilenameWithoutExtension(path); if (fwItems->first.empty()) {
// Check for iOS framework structure: return cmStrCat(fwItems->second, ".framework");
// FwName.framework/FwName (and also on macOS where FwName lib is a } else {
// symlink) return cmStrCat(fwItems->first, '/', fwItems->second, ".framework");
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);
}
} }
} }
return path; return path;
} }
} // anonymous
cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( 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)
@@ -1217,7 +1195,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
ext = ext.substr(1); ext = ext.substr(1);
} }
if (fileType.empty()) { if (fileType.empty()) {
path = GetLibraryOrFrameworkPath(path); path = this->GetLibraryOrFrameworkPath(path);
ext = cmSystemTools::GetFilenameLastExtension(path); ext = cmSystemTools::GetFilenameLastExtension(path);
if (!ext.empty()) { if (!ext.empty()) {
ext = ext.substr(1); ext = ext.substr(1);
@@ -3541,7 +3519,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
} else { } else {
linkDir = libItem->Value.Value; linkDir = libItem->Value.Value;
} }
linkDir = GetLibraryOrFrameworkPath(linkDir); linkDir = this->GetLibraryOrFrameworkPath(linkDir);
bool isFramework = cmSystemTools::IsPathToFramework(linkDir); bool isFramework = cmSystemTools::IsPathToFramework(linkDir);
linkDir = cmSystemTools::GetParentDirectory(linkDir); linkDir = cmSystemTools::GetParentDirectory(linkDir);
if (isFramework) { if (isFramework) {
@@ -3729,7 +3707,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
if (cmSystemTools::FileIsFullPath(cleanPath)) { if (cmSystemTools::FileIsFullPath(cleanPath)) {
cleanPath = cmSystemTools::CollapseFullPath(cleanPath); cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
} }
const auto libPath = GetLibraryOrFrameworkPath(cleanPath); const auto libPath = this->GetLibraryOrFrameworkPath(cleanPath);
if (cmSystemTools::StringEndsWith(libPath.c_str(), ".framework")) { if (cmSystemTools::StringEndsWith(libPath.c_str(), ".framework")) {
const auto fwName = const auto fwName =
cmSystemTools::GetFilenameWithoutExtension(libPath); cmSystemTools::GetFilenameWithoutExtension(libPath);

View File

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