Procházet zdrojové kódy

Apple: Add support for static frameworks

Closes: #16432
Gregor Jasny před 8 roky
rodič
revize
071f8e78dd

+ 1 - 1
Help/command/add_library.rst

@@ -33,7 +33,7 @@ type is ``STATIC`` or ``SHARED`` based on whether the current value of the
 variable :variable:`BUILD_SHARED_LIBS` is ``ON``.  For ``SHARED`` and
 ``MODULE`` libraries the :prop_tgt:`POSITION_INDEPENDENT_CODE` target
 property is set to ``ON`` automatically.
-A ``SHARED`` library may be marked with the :prop_tgt:`FRAMEWORK`
+A ``SHARED`` or ``STATIC`` library may be marked with the :prop_tgt:`FRAMEWORK`
 target property to create an OS X Framework.
 
 If a library does not export any symbols, it must not be declared as a

+ 4 - 2
Help/command/install.rst

@@ -90,8 +90,10 @@ project.  There are five kinds of target files that may be installed:
 ``ARCHIVE``, ``LIBRARY``, ``RUNTIME``, ``FRAMEWORK``, and ``BUNDLE``.
 Executables are treated as ``RUNTIME`` targets, except that those
 marked with the ``MACOSX_BUNDLE`` property are treated as ``BUNDLE``
-targets on OS X.  Static libraries are always treated as ``ARCHIVE``
-targets.  Module libraries are always treated as ``LIBRARY`` targets.
+targets on OS X.  Static libraries are treated as ``ARCHIVE`` targets,
+except that those marked with the ``FRAMEWORK`` property are treated
+as ``FRAMEWORK`` targets on OS X.
+Module libraries are always treated as ``LIBRARY`` targets.
 For non-DLL platforms shared libraries are treated as ``LIBRARY``
 targets, except that those marked with the ``FRAMEWORK`` property are
 treated as ``FRAMEWORK`` targets on OS X.  For DLL platforms the DLL

+ 2 - 2
Help/prop_tgt/FRAMEWORK.rst

@@ -1,9 +1,9 @@
 FRAMEWORK
 ---------
 
-Build ``SHARED`` library as Framework Bundle on the OS X and iOS.
+Build ``SHARED`` or ``STATIC`` library as Framework Bundle on the OS X and iOS.
 
-If a ``SHARED`` library target has this property set to ``TRUE`` it will be
+If such a library target has this property set to ``TRUE`` it will be
 built as a framework when built on the OS X and iOS.  It will have the
 directory structure required for a framework and will be suitable to
 be used with the ``-framework`` option

+ 6 - 0
Help/release/dev/static-frameworks.rst

@@ -0,0 +1,6 @@
+static-frameworks
+-----------------
+
+* The :prop_tgt:`FRAMEWORK` property could now also be applied to
+  static libraries on Apple targets.  It will result in a proper
+  Framework but with a static library inside.

+ 2 - 1
Source/cmGeneratorTarget.cxx

@@ -5308,7 +5308,8 @@ bool cmGeneratorTarget::IsLinkable() const
 
 bool cmGeneratorTarget::IsFrameworkOnApple() const
 {
-  return (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
+  return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+           this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
           this->Makefile->IsOn("APPLE") &&
           this->GetPropertyAsBool("FRAMEWORK"));
 }

+ 35 - 4
Source/cmGlobalXCodeGenerator.cxx

