mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-02 03:39:43 -06:00
Merge topic 'LINK_LIBRARY-framework'
a2cfa2da4fGenEx/LINK_LIBRARY: Add features for framework support on Apple40178f3c90cmGlobalGenerator: Add helper to split framework path Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !6967
This commit is contained in:
11
Help/release/dev/Apple-link-framework.rst
Normal file
11
Help/release/dev/Apple-link-framework.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
Apple-link-framework
|
||||
--------------------
|
||||
|
||||
* The :genex:`LINK_LIBRARY` generator expression gained the ability to link
|
||||
frameworks in various ways when targeting ``Apple`` platforms. The following
|
||||
new features were added:
|
||||
|
||||
* ``FRAMEWORK``
|
||||
* ``NEEDED_FRAMEWORK``
|
||||
* ``REEXPORT_FRAMEWORK``
|
||||
* ``WEAK_FRAMEWORK``
|
||||
@@ -3,3 +3,43 @@
|
||||
* ``DEFAULT``: This feature enables default link expression. This is mainly
|
||||
useful with :prop_tgt:`LINK_LIBRARY_OVERRIDE` and
|
||||
:prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties.
|
||||
|
||||
**Features available in Apple environments**
|
||||
|
||||
It is assumed that the linker used is the one provided by `XCode` or is
|
||||
compatible with it.
|
||||
|
||||
* ``FRAMEWORK``: This option tells the linker to search for the specified
|
||||
framework (use linker option ``-framework``).
|
||||
* ``NEEDED_FRAMEWORK``: This is the same as the ``FRAMEWORK`` feature but means
|
||||
to really link with the framework even if no symbols are used from it (use
|
||||
linker option ``-needed_framework``).
|
||||
* ``REEXPORT_FRAMEWORK``: This is the same as the ``FRAMEWORK`` feature but
|
||||
also specifies that all symbols in that framework should be available to
|
||||
clients linking to the library being created (use linker option
|
||||
``-reexport_framework``).
|
||||
* ``WEAK_FRAMEWORK``: This is the same as the ``FRAMEWORK`` feature but forces
|
||||
the framework and all references to it to be marked as weak imports (use
|
||||
linker option ``-weak_framework``).
|
||||
|
||||
Features for framework linking have a special handling in ``CMake``: the
|
||||
framework can be specified as a ``CMake`` framework target or file path. In
|
||||
the later case, if the path includes a directory part, this one will be
|
||||
specified as framework search path at link step.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
add_library(lib SHARED ...)
|
||||
target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:NEEDED_FRAMEWORK,/path/to/my_framework>")
|
||||
|
||||
# at link step we will have:
|
||||
# -F/path/to -needed_framework my_framework
|
||||
|
||||
.. note::
|
||||
|
||||
The expected formats for the file path, with optional parts specified as
|
||||
``()?``, are:
|
||||
|
||||
* (/path/to/)?FwName(.framework)?
|
||||
* (/path/to/)?FwName.framework/FwName
|
||||
* (/path/to/)?FwName.framework/Versions/\*/FwName
|
||||
|
||||
@@ -38,3 +38,18 @@ set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE "")
|
||||
if(UNIX)
|
||||
list(APPEND CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "rt" "pthread" "dl")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
# Defines host link features for frameworks
|
||||
set(CMAKE_CUDA_LINK_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_CUDA_LINK_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_CUDA_LINK_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_CUDA_LINK_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_WEAK_FRAMEWORK_SUPPORTED TRUE)
|
||||
endif()
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
set(CMAKE_Swift_SYSROOT_FLAG "-sdk")
|
||||
|
||||
|
||||
# Defines host link features for frameworks
|
||||
set(CMAKE_Swift_LINK_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
|
||||
set(CMAKE_Swift_LINK_USING_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_Swift_LINK_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>")
|
||||
set(CMAKE_Swift_LINK_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_Swift_LINK_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>")
|
||||
set(CMAKE_Swift_LINK_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_Swift_LINK_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>")
|
||||
set(CMAKE_Swift_LINK_USING_WEAK_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
@@ -17,3 +17,17 @@ set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS "-shared -Wl,-headerpad_max_install_na
|
||||
|
||||
set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
|
||||
set(CMAKE_CUDA_CREATE_SHARED_MODULE "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
|
||||
|
||||
|
||||
# Defines host link features for frameworks
|
||||
set(CMAKE_CUDA_LINK_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_CUDA_LINK_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_CUDA_LINK_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_CUDA_LINK_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>")
|
||||
set(CMAKE_CUDA_LINK_USING_WEAK_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
@@ -106,6 +106,19 @@ foreach(lang C CXX Fortran OBJC OBJCXX)
|
||||
# Set default framework search path flag for languages known to use a
|
||||
# preprocessor that may find headers in frameworks.
|
||||
set(CMAKE_${lang}_FRAMEWORK_SEARCH_FLAG -F)
|
||||
|
||||
# Defines link features for frameworks
|
||||
set(CMAKE_${lang}_LINK_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
|
||||
set(CMAKE_${lang}_LINK_USING_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_${lang}_LINK_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>")
|
||||
set(CMAKE_${lang}_LINK_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_${lang}_LINK_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>")
|
||||
set(CMAKE_${lang}_LINK_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE)
|
||||
|
||||
set(CMAKE_${lang}_LINK_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>")
|
||||
set(CMAKE_${lang}_LINK_USING_WEAK_FRAMEWORK_SUPPORTED TRUE)
|
||||
endforeach()
|
||||
|
||||
# default to searching for frameworks first
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <utility>
|
||||
|
||||
#include <cm/memory>
|
||||
#include <cm/optional>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmComputeLinkDepends.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
@@ -18,7 +20,6 @@
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmOrderDirectories.h"
|
||||
#include "cmOutputConverter.h"
|
||||
#include "cmPlaceholderExpander.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmState.h"
|
||||
@@ -1044,12 +1045,14 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
|
||||
}
|
||||
} else {
|
||||
// This is not a CMake target. Use the name given.
|
||||
if (cmSystemTools::FileIsFullPath(item.Value)) {
|
||||
if (cmSystemTools::IsPathToFramework(item.Value) &&
|
||||
this->Makefile->IsOn("APPLE")) {
|
||||
// This is a framework.
|
||||
this->AddFrameworkItem(entry);
|
||||
} else if (cmSystemTools::FileIsDirectory(item.Value)) {
|
||||
if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) ||
|
||||
(entry.Feature == DEFAULT &&
|
||||
cmSystemTools::IsPathToFramework(item.Value) &&
|
||||
this->Makefile->IsOn("APPLE"))) {
|
||||
// This is a framework.
|
||||
this->AddFrameworkItem(entry);
|
||||
} else if (cmSystemTools::FileIsFullPath(item.Value)) {
|
||||
if (cmSystemTools::FileIsDirectory(item.Value)) {
|
||||
// This is a directory.
|
||||
this->DropDirectoryItem(item);
|
||||
} else {
|
||||
@@ -1424,11 +1427,41 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
|
||||
this->OldLinkDirItems.push_back(item.Value);
|
||||
}
|
||||
|
||||
// Now add the full path to the library.
|
||||
this->Items.emplace_back(item, ItemIsPath::Yes, target,
|
||||
this->FindLibraryFeature(entry.Feature == DEFAULT
|
||||
? "__CMAKE_LINK_LIBRARY"
|
||||
: entry.Feature));
|
||||
if (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode() &&
|
||||
entry.Feature == DEFAULT) {
|
||||
// ensure FRAMEWORK feature is loaded
|
||||
this->AddLibraryFeature("FRAMEWORK");
|
||||
}
|
||||
|
||||
if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) &&
|
||||
target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) {
|
||||
// Add the framework directory and the framework item itself
|
||||
auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item.Value, true);
|
||||
if (!fwItems) {
|
||||
this->CMakeInstance->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Could not parse framework path \"", item.Value,
|
||||
"\" linked by target ", this->Target->GetName(), '.'),
|
||||
item.Backtrace);
|
||||
return;
|
||||
}
|
||||
if (!fwItems->first.empty()) {
|
||||
// Add the directory portion to the framework search path.
|
||||
this->AddFrameworkPath(fwItems->first);
|
||||
}
|
||||
this->Items.emplace_back(fwItems->second, ItemIsPath::Yes, target,
|
||||
this->FindLibraryFeature(entry.Feature));
|
||||
} else {
|
||||
// Now add the full path to the library.
|
||||
this->Items.emplace_back(
|
||||
item, ItemIsPath::Yes, target,
|
||||
this->FindLibraryFeature(
|
||||
entry.Feature == DEFAULT
|
||||
? (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode()
|
||||
? "FRAMEWORK"
|
||||
: "__CMAKE_LINK_LIBRARY")
|
||||
: entry.Feature));
|
||||
}
|
||||
}
|
||||
|
||||
void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry)
|
||||
@@ -1679,7 +1712,9 @@ 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, entry.Feature != DEFAULT);
|
||||
if (!fwItems) {
|
||||
std::ostringstream e;
|
||||
e << "Could not parse framework path \"" << item << "\" "
|
||||
<< "linked by target " << this->Target->GetName() << ".";
|
||||
@@ -1687,26 +1722,36 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
|
||||
return;
|
||||
}
|
||||
|
||||
std::string fw_path = this->SplitFramework.match(1);
|
||||
std::string fw = this->SplitFramework.match(2);
|
||||
std::string full_fw = cmStrCat(fw_path, '/', fw, ".framework/", fw);
|
||||
std::string fw_path = std::move(fwItems->first);
|
||||
std::string fw = std::move(fwItems->second);
|
||||
std::string full_fw = cmStrCat(fw, ".framework/", fw);
|
||||
|
||||
// Add the directory portion to the framework search path.
|
||||
this->AddFrameworkPath(fw_path);
|
||||
if (!fw_path.empty()) {
|
||||
full_fw = cmStrCat(fw_path, '/', full_fw);
|
||||
// Add the directory portion to the framework search path.
|
||||
this->AddFrameworkPath(fw_path);
|
||||
}
|
||||
|
||||
// add runtime information
|
||||
this->AddLibraryRuntimeInfo(full_fw);
|
||||
|
||||
if (entry.Feature == DEFAULT) {
|
||||
// ensure FRAMEWORK feature is loaded
|
||||
this->AddLibraryFeature("FRAMEWORK");
|
||||
}
|
||||
|
||||
if (this->GlobalGenerator->IsXcode()) {
|
||||
// Add framework path - it will be handled by Xcode after it's added to
|
||||
// "Link Binary With Libraries" build phase
|
||||
this->Items.emplace_back(item, ItemIsPath::Yes);
|
||||
this->Items.emplace_back(item, ItemIsPath::Yes, nullptr,
|
||||
this->FindLibraryFeature(entry.Feature == DEFAULT
|
||||
? "FRAMEWORK"
|
||||
: entry.Feature));
|
||||
} else {
|
||||
// Add the item using the -framework option.
|
||||
this->Items.emplace_back(std::string("-framework"), ItemIsPath::No);
|
||||
cmOutputConverter converter(this->Makefile->GetStateSnapshot());
|
||||
fw = converter.EscapeForShell(fw);
|
||||
this->Items.emplace_back(fw, ItemIsPath::No);
|
||||
this->Items.emplace_back(fw, ItemIsPath::Yes, nullptr,
|
||||
this->FindLibraryFeature(entry.Feature == DEFAULT
|
||||
? "FRAMEWORK"
|
||||
: entry.Feature));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1739,9 +1784,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)
|
||||
|
||||
@@ -63,6 +63,11 @@ public:
|
||||
cmGeneratorTarget const* Target = nullptr;
|
||||
|
||||
bool HasFeature() const { return this->Feature != nullptr; }
|
||||
const std::string& GetFeatureName() const
|
||||
{
|
||||
return HasFeature() ? this->Feature->Name
|
||||
: cmComputeLinkDepends::LinkEntry::DEFAULT;
|
||||
}
|
||||
|
||||
BT<std::string> GetFormattedItem(std::string const& path) const
|
||||
{
|
||||
@@ -205,7 +210,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;
|
||||
|
||||
@@ -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,47 @@ 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,
|
||||
bool extendedFormat) 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 };
|
||||
}
|
||||
|
||||
if (extendedFormat) {
|
||||
// path format can be more flexible: (/path/to/)?fwName(.framework)?
|
||||
auto fwDir = cmSystemTools::GetParentDirectory(path);
|
||||
auto name = cmSystemTools::GetFilenameLastExtension(path) == ".framework"
|
||||
? cmSystemTools::GetFilenameWithoutExtension(path)
|
||||
: cmSystemTools::GetFilenameName(path);
|
||||
|
||||
return std::pair<std::string, std::string>{ fwDir, name };
|
||||
}
|
||||
|
||||
return cm::nullopt;
|
||||
}
|
||||
|
||||
bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
|
||||
std::string const& reason) const
|
||||
{
|
||||
|
||||
@@ -367,6 +367,13 @@ 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
|
||||
* when extendedFormat is true, required format is relaxed (i.e. extension
|
||||
* `.framework' is optional). Used when FRAMEWORK link feature is
|
||||
* specified */
|
||||
cm::optional<std::pair<std::string, std::string>> SplitFrameworkPath(
|
||||
const std::string& path, bool extendedFormat = false) const;
|
||||
|
||||
cmMakefile* FindMakefile(const std::string& start_dir) const;
|
||||
cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;
|
||||
|
||||
@@ -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,13 +3519,14 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
|
||||
} else {
|
||||
linkDir = libItem->Value.Value;
|
||||
}
|
||||
linkDir = GetLibraryOrFrameworkPath(linkDir);
|
||||
bool isFramework = cmSystemTools::IsPathToFramework(linkDir);
|
||||
linkDir = cmSystemTools::GetParentDirectory(linkDir);
|
||||
if (isFramework) {
|
||||
if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(),
|
||||
linkDir) == frameworkSearchPaths.end()) {
|
||||
frameworkSearchPaths.push_back(linkDir);
|
||||
if (cmHasSuffix(libItem->GetFeatureName(), "FRAMEWORK"_s)) {
|
||||
auto fwItems = this->SplitFrameworkPath(linkDir, true);
|
||||
if (fwItems && !fwItems->first.empty()) {
|
||||
linkDir = std::move(fwItems->first);
|
||||
if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(),
|
||||
linkDir) == frameworkSearchPaths.end()) {
|
||||
frameworkSearchPaths.push_back(linkDir);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) ==
|
||||
@@ -3555,7 +3534,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
|
||||
linkSearchPaths.push_back(linkDir);
|
||||
}
|
||||
}
|
||||
// Add target dependency
|
||||
|
||||
if (libItem->Target && !libItem->Target->IsImported()) {
|
||||
for (auto const& configName : this->CurrentConfigurationTypes) {
|
||||
target->AddDependTarget(configName, libItem->Target->GetName());
|
||||
@@ -3729,24 +3708,27 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
|
||||
if (cmSystemTools::FileIsFullPath(cleanPath)) {
|
||||
cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
|
||||
}
|
||||
const auto libPath = GetLibraryOrFrameworkPath(cleanPath);
|
||||
if (cmSystemTools::StringEndsWith(libPath.c_str(), ".framework")) {
|
||||
const auto fwName =
|
||||
cmSystemTools::GetFilenameWithoutExtension(libPath);
|
||||
const auto fwDir = cmSystemTools::GetParentDirectory(libPath);
|
||||
if (emitted.insert(fwDir).second) {
|
||||
// This is a search path we had not added before and it isn't an
|
||||
// implicit search path, so we need it
|
||||
libPaths.Add("-F " + this->XCodeEscapePath(fwDir));
|
||||
bool isFramework =
|
||||
cmHasSuffix(libName.GetFeatureName(), "FRAMEWORK"_s);
|
||||
if (isFramework) {
|
||||
const auto fwItems =
|
||||
this->SplitFrameworkPath(cleanPath, isFramework);
|
||||
if (!fwItems->first.empty() &&
|
||||
emitted.insert(fwItems->first).second) {
|
||||
// This is a search path we had not added before and it isn't
|
||||
// an implicit search path, so we need it
|
||||
libPaths.Add("-F " + this->XCodeEscapePath(fwItems->first));
|
||||
}
|
||||
libPaths.Add("-framework " + this->XCodeEscapePath(fwName));
|
||||
libPaths.Add(
|
||||
libName.GetFormattedItem(this->XCodeEscapePath(fwItems->second))
|
||||
.Value);
|
||||
} else {
|
||||
libPaths.Add(
|
||||
libName.GetFormattedItem(this->XCodeEscapePath(cleanPath))
|
||||
.Value);
|
||||
}
|
||||
if ((!libName.Target || libName.Target->IsImported()) &&
|
||||
IsLinkPhaseLibraryExtension(libPath)) {
|
||||
(isFramework || IsLinkPhaseLibraryExtension(cleanPath))) {
|
||||
// Create file reference for embedding
|
||||
auto it = this->ExternalLibRefs.find(cleanPath);
|
||||
if (it == this->ExternalLibRefs.end()) {
|
||||
@@ -3914,8 +3896,8 @@ void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target)
|
||||
{
|
||||
static const auto dstSubfolderSpec = "10";
|
||||
|
||||
// Despite the name, by default Xcode uses "Embed Frameworks" build phase for
|
||||
// both frameworks and dynamic libraries
|
||||
// Despite the name, by default Xcode uses "Embed Frameworks" build phase
|
||||
// for both frameworks and dynamic libraries
|
||||
this->AddEmbeddedObjects(target, "Embed Frameworks",
|
||||
"XCODE_EMBED_FRAMEWORKS", dstSubfolderSpec,
|
||||
NoActionOnCopyByDefault);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -659,6 +659,7 @@ add_RunCMake_test(target_link_libraries-LINK_LIBRARY -DCMAKE_SYSTEM_NAME=${CMAKE
|
||||
-DMSYS=${MSYS}
|
||||
-DCYGWIN=${CYGWIN}
|
||||
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
|
||||
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
|
||||
-DMSVC_VERSION=${MSVC_VERSION}
|
||||
-DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX}
|
||||
-DCMAKE_SHARED_LIBRARY_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
|
||||
@@ -79,3 +79,21 @@ if ((RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Xcode"
|
||||
unset(RunCMake_TEST_OUTPUT_MERGE)
|
||||
|
||||
endif()
|
||||
|
||||
# Apple framework features
|
||||
if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang"))
|
||||
run_cmake(apple_framework)
|
||||
run_cmake_target(apple_framework framework main-framework)
|
||||
run_cmake_target(apple_framework reexport_framework main-reexport_framework)
|
||||
run_cmake_target(apple_framework weak_framework main-weak_framework)
|
||||
|
||||
run_cmake_target(apple_framework target-framework main-target-framework)
|
||||
run_cmake_target(apple_framework target-reexport_framework main-target-reexport_framework)
|
||||
run_cmake_target(apple_framework target-weak_framework main-target-weak_framework)
|
||||
endif()
|
||||
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION GREATER_EQUAL "12")
|
||||
run_cmake_target(apple_framework needed_framework main-needed_framework)
|
||||
|
||||
run_cmake_target(apple_framework target-needed_framework main-target-needed_framework)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
enable_language(OBJCXX)
|
||||
|
||||
|
||||
# feature FRAMEWORK
|
||||
add_library(foo-framework SHARED foo.mm)
|
||||
target_link_libraries(foo-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>")
|
||||
|
||||
add_executable(main-framework main.mm)
|
||||
target_link_libraries(main-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-framework)
|
||||
|
||||
|
||||
# feature NEEDED_FRAMEWORK
|
||||
add_library(foo-needed_framework SHARED foo.mm)
|
||||
target_link_libraries(foo-needed_framework PRIVATE "$<LINK_LIBRARY:NEEDED_FRAMEWORK,Foundation>")
|
||||
|
||||
add_executable(main-needed_framework main.mm)
|
||||
target_link_libraries(main-needed_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-needed_framework)
|
||||
|
||||
|
||||
# feature REEXPORT_FRAMEWORK
|
||||
add_library(foo-reexport_framework SHARED foo.mm)
|
||||
target_link_libraries(foo-reexport_framework PRIVATE "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,Foundation>")
|
||||
|
||||
add_executable(main-reexport_framework main.mm)
|
||||
target_link_libraries(main-reexport_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-reexport_framework)
|
||||
|
||||
|
||||
# feature WEAK_FRAMEWORK
|
||||
add_library(foo-weak_framework SHARED foo.mm)
|
||||
target_link_libraries(foo-weak_framework PRIVATE "$<LINK_LIBRARY:WEAK_FRAMEWORK,Foundation>")
|
||||
|
||||
add_executable(main-weak_framework main.mm)
|
||||
target_link_libraries(main-weak_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" foo-weak_framework)
|
||||
|
||||
|
||||
##
|
||||
## Consumption of target specified as FRAMEWORK
|
||||
add_library(target-framework SHARED foo.mm)
|
||||
set_target_properties(target-framework PROPERTIES FRAMEWORK TRUE)
|
||||
target_link_libraries(target-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>")
|
||||
|
||||
|
||||
# feature FRAMEWORK
|
||||
add_executable(main-target-framework main.mm)
|
||||
target_link_libraries(main-target-framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:FRAMEWORK,target-framework>")
|
||||
|
||||
|
||||
# feature NEEDED_FRAMEWORK
|
||||
add_executable(main-target-needed_framework main.mm)
|
||||
target_link_libraries(main-target-needed_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:NEEDED_FRAMEWORK,target-framework>")
|
||||
|
||||
|
||||
# feature REEXPORT_FRAMEWORK
|
||||
add_executable(main-target-reexport_framework main.mm)
|
||||
target_link_libraries(main-target-reexport_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,target-framework>")
|
||||
|
||||
|
||||
# feature WEAK_FRAMEWORK
|
||||
add_executable(main-target-weak_framework main.mm)
|
||||
target_link_libraries(main-target-weak_framework PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,target-framework>")
|
||||
9
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h
Normal file
9
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface Foo : NSObject {
|
||||
NSNumber* age;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSNumber* age;
|
||||
|
||||
@end
|
||||
7
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm
Normal file
7
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm
Normal file
@@ -0,0 +1,7 @@
|
||||
#import "foo.h"
|
||||
|
||||
@implementation Foo
|
||||
|
||||
@synthesize age;
|
||||
|
||||
@end
|
||||
14
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm
Normal file
14
Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm
Normal file
@@ -0,0 +1,14 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "foo.h"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
Foo *theFoo = [[Foo alloc] init];
|
||||
theFoo.age = [NSNumber numberWithInt:argc];
|
||||
NSLog(@"%d\n",[theFoo.age intValue]);
|
||||
std::cout << [theFoo.age intValue] << std::endl;
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user