Hi,
Patches help to install universal iOS (device + simulator) libraries by
triggering some extra instructions (build + fuse) after "regular"
library installation finished. This behavior controlled by CMake
variable CMAKE_IOS_INSTALL_UNIVERSAL_LIBS.
= Example =
> cat CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(Foo)
add_library(foo foo.cpp)
install(TARGETS foo DESTINATION lib)
> cat toolchain.cmake
set(CMAKE_MACOSX_BUNDLE YES)
set(CMAKE_OSX_SYSROOT "iphoneos")
set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.example")
> rm -rf _builds _install
> cmake -H. -B_builds -GXcode -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
-DCMAKE_INSTALL_PREFIX=_install ...
= Current functionality =
Device one arch (default):
> cmake ...
> cmake --build _builds --target install
> lipo -info _install/lib/libfoo.a
Non-fat file: _install/lib/libfoo.a is architecture: armv7
Simulator one arch:
> cmake ...
> cmake --build _builds --target install -- -sdk iphonesimulator
> lipo -info _install/lib/libfoo.a
Non-fat file: _install/lib/libfoo.a is architecture: x86_64
Device multi arch:
> cmake ... -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO
> cmake --build _builds --target install
> lipo -info _install/lib/libfoo.a
Architectures in the fat file: _install/lib/libfoo.a are: armv7 arm64
Simulator multi arch:
> cmake ... -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO
> cmake --build _builds --target install -- -sdk iphonesimulator
> lipo -info _install/lib/libfoo.a
Architectures in the fat file: _install/lib/libfoo.a are: i386 x86_64
= This upgrade =
Device + simulator one arch:
> cmake ... -DCMAKE_IOS_INSTALL_UNIVERSAL_LIBS=YES
> cmake --build _builds --target install
> lipo -info _install/lib/libfoo.a
Architectures in the fat file: _install/lib/libfoo.a are: armv7 x86_64
Device + simulator multi arch:
> cmake ... -DCMAKE_IOS_INSTALL_UNIVERSAL_LIBS=YES
-DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO
> cmake --build _builds --target install
> lipo -info _install/lib/libfoo.a
Architectures in the fat file: _install/lib/libfoo.a are: i386 armv7
x86_64 arm64
Let me know if this looks acceptable, then I will add documentation part
and tests.
Thanks, Ruslo
>From 81665dad37f6b102449cd5f36b2ea0a666cf9d68 Mon Sep 17 00:00:00 2001
From: Ruslan Baratov <ruslan_bara...@yahoo.com>
Date: Thu, 24 Sep 2015 11:45:44 +0300
Subject: [PATCH 1/3] Get target name for universal iOS library install
Add method GetTargetNameForUniversalIosInstall to cmInstallTargetGenerator.
This method will return target name if:
* Platform is iOS
* Target is library
* CMake variable CMAKE_IOS_INSTALL_UNIVERSAL_LIBS is ON
Otherwise an empty string will be returned.
---
Source/cmInstallTargetGenerator.cxx | 29 +++++++++++++++++++++++++++++
Source/cmInstallTargetGenerator.h | 5 +++++
2 files changed, 34 insertions(+)
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 30cf175..db0ed6e 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -869,3 +869,32 @@ cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
os << indent << "execute_process(COMMAND \""
<< ranlib << "\" \"" << toDestDirPath << "\")\n";
}
+
+std::string
+cmInstallTargetGenerator
+::GetTargetNameForUniversalIosInstall(cmInstallType type) const
+{
+ if(!this->Target->Target->GetMakefile()->PlatformIsAppleIos())
+ {
+ return "";
+ }
+
+ switch(type)
+ {
+ case cmInstallType_STATIC_LIBRARY:
+ case cmInstallType_SHARED_LIBRARY:
+ case cmInstallType_MODULE_LIBRARY:
+ break;
+ default:
+ return "";
+ }
+
+ const char* var = "CMAKE_IOS_INSTALL_UNIVERSAL_LIBS";
+ const char* flag = this->Target->Target->GetMakefile()->GetDefinition(var);
+ if (cmSystemTools::IsOff(flag))
+ {
+ return "";
+ }
+
+ return this->Target->GetName();
+}
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index a8f4a75..6335e31 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -109,6 +109,11 @@ protected:
NamelinkModeType NamelinkMode;
bool ImportLibrary;
bool Optional;
+
+ private:
+ /** Get target name for installing universal iOS library. If target is not
+ an iOS library or universal build is disabled return empty string. */
+ std::string GetTargetNameForUniversalIosInstall(cmInstallType type) const;
};
#endif
--
1.9.3 (Apple Git-50)
>From 89e8b5aebb1fd8709f3a2bcff5ac77dc3e545a07 Mon Sep 17 00:00:00 2001
From: Ruslan Baratov <ruslan_bara...@yahoo.com>
Date: Thu, 24 Sep 2015 12:04:27 +0300
Subject: [PATCH 2/3] CMake module for universal iOS library install
Add CMake module with function `install_universal_ios_library`.
Target name and destination passed to the function. This function will be run
after library installed: will trigger additional build instructions for missing
platform and fuse libraries into universal in destination directory.
Module designed to be used in `cmake_install.cmake` script.
---
Modules/install_universal_ios_library.cmake | 268 ++++++++++++++++++++++++++++
1 file changed, 268 insertions(+)
create mode 100644 Modules/install_universal_ios_library.cmake
diff --git a/Modules/install_universal_ios_library.cmake b/Modules/install_universal_ios_library.cmake
new file mode 100644
index 0000000..6c05ad1
--- /dev/null
+++ b/Modules/install_universal_ios_library.cmake
@@ -0,0 +1,268 @@
+#=============================================================================
+# Copyright 2014-2015 Ruslan Baratov
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# Function to print messages of this module
+function(install_universal_ios_message str)
+ message("[iOS universal] ${str}")
+endfunction()
+
+# Get build settings for the current target/config/SDK by running
+# `xcodebuild -sdk ... -showBuildSettings` and parsing it's output
+function(install_universal_ios_get sdk variable resultvar)
+ if("${sdk}" STREQUAL "")
+ message(FATAL_ERROR "`sdk` is empty")
+ endif()
+
+ if("${variable}" STREQUAL "")
+ message(FATAL_ERROR "`variable` is empty")
+ endif()
+
+ if("${resultvar}" STREQUAL "")
+ message(FATAL_ERROR "`resultvar` is empty")
+ endif()
+
+ set(
+ cmd
+ xcodebuild -showBuildSettings
+ -sdk "${sdk}"
+ -target "${CURRENT_TARGET}"
+ -config "${CURRENT_CONFIG}"
+ )
+
+ execute_process(
+ COMMAND ${cmd}
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE output
+ )
+
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Command failed (${result}): ${cmd}")
+ endif()
+
+ string(REPLACE "\n" ";" output "${output}")
+
+ set(var_pattern " ${variable} = ")
+ string(LENGTH "${var_pattern}" var_pattern_len)
+
+ set(result "")
+ foreach(x ${output})
+ string(FIND "${x}" "${var_pattern}" index)
+ if(index EQUAL 0)
+ if(NOT "${result}" STREQUAL "")
+ message(FATAL_ERROR "${variable} already found: ${result}")
+ endif()
+ string(SUBSTRING "${x}" "${var_pattern_len}" -1 result)
+ if("${result}" STREQUAL "")
+ message(FATAL_ERROR "Empty value of variable: ${variable}")
+ endif()
+ endif()
+ endforeach()
+
+ set("${resultvar}" "${result}" PARENT_SCOPE)
+endfunction()
+
+# Get architectures of given SDK (iphonesimulator/iphoneos)
+function(install_universal_ios_get_archs sdk resultvar)
+ cmake_policy(SET CMP0007 NEW)
+
+ if("${resultvar}" STREQUAL "")
+ message(FATAL_ERROR "`resultvar` is empty")
+ endif()
+
+ install_universal_ios_get("${sdk}" "VALID_ARCHS" valid_archs)
+
+ string(REPLACE " " ";" valid_archs "${valid_archs}")
+
+ list(REMOVE_ITEM valid_archs "") # remove empty elements
+ list(REMOVE_DUPLICATES valid_archs)
+
+ set("${resultvar}" "${valid_archs}" PARENT_SCOPE)
+endfunction()
+
+# Run build command for the given SDK
+function(install_universal_ios_build sdk)
+ if("${sdk}" STREQUAL "")
+ message(FATAL_ERROR "`sdk` is empty")
+ endif()
+
+ install_universal_ios_message("Build `${CURRENT_TARGET}` for `${sdk}`")
+
+ execute_process(
+ COMMAND
+ "${CMAKE_COMMAND}"
+ --build
+ .
+ --target "${CURRENT_TARGET}"
+ --config ${CURRENT_CONFIG}
+ --
+ -sdk "${sdk}"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Build failed")
+ endif()
+endfunction()
+
+# If linked with other fat libraries this library can contain extra
+# architectures. Remove them to avoid 'lipo -create' error.
+# Ignore result and output since architectures may not exist.
+function(install_universal_ios_remove_arch lib arch)
+ execute_process(
+ COMMAND lipo -remove ${arch} -output ${lib} ${lib}
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+endfunction()
+
+# Create universal library for the given target.
+#
+# Preconditions:
+# * Library already installed to ${destination} directory
+# for the ${EFFECTIVE_PLATFORM_NAME} platform
+#
+# This function will:
+# * Run build for the lacking platform,
+# i.e. opposite to the ${EFFECTIVE_PLATFORM_NAME}
+# * Fuse both libraries by running `lipo -create ${src} ${dst} -output ${dst}`
+# src: library that was just built
+# dst: installed library
+function(install_universal_ios_library target destination)
+ if("${target}" STREQUAL "")
+ message(FATAL_ERROR "`target` is empty")
+ endif()
+
+ if("${destination}" STREQUAL "")
+ message(FATAL_ERROR "`destination` is empty")
+ endif()
+
+ if(NOT IS_ABSOLUTE "${destination}")
+ message(FATAL_ERROR "`destination` is not absolute: ${destination}")
+ endif()
+
+ if(NOT IS_DIRECTORY "${destination}")
+ message(FATAL_ERROR "`destination` is not absolute: ${destination}")
+ endif()
+
+ if(NOT EXISTS "${destination}")
+ message(FATAL_ERROR "`destination` not exists: ${destination}")
+ endif()
+
+ if("${CMAKE_BINARY_DIR}" STREQUAL "")
+ message(FATAL_ERROR "`CMAKE_BINARY_DIR` is empty")
+ endif()
+
+ if(NOT IS_DIRECTORY "${CMAKE_BINARY_DIR}")
+ message(FATAL_ERROR "Is not a directory: ${CMAKE_BINARY_DIR}")
+ endif()
+
+ if(NOT EXISTS "${CMAKE_BINARY_DIR}")
+ message(FATAL_ERROR "Not exists: ${CMAKE_BINARY_DIR}")
+ endif()
+
+ if("${CMAKE_INSTALL_CONFIG_NAME}" STREQUAL "")
+ message(FATAL_ERROR "CMAKE_INSTALL_CONFIG_NAME is empty")
+ endif()
+
+ if("${EFFECTIVE_PLATFORM_NAME}" STREQUAL "")
+ message(FATAL_ERROR "EFFECTIVE_PLATFORM_NAME is empty")
+ elseif("${EFFECTIVE_PLATFORM_NAME}" STREQUAL "-iphoneos")
+ # iphoneos already installed - add simulator part
+ set(build_sdk "iphonesimulator")
+ set(build_sim YES)
+ elseif("${EFFECTIVE_PLATFORM_NAME}" STREQUAL "-iphonesimulator")
+ # iphonesimulator already installed - add device part
+ set(build_sdk "iphoneos")
+ set(build_sim NO)
+ else()
+ message(
+ FATAL_ERROR
+ "Unexpected EFFECTIVE_PLATFORM_NAME: ${EFFECTIVE_PLATFORM_NAME}"
+ )
+ endif()
+
+ set(CURRENT_CONFIG "${CMAKE_INSTALL_CONFIG_NAME}")
+ set(CURRENT_TARGET "${target}")
+
+ install_universal_ios_message("Target: ${CURRENT_TARGET}")
+ install_universal_ios_message("Config: ${CURRENT_CONFIG}")
+ install_universal_ios_message("Destination: ${destination}")
+
+ # SDK name for device/simulator
+ set(dev_sdk "iphoneos")
+ set(sim_sdk "iphonesimulator")
+
+ # Get architectures of the target
+ install_universal_ios_get_archs("${build_sdk}" build_archs)
+
+ # Return if there are no valid architectures for the SDK.
+ # (note that library already installed)
+ if("${build_archs}" STREQUAL "")
+ install_universal_ios_message(
+ "No architectures detected for build_sdk: ${build_sdk} (skip)"
+ )
+ return()
+ endif()
+
+ # Get location of the library in build directory
+ install_universal_ios_get("${build_sdk}" "CODESIGNING_FOLDER_PATH" src)
+
+ # Library output name
+ install_universal_ios_get("${dev_sdk}" "EXECUTABLE_NAME" dev_libname)
+ install_universal_ios_get("${sim_sdk}" "EXECUTABLE_NAME" sim_libname)
+
+ if("${dev_libname}" STREQUAL "${sim_libname}")
+ set(libname "${dev_libname}")
+ else()
+ message(FATAL_ERROR "Library names differs: ${dev_libname} ${sim_libname}")
+ endif()
+
+ set(dst "${destination}/${libname}")
+
+ install_universal_ios_build("${build_sdk}")
+
+ if(build_sim)
+ set(sim_libpath "${src}")
+ set(dev_libpath "${dst}")
+ else()
+ set(sim_libpath "${dst}")
+ set(dev_libpath "${src}")
+ endif()
+
+ install_universal_ios_remove_arch("${dev_libpath}" "i386")
+ install_universal_ios_remove_arch("${dev_libpath}" "x86_64")
+
+ install_universal_ios_remove_arch("${sim_libpath}" "armv7")
+ install_universal_ios_remove_arch("${sim_libpath}" "armv7s")
+ install_universal_ios_remove_arch("${sim_libpath}" "arm64")
+
+ install_universal_ios_message("Device: ${dev_libpath}")
+ install_universal_ios_message("Simulator: ${sim_libpath}")
+
+ set(cmd lipo -create ${src} ${dst} -output ${dst})
+
+ execute_process(
+ COMMAND ${cmd}
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ message(FATAL_ERROR "Command failed: ${cmd}")
+ endif()
+
+ install_universal_ios_message("Install done: ${dst}")
+endfunction()
--
1.9.3 (Apple Git-50)
>From 83c15d383700c9c14d4252cf878d7b4ff02352bf Mon Sep 17 00:00:00 2001
From: Ruslan Baratov <ruslan_bara...@yahoo.com>
Date: Thu, 24 Sep 2015 12:25:00 +0300
Subject: [PATCH 3/3] Universal iOS library install
Run `install_universal_ios_library` function in `cmake_install.cmake` script if
`GetTargetNameForUniversalIosInstall` returns non-empty target name.
---
Source/cmInstallGenerator.cxx | 10 +++++++++-
Source/cmInstallGenerator.h | 3 ++-
Source/cmInstallTargetGenerator.cxx | 2 +-
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 2e1c5f0..5c2cd21 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -45,7 +45,8 @@ void cmInstallGenerator
const char* permissions_dir /* = 0 */,
const char* rename /* = 0 */,
const char* literal_args /* = 0 */,
- Indent const& indent
+ Indent const& indent,
+ std::string target_name_for_universal_ios_install
)
{
// Use the FILE command to install the file.
@@ -142,6 +143,13 @@ void cmInstallGenerator
os << literal_args;
}
os << ")\n";
+ if(!target_name_for_universal_ios_install.empty())
+ {
+ os << indent << "include(install_universal_ios_library)\n";
+ os << indent << "install_universal_ios_library(";
+ os << "\"" << target_name_for_universal_ios_install << "\" ";
+ os << "\"" << absDest << "\")\n";
+ }
}
//----------------------------------------------------------------------------
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index b8e5b53..ee10b0c 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -49,7 +49,8 @@ public:
const char* permissions_dir = 0,
const char* rename = 0,
const char* literal_args = 0,
- Indent const& indent = Indent()
+ Indent const& indent = Indent(),
+ std::string target_name_for_universal_ios_install = ""
);
/** Get the install destination as it should appear in the
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index db0ed6e..709ffbd 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -338,7 +338,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
type, filesFrom, optional,
this->FilePermissions.c_str(), no_dir_permissions,
no_rename, literal_args.c_str(),
- indent);
+ indent, this->GetTargetNameForUniversalIosInstall(type));
// Add post-installation tweaks.
this->AddTweak(os, indent, config, filesTo,
--
1.9.3 (Apple Git-50)
--
Powered by www.kitware.com
Please keep messages on-topic and check the CMake FAQ at:
http://www.cmake.org/Wiki/CMake_FAQ
Kitware offers various services to support the CMake community. For more
information on each offering, please visit:
CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers