Merge topic '16432-static-frameworks'

071f8e78 Apple: Add support for static frameworks
d525754e Xcode: Refactor RunCMake.Framework test to prepare for static frameworks
45405f00 Xcode: Ignore Xcode project warning until issue is fixed
50e1c105 Makefile: For static libraries remove only the "real" lib before creating
8643ca75 Makefile: Re-order list of files to clean
This commit is contained in:
Brad King 2017-01-31 09:04:16 -05:00 committed by CMake Topic Stage
commit f012a95836
17 changed files with 205 additions and 103 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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"));
}

View File

@ -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";

View File

@ -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: {

View File

@ -597,12 +597,26 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Clean files associated with this library.
std::vector<std::string> libCleanFiles;
libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
if (targetNameReal != targetName) {
libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal));
std::vector<std::string> commands1;
// Add a command to remove any existing files for this library.
// for static libs only
if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
this->GeneratorTarget, "target");
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
}
if (targetNameSO != targetName && targetNameSO != targetNameReal) {
if (targetName != targetNameReal) {
libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath));
}
if (targetNameSO != targetNameReal && targetNameSO != targetName) {
libCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO));
}
@ -634,19 +648,6 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
}
#endif
std::vector<std::string> commands1;
// Add a command to remove any existing files for this library.
// for static libs only
if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
this->GeneratorTarget, "target");
this->LocalGenerator->CreateCDCommand(
commands1, this->Makefile->GetCurrentBinaryDirectory(),
this->LocalGenerator->GetBinaryDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
}
// Add the pre-build and pre-link rules building but not when relinking.
if (!relink) {
this->LocalGenerator->AppendCustomCommands(

View File

@ -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"));
}

View File

@ -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)

View File

@ -276,8 +276,7 @@ if(XCODE_VERSION AND NOT "${XCODE_VERSION}" VERSION_LESS 3)
add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION})
endif()
if(NOT XCODE
AND CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
add_RunCMake_test(Framework)
endif()

View File

@ -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>)

View File

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

View File

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

View File

@ -1,33 +1,40 @@
include(RunCMake)
# iOS
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}")
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/iOSFrameworkLayout-build)
set(RunCMake_TEST_NO_CLEAN 1)
set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/ios.cmake")
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(FrameworkLayout)
run_cmake_command(${Name} ${CMAKE_COMMAND} --build .)
endfunction()
run_cmake(FrameworkLayout)
run_cmake_command(iOSFrameworkLayout-build ${CMAKE_COMMAND} --build .)
# build check cannot cope with multi-configuration generators directory layout
if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
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()
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
unset(RunCMake_TEST_OPTIONS)
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}")
# OSX
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/OSXFrameworkLayout-build)
set(RunCMake_TEST_NO_CLEAN 1)
set(RunCMake_TEST_OPTIONS "-DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/osx.cmake")
run_cmake(FrameworkLayout)
run_cmake_command(FrameworkType${Type}-build ${CMAKE_COMMAND} --build .)
endfunction()
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(FrameworkLayout)
run_cmake_command(OSXFrameworkLayout-build ${CMAKE_COMMAND} --build .)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
unset(RunCMake_TEST_OPTIONS)
framework_type_test(ios SHARED)
framework_type_test(ios STATIC)
framework_type_test(osx SHARED)
framework_type_test(osx STATIC)

View File

@ -101,7 +101,7 @@ function(run_cmake test)
endif()
foreach(o out err)
string(REGEX REPLACE "\r\n" "\n" actual_std${o} "${actual_std${o}}")
string(REGEX REPLACE "(^|\n)((==[0-9]+==|BullseyeCoverage|[a-z]+\\([0-9]+\\) malloc:|Error kstat returned|[^\n]*from Time Machine by path|[^\n]*Bullseye Testing Technology)[^\n]*\n)+" "\\1" actual_std${o} "${actual_std${o}}")
string(REGEX REPLACE "(^|\n)((==[0-9]+==|BullseyeCoverage|[a-z]+\\([0-9]+\\) malloc:|Error kstat returned|[^\n]*is a member of multiple groups|[^\n]*from Time Machine by path|[^\n]*Bullseye Testing Technology)[^\n]*\n)+" "\\1" actual_std${o} "${actual_std${o}}")
string(REGEX REPLACE "\n+$" "" actual_std${o} "${actual_std${o}}")
set(expect_${o} "")
if(DEFINED expect_std${o})

View File

@ -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