summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/release/dev/genex-LINK_LIBRARY-FRAMEWORK-supports-suffix.rst5
-rw-r--r--Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt9
-rw-r--r--Source/cmComputeLinkInformation.cxx48
-rw-r--r--Source/cmGlobalGenerator.cxx19
-rw-r--r--Source/cmGlobalGenerator.h57
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx36
-rw-r--r--Tests/RunCMake/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake30
9 files changed, 160 insertions, 56 deletions
diff --git a/Help/release/dev/genex-LINK_LIBRARY-FRAMEWORK-supports-suffix.rst b/Help/release/dev/genex-LINK_LIBRARY-FRAMEWORK-supports-suffix.rst
new file mode 100644
index 0000000..e4d82ee
--- /dev/null
+++ b/Help/release/dev/genex-LINK_LIBRARY-FRAMEWORK-supports-suffix.rst
@@ -0,0 +1,5 @@
+genex-LINK_LIBRARY-FRAMEWORK-supports-suffix
+--------------------------------------------
+
+The :genex:`$<LINK_LIBRARY>` generator expression gains the capability, for the
+``FRAMEWORK`` features, to handle the suffix of the framework library name.
diff --git a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
index 8ae6c57..aea1be8 100644
--- a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
+++ b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
@@ -45,8 +45,8 @@
wildcard, and optional parts are shown as ``[...]``):
* ``[/path/to/]FwName[.framework]``
- * ``[/path/to/]FwName.framework/FwName``
- * ``[/path/to/]FwName.framework/Versions/*/FwName``
+ * ``[/path/to/]FwName.framework/FwName[suffix]``
+ * ``[/path/to/]FwName.framework/Versions/*/FwName[suffix]``
Note that CMake recognizes and automatically handles framework targets,
even without using the ``$<LINK_LIBRARY:FRAMEWORK,...>`` expression.
@@ -59,6 +59,11 @@
``$<LINK_LIBRARY:FRAMEWORK,...>`` for file paths so that the expected
behavior is clear.
+ .. versionadded:: 3.25
+ The :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` target property as
+ well as the ``suffix`` of the framework library name are now supported by
+ the ``FRAMEWORK`` features.
+
``NEEDED_FRAMEWORK``
This is similar to the ``FRAMEWORK`` feature, except it forces the linker
to link with the framework even if no symbols are used from it. It uses
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index cda70fc..044f69f 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -1566,8 +1566,9 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
if (target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) {
// Add the framework directory and the framework item itself
- auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item.Value, true);
- if (!fwItems) {
+ auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
+ item.Value, cmGlobalGenerator::FrameworkFormat::Extended);
+ if (!fwDescriptor) {
this->CMakeInstance->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Could not parse framework path \"", item.Value,
@@ -1575,12 +1576,13 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
item.Backtrace);
return;
}
- if (!fwItems->first.empty()) {
+ if (!fwDescriptor->Directory.empty()) {
// Add the directory portion to the framework search path.
- this->AddFrameworkPath(fwItems->first);
+ this->AddFrameworkPath(fwDescriptor->Directory);
}
if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
- this->Items.emplace_back(fwItems->second, ItemIsPath::Yes, target,
+ this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
+ target,
this->FindLibraryFeature(entry.Feature));
} else {
this->Items.emplace_back(
@@ -1851,9 +1853,11 @@ 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, entry.Feature != DEFAULT);
- if (!fwItems) {
+ auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
+ item,
+ entry.Feature == DEFAULT ? cmGlobalGenerator::FrameworkFormat::Relaxed
+ : cmGlobalGenerator::FrameworkFormat::Extended);
+ if (!fwDescriptor) {
std::ostringstream e;
e << "Could not parse framework path \"" << item << "\" "
<< "linked by target " << this->Target->GetName() << ".";
@@ -1861,18 +1865,14 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
return;
}
- std::string fw_path = std::move(fwItems->first);
- std::string fw = std::move(fwItems->second);
- std::string full_fw = cmStrCat(fw, ".framework/", fw);
-
+ const std::string& fw_path = fwDescriptor->Directory;
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);
+ this->AddLibraryRuntimeInfo(fwDescriptor->GetFullPath());
if (entry.Feature == DEFAULT) {
// ensure FRAMEWORK feature is loaded
@@ -1887,9 +1887,9 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
? "FRAMEWORK"
: entry.Feature));
} else {
- this->Items.emplace_back(fw, ItemIsPath::Yes, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "FRAMEWORK"
+ this->Items.emplace_back(
+ fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr,
+ this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK"
: entry.Feature));
}
}
@@ -2252,15 +2252,11 @@ void cmComputeLinkInformation::AddLibraryRuntimeInfo(
// It could be an Apple framework
if (!is_shared_library) {
- if (fullPath.find(".framework") != std::string::npos) {
- static cmsys::RegularExpression splitFramework(
- "^(.*)/(.*).framework/(.*)$");
- if (splitFramework.find(fullPath) &&
- (std::string::npos !=
- splitFramework.match(3).find(splitFramework.match(2)))) {
- is_shared_library = true;
- }
- }
+ is_shared_library =
+ this->GlobalGenerator
+ ->SplitFrameworkPath(fullPath,
+ cmGlobalGenerator::FrameworkFormat::Strict)
+ .has_value();
}
if (!is_shared_library) {
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 8130521..6962b52 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -2563,9 +2563,9 @@ bool cmGlobalGenerator::NameResolvesToFramework(
// 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>>
+cm::optional<cmGlobalGenerator::FrameworkDescriptor>
cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
- bool extendedFormat) const
+ FrameworkFormat format) const
{
// Check for framework structure:
// (/path/to/)?FwName.framework
@@ -2580,20 +2580,29 @@ cmGlobalGenerator::SplitFrameworkPath(const std::string& path,
auto name = frameworkPath.match(3);
auto libname =
cmSystemTools::GetFilenameWithoutExtension(frameworkPath.match(6));
+ if (format == FrameworkFormat::Strict && libname.empty()) {
+ return cm::nullopt;
+ }
if (!libname.empty() && !cmHasPrefix(libname, name)) {
return cm::nullopt;
}
- return std::pair<std::string, std::string>{ frameworkPath.match(2), name };
+
+ if (libname.empty() || name.size() == libname.size()) {
+ return FrameworkDescriptor{ frameworkPath.match(2), name };
+ }
+
+ return FrameworkDescriptor{ frameworkPath.match(2), name,
+ libname.substr(name.size()) };
}
- if (extendedFormat) {
+ if (format == FrameworkFormat::Extended) {
// 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 FrameworkDescriptor{ fwDir, name };
}
return cm::nullopt;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 6e3072b..89b2ea8 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -17,6 +17,7 @@
#include <cm/optional>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cm_codecvt.hxx"
@@ -367,13 +368,61 @@ 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
+ /** Split a framework path to the directory and name of the framework as well
+ * as optiona; suffix.
+ * 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;
+ struct FrameworkDescriptor
+ {
+ FrameworkDescriptor(std::string directory, std::string name)
+ : Directory(std::move(directory))
+ , Name(std::move(name))
+ {
+ }
+ FrameworkDescriptor(std::string directory, std::string name,
+ std::string suffix)
+ : Directory(std::move(directory))
+ , Name(std::move(name))
+ , Suffix(std::move(suffix))
+ {
+ }
+ std::string GetLinkName() const
+ {
+ return this->Suffix.empty() ? this->Name
+ : cmStrCat(this->Name, ',', this->Suffix);
+ }
+ std::string GetFullName() const
+ {
+ return cmStrCat(this->Name, ".framework/"_s, this->Name, this->Suffix);
+ }
+ std::string GetFrameworkPath() const
+ {
+ return this->Directory.empty()
+ ? cmStrCat(this->Name, ".framework"_s)
+ : cmStrCat(this->Directory, '/', this->Name, ".framework"_s);
+ }
+ std::string GetFullPath() const
+ {
+ return this->Directory.empty()
+ ? this->GetFullName()
+ : cmStrCat(this->Directory, '/', this->GetFullName());
+ }
+
+ const std::string Directory;
+ const std::string Name;
+ const std::string Suffix;
+ };
+ enum class FrameworkFormat
+ {
+ Strict,
+ Relaxed,
+ Extended
+ };
+ cm::optional<FrameworkDescriptor> SplitFrameworkPath(
+ const std::string& path,
+ FrameworkFormat format = FrameworkFormat::Relaxed) 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 2c455cf..9739a4e 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1192,13 +1192,9 @@ std::string GetTargetObjectDirArch(T const& target,
std::string cmGlobalXCodeGenerator::GetLibraryOrFrameworkPath(
const std::string& path) const
{
- auto fwItems = this->SplitFrameworkPath(path);
- if (fwItems) {
- if (fwItems->first.empty()) {
- return cmStrCat(fwItems->second, ".framework");
- } else {
- return cmStrCat(fwItems->first, '/', fwItems->second, ".framework");
- }
+ auto fwDescriptor = this->SplitFrameworkPath(path);
+ if (fwDescriptor) {
+ return fwDescriptor->GetFrameworkPath();
}
return path;
@@ -3641,9 +3637,10 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
linkDir = libItem->Value.Value;
}
if (cmHasSuffix(libItem->GetFeatureName(), "FRAMEWORK"_s)) {
- auto fwItems = this->SplitFrameworkPath(linkDir, true);
- if (fwItems && !fwItems->first.empty()) {
- linkDir = std::move(fwItems->first);
+ auto fwDescriptor = this->SplitFrameworkPath(
+ linkDir, cmGlobalGenerator::FrameworkFormat::Extended);
+ if (fwDescriptor && !fwDescriptor->Directory.empty()) {
+ linkDir = fwDescriptor->Directory;
if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(),
linkDir) == frameworkSearchPaths.end()) {
frameworkSearchPaths.push_back(linkDir);
@@ -3839,13 +3836,14 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
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) {
+ const auto fwDescriptor = this->SplitFrameworkPath(
+ cleanPath, cmGlobalGenerator::FrameworkFormat::Extended);
+ if (!fwDescriptor->Directory.empty() &&
+ emitted.insert(fwDescriptor->Directory).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("-F " +
+ this->XCodeEscapePath(fwDescriptor->Directory));
}
if (libName.GetFeatureName() == "__CMAKE_LINK_FRAMEWORK"_s) {
// use the full path
@@ -3853,10 +3851,10 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
libName.GetFormattedItem(this->XCodeEscapePath(cleanPath))
.Value);
} else {
- libPaths.Add(
- libName
- .GetFormattedItem(this->XCodeEscapePath(fwItems->second))
- .Value);
+ libPaths.Add(libName
+ .GetFormattedItem(this->XCodeEscapePath(
+ fwDescriptor->GetLinkName()))
+ .Value);
}
} else {
libPaths.Add(
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index db4200b..d802e1f 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -697,6 +697,8 @@ add_RunCMake_test(target_link_libraries-LINK_LIBRARY -DCMAKE_SYSTEM_NAME=${CMAKE
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
-DMSVC_VERSION=${MSVC_VERSION}
+ -DXCODE=${XCODE}
+ -DXCODE_VERSION=${XCODE_VERSION}
-DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX}
-DCMAKE_SHARED_LIBRARY_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX}
-DCMAKE_IMPORT_LIBRARY_PREFIX=${CMAKE_IMPORT_LIBRARY_PREFIX}
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
index 021de41..9b6581c 100644
--- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
@@ -90,12 +90,22 @@ if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES
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)
+
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG AND (NOT XCODE OR XCODE_VERSION GREATER_EQUAL 13))
+ run_cmake_target(apple_framework target-framework-postfix main-target-framework-postfix)
+ run_cmake_target(apple_framework target-reexport_framework-postfix main-target-reexport_framework-postfix)
+ run_cmake_target(apple_framework target-weak_framework-postfix main-target-weak_framework-postfix)
+ endif()
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)
+
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG AND (NOT XCODE OR XCODE_VERSION GREATER_EQUAL 13))
+ run_cmake_target(apple_framework target-needed_framework-postfix main-target-needed_framework-postfix)
+ endif()
endif()
# Apple library features
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake
index e9a93e9..ca0e72d 100644
--- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/apple_framework.cmake
@@ -59,3 +59,33 @@ target_link_libraries(main-target-reexport_framework PRIVATE "$<LINK_LIBRARY:FRA
# 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>")
+
+
+
+get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(IS_MULTI_CONFIG)
+ add_library(target-framework-postfix SHARED foo.mm)
+ set_target_properties(target-framework-postfix PROPERTIES FRAMEWORK TRUE
+ FRAMEWORK_MULTI_CONFIG_POSTFIX_RELEASE "_release")
+ target_link_libraries(target-framework-postfix PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>")
+
+
+ # feature FRAMEWORK
+ add_executable(main-target-framework-postfix main.mm)
+ target_link_libraries(main-target-framework-postfix PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:FRAMEWORK,target-framework-postfix>")
+
+
+ # feature NEEDED_FRAMEWORK
+ add_executable(main-target-needed_framework-postfix main.mm)
+ target_link_libraries(main-target-needed_framework-postfix PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:NEEDED_FRAMEWORK,target-framework-postfix>")
+
+
+ # feature REEXPORT_FRAMEWORK
+ add_executable(main-target-reexport_framework-postfix main.mm)
+ target_link_libraries(main-target-reexport_framework-postfix PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,target-framework-postfix>")
+
+
+ # feature WEAK_FRAMEWORK
+ add_executable(main-target-weak_framework-postfix main.mm)
+ target_link_libraries(main-target-weak_framework-postfix PRIVATE "$<LINK_LIBRARY:FRAMEWORK,Foundation>" "$<LINK_LIBRARY:REEXPORT_FRAMEWORK,target-framework-postfix>")
+endif()