Commit 071f8e78 authored by Gregor Jasny's avatar Gregor Jasny Committed by Brad King

Apple: Add support for static frameworks

Closes: #16432
parent d525754e
Pipeline #44927 passed with stage
......@@ -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
......
......@@ -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
......
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
......
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.
......@@ -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"));
}
......
......@@ -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";
......
......@@ -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: {
......
......@@ -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"));
}
......
......@@ -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)
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>)
.*/Framework: Mach-O[^\n]* dynamically linked shared library.*
.*/Framework: current ar archive random library.*
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)
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment