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

View File

@ -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;

View File

@ -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
{

View File

@ -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;

View File

@ -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);

View File

@ -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,