123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- # file Copyright.txt or https://cmake.org/licensing for details.
- cmake_policy(PUSH)
- cmake_policy(SET CMP0057 NEW) # if IN_LIST
- # 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]*)")
- if("${variable}" STREQUAL "VALID_ARCHS")
- # VALID_ARCHS may be unset by user for given SDK
- # (e.g. for build without simulator).
- set("${resultvar}" "" PARENT_SCOPE)
- return()
- else()
- message(FATAL_ERROR "${variable} not found.")
- endif()
- 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(PUSH)
- 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)
- string(REPLACE ";" " " printable "${valid_archs}")
- _ios_install_combined_message("Architectures (${sdk}): ${printable}")
- set("${resultvar}" "${valid_archs}" PARENT_SCOPE)
- cmake_policy(POP)
- 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)
- 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)
- # Do not merge OUTPUT_VARIABLE and ERROR_VARIABLE since latter may contain
- # some diagnostic information even for the successful run.
- execute_process(
- COMMAND ${cmd}
- RESULT_VARIABLE result
- OUTPUT_VARIABLE output
- ERROR_VARIABLE error_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}\nOutput(error):\n${error_output}"
- )
- endif()
- set(_lipo_path ${output})
- list(LENGTH _lipo_path len)
- if(NOT len EQUAL 1)
- message(FATAL_ERROR "Unexpected xcrun output: ${_lipo_path}")
- endif()
- if(NOT EXISTS "${_lipo_path}")
- message(FATAL_ERROR "File not found: ${_lipo_path}")
- endif()
- 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()
- cmake_policy(POP)
|