@@ -1816,8 +1816,34 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
 
   // Handle settings for each target type.
   switch (gtgt->GetType()) {
-    case cmStateEnums::OBJECT_LIBRARY:
-    case cmStateEnums::STATIC_LIBRARY: {
+    case cmStateEnums::STATIC_LIBRARY:
+      if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
+        std::string fw_version = gtgt->GetFrameworkVersion();
+        buildSettings->AddAttribute("FRAMEWORK_VERSION",
+                                    this->CreateString(fw_version));
+        const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION");
+        if (ext) {
+          buildSettings->AddAttribute("WRAPPER_EXTENSION",
+                                      this->CreateString(ext));
+        }
+
+        std::string plist = this->ComputeInfoPListLocation(gtgt);
+        // Xcode will create the final version of Info.plist at build time,
+        // so let it replace the framework name. This avoids creating
+        // a per-configuration Info.plist file.
+        this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
+          gtgt, "$(EXECUTABLE_NAME)", plist.c_str());
+        buildSettings->AddAttribute("INFOPLIST_FILE",
+                                    this->CreateString(plist));
+        buildSettings->AddAttribute("MACH_O_TYPE",
+                                    this->CreateString("staticlib"));
+      } else {
+        buildSettings->AddAttribute("LIBRARY_STYLE",
+                                    this->CreateString("STATIC"));
+      }
+      break;
+
+    case cmStateEnums::OBJECT_LIBRARY: {
       buildSettings->AddAttribute("LIBRARY_STYLE",
                                   this->CreateString("STATIC"));
       break;
@@ -2336,8 +2362,10 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType(
 
   switch (target->GetType()) {
     case cmStateEnums::OBJECT_LIBRARY:
-    case cmStateEnums::STATIC_LIBRARY:
       return "archive.ar";
+    case cmStateEnums::STATIC_LIBRARY:
+      return (target->GetPropertyAsBool("FRAMEWORK") ? "wrapper.framework"
+                                                     : "archive.ar");
     case cmStateEnums::MODULE_LIBRARY:
       if (target->IsXCTestOnApple())
         return "wrapper.cfbundle";
@@ -2367,8 +2395,11 @@ const char* cmGlobalXCodeGenerator::GetTargetProductType(
 
   switch (target->GetType()) {
     case cmStateEnums::OBJECT_LIBRARY:
-    case cmStateEnums::STATIC_LIBRARY:
       return "com.apple.product-type.library.static";
+    case cmStateEnums::STATIC_LIBRARY:
+      return (target->GetPropertyAsBool("FRAMEWORK")
+                ? "com.apple.product-type.framework"
+                : "com.apple.product-type.library.static");
     case cmStateEnums::MODULE_LIBRARY:
       if (target->IsXCTestOnApple())
         return "com.apple.product-type.bundle.unit-test";

+ 32 - 10
Source/cmInstallCommand.cxx

@@ -471,17 +471,39 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
         }
       } break;
       case cmStateEnums::STATIC_LIBRARY: {
-        // Static libraries use ARCHIVE properties.
-        if (!archiveArgs.GetDestination().empty()) {
-          archiveGenerator =
-            CreateInstallTargetGenerator(target, archiveArgs, false);
+        // If it is marked with FRAMEWORK property use the FRAMEWORK set of
+        // INSTALL properties. Otherwise, use the LIBRARY properties.
+        if (target.IsFrameworkOnApple()) {
+          // When in namelink only mode skip frameworks.
+          if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
+            continue;
+          }
+
+          // Use the FRAMEWORK properties.
+          if (!frameworkArgs.GetDestination().empty()) {
+            frameworkGenerator =
+              CreateInstallTargetGenerator(target, frameworkArgs, false);
+          } else {
+            std::ostringstream e;
+            e << "TARGETS given no FRAMEWORK DESTINATION for static library "
+                 "FRAMEWORK target \""
+              << target.GetName() << "\".";
+            this->SetError(e.str());
+            return false;
+          }
         } else {
-          std::ostringstream e;
-          e << "TARGETS given no ARCHIVE DESTINATION for static library "
-               "target \""
-            << target.GetName() << "\".";
-          this->SetError(e.str());
-          return false;
+          // Static libraries use ARCHIVE properties.
+          if (!archiveArgs.GetDestination().empty()) {
+            archiveGenerator =
+              CreateInstallTargetGenerator(target, archiveArgs, false);
+          } else {
+            std::ostringstream e;
+            e << "TARGETS given no ARCHIVE DESTINATION for static library "
+                 "target \""
+              << target.GetName() << "\".";
+            this->SetError(e.str());
+            return false;
+          }
         }
       } break;
       case cmStateEnums::MODULE_LIBRARY: {

+ 2 - 1
Source/cmTarget.cxx

@@ -451,7 +451,8 @@ bool cmTarget::HasImportLibrary() const
 
 bool cmTarget::IsFrameworkOnApple() const
 {
-  return (this->GetType() == cmStateEnums::SHARED_LIBRARY &&
+  return ((this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+           this->GetType() == cmStateEnums::STATIC_LIBRARY) &&
           this->Makefile->IsOn("APPLE") &&
           this->GetPropertyAsBool("FRAMEWORK"));
 }

+ 24 - 23
Tests/Framework/CMakeLists.txt

@@ -57,29 +57,30 @@ add_custom_target(fooCustom ALL COMMAND ${CMAKE_COMMAND} -E copy foo-post-build
 add_dependencies(fooCustom foo)
 
 # Make a static library and apply the framework properties to it to verify
-# that everything still builds correctly, but it will not actually produce
-# a framework... The framework properties only apply when the library type
-# is SHARED.
+# that everything still builds correctly. Xcode prior to version 5 does not
+# support static Frameworks.
 #
-add_library(fooStatic STATIC
-  foo.cxx
-  foo.h
-  foo2.h
-  fooExtensionlessResource
-  fooPublic.h
-  fooPublicExtensionlessHeader
-  fooPrivate.h
-  fooPrivateExtensionlessHeader
-  fooNeither.h
-  fooBoth.h
-  test.lua
-  fooDeepPublic.h
-)
-set_target_properties(fooStatic PROPERTIES
-  FRAMEWORK TRUE
-  FRAMEWORK_VERSION none
-)
-add_executable(barStatic bar.cxx)
-target_link_libraries(barStatic fooStatic)
+if(NOT XCODE OR NOT XCODE_VERSION VERSION_LESS 5)
+  add_library(fooStatic STATIC
+    foo.cxx
+    foo.h
+    foo2.h
+    fooExtensionlessResource
+    fooPublic.h
+    fooPublicExtensionlessHeader
+    fooPrivate.h
+    fooPrivateExtensionlessHeader
+    fooNeither.h
+    fooBoth.h
+    test.lua
+    fooDeepPublic.h
+  )
+  set_target_properties(fooStatic PROPERTIES
+    FRAMEWORK TRUE
+    FRAMEWORK_VERSION none
+  )
+  add_executable(barStatic bar.cxx)
+  target_link_libraries(barStatic fooStatic)
+endif()
 
 include(CPack)

+ 4 - 1
Tests/RunCMake/Framework/FrameworkLayout.cmake

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.4)
 enable_language(C)
 
-add_library(Framework SHARED
+add_library(Framework ${FRAMEWORK_TYPE}
             foo.c
             foo.h
             res.txt)
@@ -9,3 +9,6 @@ set_target_properties(Framework PROPERTIES
                       FRAMEWORK TRUE
                       PUBLIC_HEADER foo.h
                       RESOURCE "res.txt")
+
+add_custom_command(TARGET Framework POST_BUILD
+                   COMMAND /usr/bin/file $<TARGET_FILE:Framework>)

+ 1 - 0
Tests/RunCMake/Framework/FrameworkTypeSHARED-build-stdout.txt

@@ -0,0 +1 @@
+.*/Framework: Mach-O[^\n]* dynamically linked shared library.*

+ 1 - 0
Tests/RunCMake/Framework/FrameworkTypeSTATIC-build-stdout.txt

@@ -0,0 +1 @@
+.*/Framework: current ar archive random library.*

+ 25 - 4
Tests/RunCMake/Framework/RunCMakeTest.cmake

@@ -1,9 +1,10 @@
 include(RunCMake)
 
-function(framework_layout_test Name Toolchain)
-  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${Toolchain}FrameworkLayout-build)
+function(framework_layout_test Name Toolchain Type)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${Toolchain}${Type}FrameworkLayout-build)
   set(RunCMake_TEST_NO_CLEAN 1)
   set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/${Toolchain}.cmake")
+  list(APPEND RunCMake_TEST_OPTIONS "-DFRAMEWORK_TYPE=${Type}")
 
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
@@ -14,6 +15,26 @@ endfunction()
 
 # build check cannot cope with multi-configuration generators directory layout
 if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
-  framework_layout_test(iOSFrameworkLayout-build ios)
-  framework_layout_test(OSXFrameworkLayout-build osx)
+  framework_layout_test(iOSFrameworkLayout-build ios SHARED)
+  framework_layout_test(iOSFrameworkLayout-build ios STATIC)
+  framework_layout_test(OSXFrameworkLayout-build osx SHARED)
+  framework_layout_test(OSXFrameworkLayout-build osx STATIC)
 endif()
+
+function(framework_type_test Toolchain Type)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${Toolchain}${Type}FrameworkType-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/${Toolchain}.cmake")
+  list(APPEND RunCMake_TEST_OPTIONS "-DFRAMEWORK_TYPE=${Type}")
+
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake(FrameworkLayout)
+  run_cmake_command(FrameworkType${Type}-build ${CMAKE_COMMAND} --build .)
+endfunction()
+
+framework_type_test(ios SHARED)
+framework_type_test(ios STATIC)
+framework_type_test(osx SHARED)
+framework_type_test(osx STATIC)

+ 39 - 13
Tests/RunCMake/XcodeProject/XcodeBundles.cmake

@@ -50,30 +50,56 @@ if (NOT TEST_IOS AND NOT TEST_WATCHOS AND NOT TEST_TVOS)
   add_dependencies(AppBundleExtTest AppBundleExt)
 endif()
 
-# Framework (not supported for iOS on Xcode < 6)
+# Shared Framework (not supported for iOS on Xcode < 6)
 
 if(NOT TEST_IOS OR NOT XCODE_VERSION VERSION_LESS 6)
-  add_library(Framework SHARED main.c)
-  set_target_properties(Framework PROPERTIES FRAMEWORK TRUE)
+  add_library(SharedFramework SHARED main.c)
+  set_target_properties(SharedFramework PROPERTIES FRAMEWORK TRUE)
 
-  add_custom_target(FrameworkTest ALL
+  add_custom_target(SharedFrameworkTest ALL
     COMMAND ${CMAKE_COMMAND} -E copy
-      "$<TARGET_FILE:Framework>" "$<TARGET_FILE:Framework>.old")
+      "$<TARGET_FILE:SharedFramework>" "$<TARGET_FILE:SharedFramework>.old")
 
-  add_dependencies(FrameworkTest Framework)
+  add_dependencies(SharedFrameworkTest SharedFramework)
 
   # with custom extension
 
-  add_library(FrameworkExt SHARED main.c)
-  set_target_properties(FrameworkExt PROPERTIES FRAMEWORK TRUE)
-  set_target_properties(FrameworkExt PROPERTIES BUNDLE_EXTENSION "foo")
-  install(TARGETS FrameworkExt FRAMEWORK DESTINATION FooExtension)
+  add_library(SharedFrameworkExt SHARED main.c)
+  set_target_properties(SharedFrameworkExt PROPERTIES FRAMEWORK TRUE)
+  set_target_properties(SharedFrameworkExt PROPERTIES BUNDLE_EXTENSION "foo")
+  install(TARGETS SharedFrameworkExt FRAMEWORK DESTINATION FooExtension)
 
-  add_custom_target(FrameworkExtTest ALL
+  add_custom_target(SharedFrameworkExtTest ALL
     COMMAND ${CMAKE_COMMAND} -E copy
-      "$<TARGET_FILE:FrameworkExt>" "$<TARGET_FILE:FrameworkExt>.old")
+      "$<TARGET_FILE:SharedFrameworkExt>" "$<TARGET_FILE:SharedFrameworkExt>.old")
 
-  add_dependencies(FrameworkExtTest FrameworkExt)
+  add_dependencies(SharedFrameworkExtTest SharedFrameworkExt)
+endif()
+
+# Static Framework (not supported for Xcode < 6)
+
+if(NOT XCODE_VERSION VERSION_LESS 6)
+  add_library(StaticFramework STATIC main.c)
+  set_target_properties(StaticFramework PROPERTIES FRAMEWORK TRUE)
+
+  add_custom_target(StaticFrameworkTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_FILE:StaticFramework>" "$<TARGET_FILE:StaticFramework>.old")
+
+  add_dependencies(StaticFrameworkTest StaticFramework)
+
+  # with custom extension
+
+  add_library(StaticFrameworkExt STATIC main.c)
+  set_target_properties(StaticFrameworkExt PROPERTIES FRAMEWORK TRUE)
+  set_target_properties(StaticFrameworkExt PROPERTIES BUNDLE_EXTENSION "foo")
+  install(TARGETS StaticFrameworkExt FRAMEWORK DESTINATION StaticFooExtension)
+
+  add_custom_target(StaticFrameworkExtTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_FILE:StaticFrameworkExt>" "$<TARGET_FILE:StaticFrameworkExt>.old")
+
+  add_dependencies(StaticFrameworkExtTest StaticFrameworkExt)
 endif()
 
 # Bundle