Browse Source

macOS: Allow IMPORTED_LOCATION to be a framework folder

Issue: #24946
Kyle Edwards 2 years ago
parent
commit
d605f728f7

+ 5 - 0
Help/prop_tgt/IMPORTED_LOCATION.rst

@@ -15,6 +15,11 @@ is the location of the ``.dll`` part of the library.  For ``UNKNOWN``
 libraries this is the location of the file to be linked.  Ignored for
 non-imported targets.
 
+.. versionadded:: 3.28
+
+  For frameworks on macOS, this may be the location of the framework folder
+  itself.
+
 The ``IMPORTED_LOCATION`` target property may be overridden for a
 given configuration ``<CONFIG>`` by the configuration-specific
 :prop_tgt:`IMPORTED_LOCATION_<CONFIG>` target property.  Furthermore,

+ 5 - 0
Help/release/dev/imported-target-framework-path.rst

@@ -0,0 +1,5 @@
+imported-target-framework-path
+------------------------------
+
+* The :prop_tgt:`IMPORTED_LOCATION` property of a macOS framework may now be
+  the location of the framework folder itself.

+ 25 - 6
Source/cmComputeLinkInformation.cxx

@@ -1579,7 +1579,9 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
     this->OldLinkDirItems.push_back(item.Value);
   }
 
-  if (target->IsFrameworkOnApple()) {
+  const bool isImportedFrameworkFolderOnApple =
+    target->IsImportedFrameworkFolderOnApple(this->Config);
+  if (target->IsFrameworkOnApple() || isImportedFrameworkFolderOnApple) {
     // Add the framework directory and the framework item itself
     auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
       item.Value, cmGlobalGenerator::FrameworkFormat::Extended);
@@ -1597,16 +1599,33 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
     }
 
     if (this->GlobalGenerator->IsXcode()) {
-      this->Items.emplace_back(
-        item, ItemIsPath::Yes, target,
-        this->FindLibraryFeature(entry.Feature == DEFAULT
-                                   ? "__CMAKE_LINK_FRAMEWORK"
-                                   : entry.Feature));
+      if (isImportedFrameworkFolderOnApple) {
+        if (entry.Feature == DEFAULT) {
+          this->AddLibraryFeature("FRAMEWORK");
+          this->Items.emplace_back(item, ItemIsPath::Yes, target,
+                                   this->FindLibraryFeature("FRAMEWORK"));
+        } else {
+          this->Items.emplace_back(item, ItemIsPath::Yes, target,
+                                   this->FindLibraryFeature(entry.Feature));
+        }
+      } else {
+        this->Items.emplace_back(
+          item, ItemIsPath::Yes, target,
+          this->FindLibraryFeature(entry.Feature == DEFAULT
+                                     ? "__CMAKE_LINK_FRAMEWORK"
+                                     : entry.Feature));
+      }
     } else {
       if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
         this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
                                  target,
                                  this->FindLibraryFeature(entry.Feature));
