summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2022-02-10 23:57:14 +0100
committerMarc Chevrier <marc.chevrier@gmail.com>2022-02-15 10:53:33 +0100
commita2cfa2da4f53a5e9c78e6cf7332c6a308ef38af2 (patch)
tree28ddbbd9f07ad92b87fbe439c2ead74041c74f44
parent40178f3c908795a993148553a04be25748942efc (diff)
downloadcmake-a2cfa2da4f53a5e9c78e6cf7332c6a308ef38af2.tar.gz
GenEx/LINK_LIBRARY: Add features for framework support on Apple
-rw-r--r--Help/release/dev/Apple-link-framework.rst11
-rw-r--r--Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt40
-rw-r--r--Modules/Compiler/Clang-CUDA.cmake15
-rw-r--r--Modules/Platform/Apple-Apple-Swift.cmake14
-rw-r--r--Modules/Platform/Apple-NVIDIA-CUDA.cmake14
-rw-r--r--Modules/Platform/Darwin.cmake13
-rw-r--r--Source/cmComputeLinkInformation.cxx87
-rw-r--r--Source/cmComputeLinkInformation.h5
-rw-r--r--Source/cmGlobalGenerator.cxx13
-rw-r--r--Source/cmGlobalGenerator.h7
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx46
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake18
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake61
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h9
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm7
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm14
17 files changed, 329 insertions, 46 deletions
diff --git a/Help/release/dev/Apple-link-framework.rst b/Help/release/dev/Apple-link-framework.rst
new file mode 100644
index 0000000000..e194c157d2
--- /dev/null
+++ b/Help/release/dev/Apple-link-framework.rst
@@ -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``
diff --git a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
index dd22e1463e..d4fdf763c9 100644
--- a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
+++ b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
@@ -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
diff --git a/Modules/Compiler/Clang-CUDA.cmake b/Modules/Compiler/Clang-CUDA.cmake
index 219897e4e1..44eb35fc08 100644
--- a/Modules/Compiler/Clang-CUDA.cmake
+++ b/Modules/Compiler/Clang-CUDA.cmake
@@ -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()
diff --git a/Modules/Platform/Apple-Apple-Swift.cmake b/Modules/Platform/Apple-Apple-Swift.cmake
index 7ca3e36e9f..255411ead6 100644
--- a/Modules/Platform/Apple-Apple-Swift.cmake
+++ b/Modules/Platform/Apple-Apple-Swift.cmake
@@ -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)
diff --git a/Modules/Platform/Apple-NVIDIA-CUDA.cmake b/Modules/Platform/Apple-NVIDIA-CUDA.cmake
index 35e759a65c..ba669e1358 100644
--- a/Modules/Platform/Apple-NVIDIA-CUDA.cmake
+++ b/Modules/Platform/Apple-NVIDIA-CUDA.cmake
@@ -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)
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 839dc814ec..d7b615c539 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -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
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 16f20036fc..cf8c9a14c7 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -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));
}
}
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index ccb22bd647..4b7fb1aacc 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -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
{
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 79d637d644..baa54e58a0 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -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;
}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 683968edf9..a4b2ae3e6d 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -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;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 7a8bbcdb84..b752c41b44 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -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);
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 652ea5c153..3673ac9045 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -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}
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
index 9ebbdb7000..9582e11f8a 100644
--- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
@@ -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()
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake
new file mode 100644
index 0000000000..e9a93e9fc9
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake
@@ -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>")
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h
new file mode 100644
index 0000000000..b3fb084c18
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.h
@@ -0,0 +1,9 @@
+#import <Foundation/Foundation.h>
+
+@interface Foo : NSObject {
+ NSNumber* age;
+}
+
+@property (nonatomic, retain) NSNumber* age;
+
+@end
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm
new file mode 100644
index 0000000000..2d452a8e50
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/foo.mm
@@ -0,0 +1,7 @@
+#import "foo.h"
+
+@implementation Foo
+
+@synthesize age;
+
+@end
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm
new file mode 100644
index 0000000000..7c85551f0a
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main.mm
@@ -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;
+}