# This try_compile override calls try_compile for both iPhone device and simulator. # If COPY_FILE is specified, it will create a fat binary for device and simulator as well. cmake_policy(VERSION 3.3) # If ARG isn't empty, prepend PREFIX to it. macro(_tcios_prepend_if_exists PREFIX ARG) #message(STATUS "_tcios_prepend_if_exists ${PREFIX} ${ARG}") if (${ARG}) set(${ARG} ${PREFIX} ${${ARG}}) endif() endmacro(_tcios_prepend_if_exists) # Set output variables, remove temp files macro(_tcios_end SUCCESS COMPILER_OUTPUT FILE_ERROR_OUTPUT) set(${RESULT_VAR_IOS} ${SUCCESS} CACHE INTERNAL "" FORCE) # Pass the compiler's output to the caller only if they asked for it if (TCIOS_OUTPUT_VARIABLE) set(${TCIOS_OUTPUT_VARIABLE} ${COMPILER_OUTPUT} PARENT_SCOPE) endif() if (TCIOS_COPY_FILE_ERROR) set(${TCIOS_COPY_FILE_ERROR} ${FILE_ERROR_OUTPUT} PARENT_SCOPE) endif() file(REMOVE_RECURSE "${CMAKETMP_BACKUP}") if (TCIOS_COPY_FILE) file(REMOVE "${BINARY_DEVICE}" "${BINARY_SIMU}") endif() # Restore sysroot set(CMAKE_OSX_SYSROOT ${OLD_SYSROOT} CACHE STRING "System root for iOS" FORCE) return() endmacro(_tcios_end) function(try_compile RESULT_VAR_IOS BINDIR) #message(STATUS "try_compile for iPhone") #message(STATUS "called with: ${ARGV}") set(oneValueArgs OUTPUT_VARIABLE COPY_FILE COPY_FILE_ERROR) set(multiValueArgs SOURCES CMAKE_FLAGS COMPILE_DEFINITIONS LINK_LIBRARIES) # Check which version of try_compile is called (compile whole project or individual file(s)) if ( NOT ARGC LESS 4 AND NOT ARGV2 STREQUAL SOURCES AND NOT ARGV3 IN_LIST oneValueArgs AND NOT ARGV3 IN_LIST multiValueArgs ) # try_compile whole project version. cmake_parse_arguments(TCIOS "" OUTPUT_VARIABLE CMAKE_FLAGS ${ARGN}) # We need to use an intermediate OUTPUT_VARIABLE for each try_compile call if (TCIOS_OUTPUT_VARIABLE) list(REMOVE_ITEM "${ARGN}" OUTPUT_VARIABLE ${TCIOS_OUTPUT_VARIABLE}) endif() set(TCIOS_ARGS TCIOS_SUCCESS ${BINDIR} ${ARGN} ) # TCIOS_OUTPUT contains output from individual try_compile calls. set(TCIOS_ARGS_DEVICE ${TCIOS_ARGS} OUTPUT_VARIABLE TCIOS_OUTPUT_DEVICE) set(TCIOS_ARGS_SIMU ${TCIOS_ARGS} OUTPUT_VARIABLE TCIOS_OUTPUT_SIMU) else() # try_compile individual source(s) version. cmake_parse_arguments(TCIOS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Only one or multiple source files ? if (NOT TCIOS_SOURCES) set(TCIOS_SOURCES ${ARGV2}) else() set(TCIOS_SOURCES SOURCES ${TCIOS_SOURCES}) endif() # Prepend the argument flag before passing arguments to the actual try_compile _tcios_prepend_if_exists(CMAKE_FLAGS TCIOS_CMAKE_FLAGS) _tcios_prepend_if_exists(COMPILE_DEFINITIONS TCIOS_COMPILE_DEFINITIONS) _tcios_prepend_if_exists(LINK_LIBRARIES TCIOS_LINK_LIBRARIES) set(TCIOS_ARGS TCIOS_SUCCESS ${BINDIR} ${TCIOS_SOURCES} ${TCIOS_COMPILE_DEFINITIONS} ${TCIOS_LINK_LIBRARIES} ) set(TCIOS_ARGS_DEVICE ${TCIOS_ARGS} OUTPUT_VARIABLE TCIOS_OUTPUT_DEVICE ${TCIOS_CMAKE_FLAGS} ) set(TCIOS_ARGS_SIMU ${TCIOS_ARGS} OUTPUT_VARIABLE TCIOS_OUTPUT_SIMU ${TCIOS_CMAKE_FLAGS} ) # Copy the output file if the caller asked for it if (TCIOS_COPY_FILE) set(BINARY_DEVICE "${CMAKE_CURRENT_BINARY_DIR}/trycomp-ios") set(BINARY_SIMU "${CMAKE_CURRENT_BINARY_DIR}/trycomp-simulator") set(TCIOS_ARGS_DEVICE ${TCIOS_ARGS_DEVICE} COPY_FILE "${BINARY_DEVICE}" COPY_FILE_ERROR FILE_ERROR_DEVICE) set(TCIOS_ARGS_SIMU ${TCIOS_ARGS_SIMU} COPY_FILE "${BINARY_SIMU}" COPY_FILE_ERROR FILE_ERROR_SIMU) endif() endif() # try_compile cleans the CMakeTmp directory after every run. # Since content in this directory can be used as input for try_compile, we need to restore it after the first try_compile call, # or else the second call could fail (for instance with CMakeTestCCompiler). set(CMAKETMP_BACKUP "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/tcios_backup_CMakeTmp") file(COPY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" DESTINATION "${CMAKETMP_BACKUP}") # We need to set CMAKE_OSX_SYSROOT to build for the desired SDK (device or simulator). # Save its current value to restore it when we're done. set(OLD_SYSROOT ${CMAKE_OSX_SYSROOT}) # Call try_compile for both device and simulator, and then merge the binaries #message(STATUS "TCIOS device: ${TCIOS_ARGS_DEVICE}") # Setting OSX_SYSROOT this way is ugly but it's the only way that's worked for me. set(CMAKE_OSX_SYSROOT "iphoneos" CACHE STRING "System root for iOS" FORCE) _try_compile(${TCIOS_ARGS_DEVICE}) if (NOT TCIOS_SUCCESS) _tcios_end(FALSE "${TCIOS_OUTPUT_DEVICE}" "${FILE_ERROR_DEVICE}") endif() if(TCIOS_OUTPUT_SIMU) # Restore CMakeTmp for the second run file(COPY "${CMAKETMP_BACKUP}/" DESTINATION "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp") set(CMAKE_OSX_SYSROOT "iphonesimulator" CACHE STRING "System root for iOS" FORCE) _try_compile(${TCIOS_ARGS_SIMU}) if (NOT TCIOS_SUCCESS) _tcios_end(FALSE "${TCIOS_OUTPUT_SIMU}" "${FILE_ERROR_SIMU}") endif() endif(TCIOS_OUTPUT_SIMU) # Make device + simulator binary using lipo if (TCIOS_COPY_FILE) if (NOT IS_ABSOLUTE "${TCIOS_COPY_FILE}") set(TCIOS_COPY_FILE "${CMAKE_CURRENT_BINARY_DIR}/${TCIOS_COPY_FILE}") endif() #message(STATUS "TCIOS: lipo -create ${BINARY_DEVICE} ${BINARY_SIMU} -output ${TCIOS_COPY_FILE}") if (TCIOS_OUTPUT_SIMU) execute_process(COMMAND lipo -create "${BINARY_DEVICE}" "${BINARY_SIMU}" -output "${TCIOS_COPY_FILE}" RESULT_VARIABLE LIPO_RES OUTPUT_VARIABLE LIPO_OUT ERROR_VARIABLE LIPO_OUT) else() execute_process(COMMAND lipo -create "${BINARY_DEVICE}" -output "${TCIOS_COPY_FILE}" RESULT_VARIABLE LIPO_RES OUTPUT_VARIABLE LIPO_OUT ERROR_VARIABLE LIPO_OUT) endif() # Signal lipo errors if (NOT LIPO_RES EQUAL 0 OR NOT EXISTS "${TCIOS_COPY_FILE}") message(SEND_ERROR "lipo res: ${LIPO_RES}, output: ${LIPO_OUT}") _tcios_end(FALSE "${TCIOS_OUTPUT_DEVICE} ${TCIOS_OUTPUT_SIMU}" "${LIPO_OUT}") endif() endif() _tcios_end(TRUE "${TCIOS_OUTPUT_DEVICE} ${TCIOS_OUTPUT_SIMU}" "") endfunction(try_compile)