mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 10:50:16 -06:00
GenEx/LINK_LIBRARY: Add features for framework support on Apple
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
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <cm/memory>
|
||||
#include <cm/optional>
|
||||
#include <cmext/algorithm>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmComputeLinkDepends.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
@@ -19,7 +20,6 @@
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmOrderDirectories.h"
|
||||
#include "cmOutputConverter.h"
|
||||
#include "cmPlaceholderExpander.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmState.h"
|
||||
@@ -1045,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 {
|
||||
@@ -1425,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)
|
||||
@@ -1680,7 +1712,8 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
|
||||
std::string const& item = entry.Item.Value;
|
||||
|
||||
// Try to separate the framework name and path.
|
||||
auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item);
|
||||
auto fwItems =
|
||||
this->GlobalGenerator->SplitFrameworkPath(item, entry.Feature != DEFAULT);
|
||||
if (!fwItems) {
|
||||
std::ostringstream e;
|
||||
e << "Could not parse framework path \"" << item << "\" "
|
||||
@@ -1691,24 +1724,34 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -2529,7 +2529,8 @@ bool cmGlobalGenerator::NameResolvesToFramework(
|
||||
// .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
|
||||
cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
|
||||
bool extendedFormat) const
|
||||
{
|
||||
// Check for framework structure:
|
||||
// (/path/to/)?FwName.framework
|
||||
@@ -2550,6 +2551,16 @@ cmGlobalGenerator::SplitFrameworkPath(const std::string& path) const
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -368,9 +368,12 @@ public:
|
||||
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 */
|
||||
* 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) const;
|
||||
const std::string& path, bool extendedFormat = false) const;
|
||||
|
||||
cmMakefile* FindMakefile(const std::string& start_dir) const;
|
||||
cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;
|
||||
|
||||
@@ -3519,13 +3519,14 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
|
||||
} else {
|
||||
linkDir = libItem->Value.Value;
|
||||
}
|
||||
linkDir = this->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) ==
|
||||
@@ -3533,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());
|
||||
@@ -3707,24 +3708,27 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
|
||||
if (cmSystemTools::FileIsFullPath(cleanPath)) {
|
||||
cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
|
||||
}
|
||||
const auto libPath = this->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()) {
|
||||
@@ -3892,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);
|
||||
|
||||
@@ -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