Changeset View
Changeset View
Standalone View
Standalone View
cmake/modules/NativeExecutable.cmake
# Allow to easily build native executable. | # Allow to easily build native executable. | ||||
# Useful for cross compilation. | # Useful for cross compilation. | ||||
if(NOT DEFINED __IS_NATIVE_BUILD) | if(NOT DEFINED __IS_NATIVE_BUILD) | ||||
# Check if we are in a native build or not. | # Check if we are in a native build or not. | ||||
set(__IS_NATIVE_BUILD 0 CACHE INTERNAL "Indicate if this is a native build") | set(__IS_NATIVE_BUILD 0 CACHE INTERNAL "Indicate if this is a native build") | ||||
endif() | endif() | ||||
if(__IS_NATIVE_BUILD AND CMAKE_CROSSCOMPILING) | if(__IS_NATIVE_BUILD AND CMAKE_CROSSCOMPILING) | ||||
message(FATAL_ERROR "A native build cannot be cross compiled") | message(FATAL_ERROR "A native build cannot be cross compiled") | ||||
endif() | endif() | ||||
# It is imperative that NATIVE_BUILD_DIR be in the cache. | # It is imperative that NATIVE_BUILD_DIR be in the cache. | ||||
set(NATIVE_BUILD_DIR "${CMAKE_BINARY_DIR}/native" CACHE PATH "The path of the native build directory" FORCE) | set(NATIVE_BUILD_DIR "${CMAKE_BINARY_DIR}/native" CACHE PATH "The path of the native build directory" FORCE) | ||||
# Only ninja support depfiles and this is a hard error with other generators | |||||
# so we need a nice wrapper to handle this mess. | |||||
include(CustomCommandWithDepFile) | |||||
function(add_native_executable NAME) | function(add_native_executable NAME) | ||||
if(__IS_NATIVE_BUILD) | if(__IS_NATIVE_BUILD) | ||||
add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN}) | add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN}) | ||||
# Multi-configuration generators (VS, Xcode) append a per-configuration | # Multi-configuration generators (VS, Xcode) append a per-configuration | ||||
# subdirectory to the specified directory unless the | # subdirectory to the specified directory unless the | ||||
# `RUNTIME_OUTPUT_DIRECTORY` property is defined using a generator | # `RUNTIME_OUTPUT_DIRECTORY` property is defined using a generator | ||||
# expression. | # expression. | ||||
# Since we don't care about the build configuration for native | # Since we don't care about the build configuration for native | ||||
# executables, we can simply drop this subdirectory. | # executables, we can simply drop this subdirectory. | ||||
# Doing so ensure that the path to the binary can always be retrieved. | # Doing so ensure that the path to the binary can always be retrieved. | ||||
set_target_properties(${NAME} PROPERTIES | set_target_properties(${NAME} PROPERTIES | ||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<0:>" | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<0:>" | ||||
) | ) | ||||
else() | else() | ||||
set(NATIVE_TARGET "${NAME}") | set(NATIVE_TARGET "${NAME}") | ||||
file(RELATIVE_PATH RELATIVE_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") | file(RELATIVE_PATH RELATIVE_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") | ||||
if(RELATIVE_PATH) | if(RELATIVE_PATH) | ||||
string(PREPEND NATIVE_TARGET "${RELATIVE_PATH}/") | string(PREPEND NATIVE_TARGET "${RELATIVE_PATH}/") | ||||
endif() | endif() | ||||
if("${CMAKE_GENERATOR}" MATCHES "Ninja") | |||||
set(TARGET "${NATIVE_TARGET}") | |||||
else() | |||||
set(TARGET "${NAME}") | |||||
endif() | |||||
set(NATIVE_BINARY "${NATIVE_BUILD_DIR}/${NATIVE_TARGET}") | set(NATIVE_BINARY "${NATIVE_BUILD_DIR}/${NATIVE_TARGET}") | ||||
set(NATIVE_LINK "${CMAKE_CURRENT_BINARY_DIR}/native-${NAME}") | |||||
configure_file( | |||||
"${CMAKE_SOURCE_DIR}/cmake/templates/NativeBuildRunner.cmake.in" | |||||
"${CMAKE_CURRENT_BINARY_DIR}/build_native_${NAME}.sh" | |||||
) | |||||
# We create a symlink because cmake craps itself if the imported | # We create a symlink because cmake craps itself if the imported | ||||
# executable has the same name as the executable itself. | # executable has the same name as the executable itself. | ||||
# https://cmake.org/pipermail/cmake/2019-May/069480.html | # https://cmake.org/pipermail/cmake/2019-May/069480.html | ||||
add_custom_command( | add_custom_command_with_depfile( | ||||
OUTPUT "native-${NAME}" | OUTPUT "${NATIVE_LINK}" | ||||
COMMENT "Building native ${NATIVE_TARGET}" | COMMENT "Building native ${NATIVE_TARGET}" | ||||
COMMAND ${CMAKE_COMMAND} --build "${NATIVE_BUILD_DIR}" --target "${NAME}" | COMMAND "${CMAKE_CURRENT_BINARY_DIR}/build_native_${NAME}.sh" | ||||
COMMAND ${CMAKE_COMMAND} -E create_symlink "${NATIVE_BINARY}" "native-${NAME}" | DEPENDS | ||||
DEPENDS native-cmake-build ${ARGN} | native-cmake-build | ||||
"${CMAKE_CURRENT_BINARY_DIR}/build_native_${NAME}.sh" | |||||
${ARGN} | |||||
DEPFILE "${NATIVE_LINK}.d" | |||||
VERBATIM USES_TERMINAL | VERBATIM USES_TERMINAL | ||||
) | ) | ||||
add_executable(${NAME} IMPORTED GLOBAL) | add_executable(${NAME} IMPORTED GLOBAL) | ||||
set_target_properties(${NAME} PROPERTIES IMPORTED_LOCATION "${NATIVE_BINARY}") | set_target_properties(${NAME} PROPERTIES IMPORTED_LOCATION "${NATIVE_BINARY}") | ||||
# This obviously cannot depend on a file for some mysterious reasons only | # This obviously cannot depend on a file for some mysterious reasons only | ||||
# the cmake gods are aware of, so we need a phony custom target. | # the cmake gods are aware of, so we need a phony custom target. | ||||
add_custom_target("build-native-${NAME}" DEPENDS "native-${NAME}") | add_custom_target("build-native-${NAME}" DEPENDS "${NATIVE_LINK}") | ||||
add_dependencies(${NAME} "build-native-${NAME}") | add_dependencies(${NAME} "build-native-${NAME}") | ||||
endif() | endif() | ||||
endfunction(add_native_executable) | endfunction(add_native_executable) | ||||
function(native_target_include_directories) | function(native_target_include_directories) | ||||
if(__IS_NATIVE_BUILD) | if(__IS_NATIVE_BUILD) | ||||
target_include_directories(${ARGN}) | target_include_directories(${ARGN}) | ||||
endif() | endif() | ||||
Show All 28 Lines | if("${VAR}" STREQUAL "CMAKE_CURRENT_LIST_DIR" AND | ||||
_gen_native_cmake_target() | _gen_native_cmake_target() | ||||
endif() | endif() | ||||
endfunction(_gen_native_cmake_hook) | endfunction(_gen_native_cmake_hook) | ||||
if(NOT __IS_NATIVE_BUILD AND NOT TARGET native-cmake-build) | if(NOT __IS_NATIVE_BUILD AND NOT TARGET native-cmake-build) | ||||
# Set a hook to execute when everything is set. | # Set a hook to execute when everything is set. | ||||
variable_watch(CMAKE_CURRENT_LIST_DIR _gen_native_cmake_hook) | variable_watch(CMAKE_CURRENT_LIST_DIR _gen_native_cmake_hook) | ||||
if("${CMAKE_GENERATOR}" MATCHES "Ninja") | add_custom_command_with_depfile( | ||||
set(cmake_cache_dep_file DEPFILE "${NATIVE_BUILD_DIR}/CMakeFiles/CMakeCache.txt.d") | |||||
endif() | |||||
add_custom_command( | |||||
OUTPUT "${NATIVE_BUILD_DIR}/CMakeCache.txt" | OUTPUT "${NATIVE_BUILD_DIR}/CMakeCache.txt" | ||||
COMMENT "Preparing native build..." | COMMENT "Preparing native build..." | ||||
COMMAND "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | COMMAND "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | ||||
DEPENDS "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | DEPENDS "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | ||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" | ||||
${cmake_cache_dep_file} | DEPFILE "${NATIVE_BUILD_DIR}/CMakeFiles/CMakeCache.txt.d" | ||||
VERBATIM USES_TERMINAL | VERBATIM USES_TERMINAL | ||||
) | ) | ||||
add_custom_target(native-cmake-build DEPENDS "${NATIVE_BUILD_DIR}/CMakeCache.txt") | add_custom_target(native-cmake-build DEPENDS "${NATIVE_BUILD_DIR}/CMakeCache.txt") | ||||
# Add the native directory to the list of file to cleanup. | # Add the native directory to the list of file to cleanup. | ||||
set_property(DIRECTORY "${CMAKE_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${NATIVE_BUILD_DIR}") | set_property(DIRECTORY "${CMAKE_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${NATIVE_BUILD_DIR}") | ||||
endif() | endif() |