|
|
@@ -0,0 +1,297 @@
|
|
|
+
|
|
|
+#=============================================================================
|
|
|
+# Copyright 2014-2015 Ruslan Baratov, Gregor Jasny
|
|
|
+#
|
|
|
+# 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(_ios_install_combined_message)
|
|
|
+ message("[iOS combined] " ${ARGN})
|
|
|
+endfunction()
|
|
|
+
|
|
|
+# Get build settings for the current target/config/SDK by running
|
|
|
+# `xcodebuild -sdk ... -showBuildSettings` and parsing it's output
|
|
|
+function(_ios_install_combined_get_build_setting 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()
|
|
|
+
|
|
|
+ if(NOT output MATCHES " ${variable} = ([^\n]*)")
|
|
|
+ message(FATAL_ERROR "${variable} not found.")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ set("${resultvar}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
|
|
|
+endfunction()
|
|
|
+
|
|
|
+# Get architectures of given SDK (iphonesimulator/iphoneos)
|
|
|
+function(_ios_install_combined_get_valid_archs sdk resultvar)
|
|
|
+ cmake_policy(SET CMP0007 NEW)
|
|
|
+
|
|
|
+ if("${resultvar}" STREQUAL "")
|
|
|
+ message(FATAL_ERROR "`resultvar` is empty")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ _ios_install_combined_get_build_setting("${sdk}" "VALID_ARCHS" valid_archs)
|
|
|
+
|
|
|
+ separate_arguments(valid_archs)
|
|
|
+ list(REMOVE_ITEM valid_archs "") # remove empty elements
|
|
|
+ list(REMOVE_DUPLICATES valid_archs)
|
|
|
+
|
|
|
+ set("${resultvar}" "${valid_archs}" PARENT_SCOPE)
|
|
|
+endfunction()
|
|
|
+
|
|
|
+# Final target can contain more architectures that specified by SDK. This
|
|
|
+# function will run 'lipo -info' and parse output. Result will be returned
|
|
|
+# as a CMake list.
|
|
|
+function(_ios_install_combined_get_real_archs filename resultvar)
|
|
|
+ set(cmd "${_lipo_path}" -info "${filename}")
|
|
|
+ execute_process(
|
|
|
+ COMMAND ${cmd}
|
|
|
+ RESULT_VARIABLE result
|
|
|
+ OUTPUT_VARIABLE output
|
|
|
+ ERROR_VARIABLE output
|
|
|
+ OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
|
+ ERROR_STRIP_TRAILING_WHITESPACE
|
|
|
+ )
|
|
|
+ if(NOT result EQUAL 0)
|
|
|
+ message(
|
|
|
+ FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
|
|
|
+ )
|
|
|
+ endif()
|
|
|
+
|
|
|
+ if(NOT output MATCHES "(Architectures in the fat file: [^\n]+ are|Non-fat file: [^\n]+ is architecture): ([^\n]*)")
|
|
|
+ message(FATAL_ERROR "Could not detect architecture from: ${output}")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ separate_arguments(CMAKE_MATCH_2)
|
|
|
+ set(${resultvar} ${CMAKE_MATCH_2} PARENT_SCOPE)
|
|
|
+endfunction()
|
|
|
+
|
|
|
+# Run build command for the given SDK
|
|
|
+function(_ios_install_combined_build sdk)
|
|
|
+ if("${sdk}" STREQUAL "")
|
|
|
+ message(FATAL_ERROR "`sdk` is empty")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ _ios_install_combined_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()
|
|
|
+
|
|
|
+# Remove given architecture from file. This step needed only in rare cases
|
|
|
+# when target was built in "unusual" way. Emit warning message.
|
|
|
+function(_ios_install_combined_remove_arch lib arch)
|
|
|
+ _ios_install_combined_message(
|
|
|
+ "Warning! Unexpected architecture `${arch}` detected and will be removed "
|
|
|
+ "from file `${lib}`")
|
|
|
+ set(cmd "${_lipo_path}" -remove ${arch} -output ${lib} ${lib})
|
|
|
+ execute_process(
|
|
|
+ COMMAND ${cmd}
|
|
|
+ RESULT_VARIABLE result
|
|
|
+ OUTPUT_VARIABLE output
|
|
|
+ ERROR_VARIABLE output
|
|
|
+ OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
|
+ ERROR_STRIP_TRAILING_WHITESPACE
|
|
|
+ )
|
|
|
+ if(NOT result EQUAL 0)
|
|
|
+ message(
|
|
|
+ FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
|
|
|
+ )
|
|
|
+ endif()
|
|
|
+endfunction()
|
|
|
+
|
|
|
+# Check that 'lib' contains only 'archs' architectures (remove others).
|
|
|
+function(_ios_install_combined_keep_archs lib archs)
|
|
|
+ _ios_install_combined_get_real_archs("${lib}" real_archs)
|
|
|
+ set(archs_to_remove ${real_archs})
|
|
|
+ list(REMOVE_ITEM archs_to_remove ${archs})
|
|
|
+ foreach(x ${archs_to_remove})
|
|
|
+ _ios_install_combined_remove_arch("${lib}" "${x}")
|
|
|
+ endforeach()
|
|
|
+endfunction()
|
|
|
+
|
|
|
+function(_ios_install_combined_detect_sdks this_sdk_var corr_sdk_var)
|
|
|
+ cmake_policy(SET CMP0057 NEW)
|
|
|
+
|
|
|
+ set(this_sdk "$ENV{PLATFORM_NAME}")
|
|
|
+ if("${this_sdk}" STREQUAL "")
|
|
|
+ message(FATAL_ERROR "Environment variable PLATFORM_NAME is empty")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ set(all_platforms "$ENV{SUPPORTED_PLATFORMS}")
|
|
|
+ if("${all_platforms}" STREQUAL "")
|
|
|
+ message(FATAL_ERROR "Environment variable SUPPORTED_PLATFORMS is empty")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ separate_arguments(all_platforms)
|
|
|
+ if(NOT this_sdk IN_LIST all_platforms)
|
|
|
+ message(FATAL_ERROR "`${this_sdk}` not found in `${all_platforms}`")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ list(REMOVE_ITEM all_platforms "" "${this_sdk}")
|
|
|
+ list(LENGTH all_platforms all_platforms_length)
|
|
|
+ if(NOT all_platforms_length EQUAL 1)
|
|
|
+ message(FATAL_ERROR "Expected one element: ${all_platforms}")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ set(${this_sdk_var} "${this_sdk}" PARENT_SCOPE)
|
|
|
+ set(${corr_sdk_var} "${all_platforms}" PARENT_SCOPE)
|
|
|
+endfunction()
|
|
|
+
|
|
|
+# Create combined binary for the given target.
|
|
|
+#
|
|
|
+# Preconditions:
|
|
|
+# * Target already installed at ${destination}
|
|
|
+# for the ${PLATFORM_NAME} platform
|
|
|
+#
|
|
|
+# This function will:
|
|
|
+# * Run build for the lacking platform, i.e. opposite to the ${PLATFORM_NAME}
|
|
|
+# * Fuse both libraries by running lipo
|
|
|
+function(ios_install_combined 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(IS_DIRECTORY "${destination}" OR IS_SYMLINK "${destination}")
|
|
|
+ message(FATAL_ERROR "`destination` is no regular file: ${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("${CMAKE_INSTALL_CONFIG_NAME}" STREQUAL "")
|
|
|
+ message(FATAL_ERROR "CMAKE_INSTALL_CONFIG_NAME is empty")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ set(cmd xcrun -f lipo)
|
|
|
+ execute_process(
|
|
|
+ COMMAND ${cmd}
|
|
|
+ RESULT_VARIABLE result
|
|
|
+ OUTPUT_VARIABLE output
|
|
|
+ ERROR_VARIABLE output
|
|
|
+ OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
|
+ ERROR_STRIP_TRAILING_WHITESPACE
|
|
|
+ )
|
|
|
+ if(NOT result EQUAL 0)
|
|
|
+ message(
|
|
|
+ FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
|
|
|
+ )
|
|
|
+ endif()
|
|
|
+ set(_lipo_path ${output})
|
|
|
+
|
|
|
+ set(CURRENT_CONFIG "${CMAKE_INSTALL_CONFIG_NAME}")
|
|
|
+ set(CURRENT_TARGET "${target}")
|
|
|
+
|
|
|
+ _ios_install_combined_message("Target: ${CURRENT_TARGET}")
|
|
|
+ _ios_install_combined_message("Config: ${CURRENT_CONFIG}")
|
|
|
+ _ios_install_combined_message("Destination: ${destination}")
|
|
|
+
|
|
|
+ # Get SDKs
|
|
|
+ _ios_install_combined_detect_sdks(this_sdk corr_sdk)
|
|
|
+
|
|
|
+ # Get architectures of the target
|
|
|
+ _ios_install_combined_get_valid_archs("${corr_sdk}" corr_valid_archs)
|
|
|
+ _ios_install_combined_get_valid_archs("${this_sdk}" this_valid_archs)
|
|
|
+
|
|
|
+ # Return if there are no valid architectures for the SDK.
|
|
|
+ # (note that library already installed)
|
|
|
+ if("${corr_valid_archs}" STREQUAL "")
|
|
|
+ _ios_install_combined_message(
|
|
|
+ "No architectures detected for `${corr_sdk}` (skip)"
|
|
|
+ )
|
|
|
+ return()
|
|
|
+ endif()
|
|
|
+
|
|
|
+ # Trigger build of corresponding target
|
|
|
+ _ios_install_combined_build("${corr_sdk}")
|
|
|
+
|
|
|
+ # Get location of the library in build directory
|
|
|
+ _ios_install_combined_get_build_setting(
|
|
|
+ "${corr_sdk}" "CONFIGURATION_BUILD_DIR" corr_build_dir)
|
|
|
+ _ios_install_combined_get_build_setting(
|
|
|
+ "${corr_sdk}" "EXECUTABLE_PATH" corr_executable_path)
|
|
|
+ set(corr "${corr_build_dir}/${corr_executable_path}")
|
|
|
+
|
|
|
+ _ios_install_combined_keep_archs("${corr}" "${corr_valid_archs}")
|
|
|
+ _ios_install_combined_keep_archs("${destination}" "${this_valid_archs}")
|
|
|
+
|
|
|
+ _ios_install_combined_message("Current: ${destination}")
|
|
|
+ _ios_install_combined_message("Corresponding: ${corr}")
|
|
|
+
|
|
|
+ set(cmd "${_lipo_path}" -create ${corr} ${destination} -output ${destination})
|
|
|
+
|
|
|
+ execute_process(
|
|
|
+ COMMAND ${cmd}
|
|
|
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
|
+ RESULT_VARIABLE result
|
|
|
+ )
|
|
|
+
|
|
|
+ if(NOT result EQUAL 0)
|
|
|
+ message(FATAL_ERROR "Command failed: ${cmd}")
|
|
|
+ endif()
|
|
|
+
|
|
|
+ _ios_install_combined_message("Install done: ${destination}")
|
|
|
+endfunction()
|