+      } else if (entry.Feature == DEFAULT &&
+                 isImportedFrameworkFolderOnApple) {
+        this->AddLibraryFeature("FRAMEWORK");
+        this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
+                                 target,
+                                 this->FindLibraryFeature("FRAMEWORK"));
       } else {
         this->Items.emplace_back(
           item, ItemIsPath::Yes, target,

+ 12 - 1
Source/cmGeneratorTarget.cxx

@@ -3828,7 +3828,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
         if (lib.Target == nullptr) {
           libDir = cmSystemTools::CollapseFullPath(
             lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
-        } else if (lib.Target->Target->IsFrameworkOnApple()) {
+        } else if (lib.Target->Target->IsFrameworkOnApple() ||
+                   this->IsImportedFrameworkFolderOnApple(config)) {
           libDir = lib.Target->GetLocation(config);
         } else {
           continue;
@@ -8572,6 +8573,16 @@ bool cmGeneratorTarget::IsFrameworkOnApple() const
   return this->Target->IsFrameworkOnApple();
 }
 
+bool cmGeneratorTarget::IsImportedFrameworkFolderOnApple(
+  const std::string& config) const
+{
+  return this->IsApple() && this->IsImported() &&
+    (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+     this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+     this->GetType() == cmStateEnums::UNKNOWN_LIBRARY) &&
+    cmSystemTools::IsPathToFramework(this->GetLocation(config));
+}
+
 bool cmGeneratorTarget::IsAppBundleOnApple() const
 {
   return this->Target->IsAppBundleOnApple();

+ 4 - 0
Source/cmGeneratorTarget.h

@@ -812,6 +812,10 @@ public:
       Apple.  */
   bool IsFrameworkOnApple() const;
 
+  /** Return whether this target is an IMPORTED library target on Apple
+      with a .framework folder as its location.  */
+  bool IsImportedFrameworkFolderOnApple(const std::string& config) const;
+
   /** Return whether this target is an executable Bundle on Apple.  */
   bool IsAppBundleOnApple() const;
 

+ 3 - 16
Tests/RunCMake/CMP0111/CMP0111-NEW-stderr.txt

@@ -1,17 +1,4 @@
-^CMake Error in CMakeLists.txt:
-  IMPORTED_LOCATION not set for imported target "unknown_lib"( configuration
-  "[^"]+")?.
-+
-CMake Error in CMakeLists.txt:
-  IMPORTED_LOCATION not set for imported target "static_lib"( configuration
-  "[^"]+")?.
-+
-CMake Error in CMakeLists.txt:
-  IMPORTED_IMPLIB not set for imported target "shared_lib"( configuration
-  "[^"]+")?.(
-+
-CMake Error in CMakeLists.txt:
+^(CMake Error in CMakeLists.txt:
   IMPORTED_(LOCATION|IMPLIB) not set for imported target "(unknown|static|shared)_lib"( configuration
-  "[^"]+")?.)*
-+
-CMake Generate step failed.  Build files cannot be regenerated correctly.$
+  "[^"]+")?.
++)+CMake Generate step failed.  Build files cannot be regenerated correctly.$

+ 4 - 25
Tests/RunCMake/CMP0111/CMP0111-WARN-stderr.txt

@@ -1,34 +1,13 @@
-^CMake Warning \(dev\) in CMakeLists.txt:
+^(CMake Warning \(dev\) in CMakeLists.txt:
   Policy CMP0111 is not set: An imported target missing its location property
   fails during generation.  Run "cmake --help-policy CMP0111" for policy
   details.  Use the cmake_policy command to set the policy and suppress this
   warning.
 
-  IMPORTED_LOCATION not set for imported target "unknown_lib"( configuration
-  "[^"]+")?.
-This warning is for project developers.  Use -Wno-dev to suppress it.
-+
-CMake Warning \(dev\) in CMakeLists.txt:
-  Policy CMP0111 is not set: An imported target missing its location property
-  fails during generation.  Run "cmake --help-policy CMP0111" for policy
-  details.  Use the cmake_policy command to set the policy and suppress this
-  warning.
-
-  IMPORTED_LOCATION not set for imported target "static_lib"( configuration
+  IMPORTED_(LOCATION|IMPLIB) not set for imported target "(unknown|static|shared)_lib"( configuration
   "[^"]+")?.
 This warning is for project developers.  Use -Wno-dev to suppress it.
-+
-CMake Warning \(dev\) in CMakeLists.txt:
-  Policy CMP0111 is not set: An imported target missing its location property
-  fails during generation.  Run "cmake --help-policy CMP0111" for policy
-  details.  Use the cmake_policy command to set the policy and suppress this
-  warning.
-
-  IMPORTED_IMPLIB not set for imported target "shared_lib"( configuration
-  "[^"]+")?.
-This warning is for project developers.  Use -Wno-dev to suppress it.(
-+
-CMake Warning \(dev\) in CMakeLists.txt:
++)+CMake Warning \(dev\) in CMakeLists.txt:
   Policy CMP0111 is not set: An imported target missing its location property
   fails during generation.  Run "cmake --help-policy CMP0111" for policy
   details.  Use the cmake_policy command to set the policy and suppress this
@@ -36,4 +15,4 @@ CMake Warning \(dev\) in CMakeLists.txt:
 
   IMPORTED_(LOCATION|IMPLIB) not set for imported target "(unknown|static|shared)_lib"( configuration
   "[^"]+")?.
-This warning is for project developers.  Use -Wno-dev to suppress it.)*$
+This warning is for project developers.  Use -Wno-dev to suppress it.$

+ 4 - 0
Tests/RunCMake/Framework/FrameworkConsumption.cmake

@@ -1,5 +1,7 @@
 enable_language(C)
 
+set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
+
 # Create framework and ensure header is placed in Headers
 set(input_header "${CMAKE_SOURCE_DIR}/Gui.h")
 add_library(Gui SHARED Gui.c "${input_header}")
@@ -8,6 +10,8 @@ set_target_properties(Gui PROPERTIES
     FRAMEWORK TRUE
 )
 
+install(TARGETS Gui DESTINATION .)
+
 add_executable(app main.c)
 
 target_link_libraries(app PRIVATE Gui)

+ 7 - 0
Tests/RunCMake/Framework/ImportedFrameworkConsumption.cmake

@@ -0,0 +1,7 @@
+enable_language(C)
+
+add_library(Gui IMPORTED UNKNOWN)
+set_property(TARGET Gui PROPERTY IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/../FrameworkConsumption-build/install/Gui.framework")
+
+add_executable(app main.c)
+target_link_libraries(app PRIVATE Gui)

+ 10 - 1
Tests/RunCMake/Framework/RunCMakeTest.cmake

@@ -113,7 +113,16 @@ function(framework_consumption)
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
   run_cmake(FrameworkConsumption)
-  run_cmake_command(FrameworkConsumption-build ${CMAKE_COMMAND} --build .)
+  run_cmake_command(FrameworkConsumption-build ${CMAKE_COMMAND} --build . --config Release)
+  run_cmake_command(FrameworkConsumption-install ${CMAKE_COMMAND} --install . --config Release)
+
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/ImportedFrameworkConsumption-build")
+  set(RunCMake_TEST_NO_CLEAN 1)
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  run_cmake(ImportedFrameworkConsumption)
+  run_cmake_command(ImportedFrameworkConsumption-build ${CMAKE_COMMAND} --build . --config Release)
 endfunction()
 
 framework_consumption()