Changeset 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() | ||||
# If we are cross compiling, create a directory for native build. | # It is imperative that NATIVE_BUILD_DIR be in the cache. | ||||
set(NATIVE_BUILD_DIR "${CMAKE_BINARY_DIR}/native") | if(NOT DEFINED NATIVE_BUILD_DIR) | ||||
Fabien: The `if` is not necessary. Only `INTERNAL` cache variables are overridden unless `FORCE` is… | |||||
deadalnixAuthorUnsubmitted Done Inline ActionsObviously... deadalnix: Obviously... | |||||
FabienUnsubmitted Not Done Inline ActionsYes it's weird... Fabien: Yes it's weird... | |||||
set(NATIVE_BINARY_DIR "${NATIVE_BUILD_DIR}/bin") | set(NATIVE_BUILD_DIR "${CMAKE_BINARY_DIR}/native" CACHE PATH "The path of the native build directory") | ||||
set(NATIVE_BUILD_TARGET "${NATIVE_BUILD_DIR}/CMakeCache.txt") | endif() | ||||
if(NOT __IS_NATIVE_BUILD AND NOT TARGET native-cmake-build) | function(add_native_executable NAME) | ||||
file(MAKE_DIRECTORY ${NATIVE_BUILD_DIR}) | if(__IS_NATIVE_BUILD) | ||||
add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN}) | |||||
else() | |||||
file(RELATIVE_PATH RELATIVE_PATH "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") | |||||
set(NATIVE_TARGET "${RELATIVE_PATH}/${NAME}") | |||||
set(NATIVE_BINARY "${NATIVE_BUILD_DIR}/${NATIVE_TARGET}") | |||||
# We create a symlink to because cmake craps itself if the imported | |||||
FabienUnsubmitted Not Done Inline ActionsNit: symlink to because => symlink because Fabien: Nit: `symlink to because` => `symlink because` | |||||
# executable has the same name as the ecutble itself. | |||||
FabienUnsubmitted Not Done Inline ActionsNit: ecutble => executable Fabien: Nit: `ecutble` => `executable` | |||||
# https://cmake.org/pipermail/cmake/2019-May/069480.html | |||||
add_custom_command( | add_custom_command( | ||||
OUTPUT ${NATIVE_BUILD_TARGET} | OUTPUT "native-${NAME}" | ||||
COMMAND ${CMAKE_COMMAND} | COMMENT "Building native ${NATIVE_TARGET}" | ||||
-G "${CMAKE_GENERATOR}" | COMMAND ${CMAKE_COMMAND} --build "${NATIVE_BUILD_DIR}" --target "${NATIVE_TARGET}" | ||||
"${CMAKE_SOURCE_DIR}" | COMMAND ${CMAKE_COMMAND} -E create_symlink "${NATIVE_BINARY}" "native-${NAME}" | ||||
"-D__IS_NATIVE_BUILD=1" | DEPENDS "${NATIVE_BUILD_DIR}/CMakeCache.txt" | ||||
FabienUnsubmitted Not Done Inline ActionsYou need to add ${ARGN} to the dependencies, otherwise the native target won't rebuild if there source files are changed. Fabien: You need to add `${ARGN}` to the dependencies, otherwise the native target won't rebuild if… | |||||
deadalnixAuthorUnsubmitted Done Inline ActionsGood catch. This isn't exact, but probably good enough. deadalnix: Good catch. This isn't exact, but probably good enough. | |||||
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}" | |||||
"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${NATIVE_BINARY_DIR}" | |||||
# Don't require native third party dependencies we don't need. | |||||
"-DBUILD_BITCOIN_WALLET=OFF" | |||||
"-DBUILD_BITCOIN_QT=OFF" | |||||
"-DBUILD_BITCOIN_ZMQ=OFF" | |||||
"-DENABLE_QRCODE=OFF" | |||||
"-DENABLE_UPNP=OFF" | |||||
WORKING_DIRECTORY ${NATIVE_BUILD_DIR} | |||||
VERBATIM USES_TERMINAL | VERBATIM USES_TERMINAL | ||||
) | ) | ||||
add_custom_target(native-cmake-build DEPENDS ${NATIVE_BUILD_TARGET}) | add_executable(${NAME} IMPORTED GLOBAL) | ||||
endif() | set_target_properties(${NAME} PROPERTIES IMPORTED_LOCATION "${NATIVE_BINARY}") | ||||
macro(add_native_executable NAME) | |||||
if(NOT __IS_NATIVE_BUILD) | |||||
set(NATIVE_BINARY "${NATIVE_BINARY_DIR}/${NAME}") | |||||
add_custom_target("build-native-${NAME}" | |||||
COMMAND ${CMAKE_COMMAND} | |||||
--build "${NATIVE_BUILD_DIR}" | |||||
--target "${NAME}" | |||||
DEPENDS ${NATIVE_BUILD_TARGET} | |||||
BYPRODUCTS ${NATIVE_BINARY} | |||||
WORKING_DIRECTORY ${NATIVE_BUILD_DIR} | |||||
VERBATIM USES_TERMINAL | |||||
) | |||||
add_executable(${NAME} IMPORTED) | # 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. | |||||
add_custom_target("build-native-${NAME}" DEPENDS "native-${NAME}") | |||||
add_dependencies(${NAME} "build-native-${NAME}") | add_dependencies(${NAME} "build-native-${NAME}") | ||||
set_property(TARGET ${NAME} PROPERTY IMPORTED_LOCATION ${NATIVE_BINARY}) | |||||
else() | |||||
add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN}) | |||||
endif() | endif() | ||||
endmacro(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() | ||||
endfunction(native_target_include_directories) | endfunction(native_target_include_directories) | ||||
function(native_add_cmake_flags) | |||||
set_property(GLOBAL APPEND PROPERTY _NATIVE_BUILD_CMAKE_FLAGS ${ARGN}) | |||||
endfunction(native_add_cmake_flags) | |||||
# Internal machinery | |||||
function(_gen_native_cmake_target) | |||||
message(STATUS "Configuring native build in ${NATIVE_BUILD_DIR}") | |||||
get_property(ARGSLIST GLOBAL PROPERTY _NATIVE_BUILD_CMAKE_FLAGS) | |||||
list(SORT ARGSLIST) | |||||
list(REMOVE_DUPLICATES ARGSLIST) | |||||
list(JOIN ARGSLIST " " ARGS) | |||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/config") | |||||
configure_file( | |||||
"${CMAKE_SOURCE_DIR}/cmake/templates/NativeCmakeRunner.cmake.in" | |||||
"${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | |||||
) | |||||
endfunction(_gen_native_cmake_target) | |||||
function(_gen_native_cmake_hook VAR ACCESS) | |||||
# When CMAKE_CURRENT_LIST_DIR is set to empty, we execute everything. | |||||
FabienUnsubmitted Not Done Inline ActionsCan you point to some documentation regarding this behavior ? I couldn't find anything. Fabien: Can you point to some documentation regarding this behavior ? I couldn't find anything. | |||||
deadalnixAuthorUnsubmitted Done Inline ActionsFrom https://cmake.org/cmake/help/v3.10/variable/CMAKE_CURRENT_LIST_DIR.html
Which ends up being nothing for the last one. Let's be clear, this is an horrible hack, but it doesn't looks like there is a better way to do this. deadalnix: From https://cmake.org/cmake/help/v3.10/variable/CMAKE_CURRENT_LIST_DIR.html
> When CMake… | |||||
FabienUnsubmitted Not Done Inline ActionsIndeed, that's hacky ! But I can't this at any good solution: PRE-BUILD custom command attached to target will only work with VS, and calling the generation at the end of the top level file will break secp256k1 build... Fabien: Indeed, that's hacky !
But I can't this at any good solution: PRE-BUILD custom command… | |||||
if("${VAR}" STREQUAL "CMAKE_CURRENT_LIST_DIR" AND | |||||
"${CMAKE_CURRENT_LIST_DIR}" STREQUAL "" AND | |||||
"${ACCESS}" STREQUAL "MODIFIED_ACCESS") | |||||
_gen_native_cmake_target() | |||||
endif() | |||||
endfunction(_gen_native_cmake_hook) | |||||
if(NOT __IS_NATIVE_BUILD AND NOT TARGET native-cmake-build) | |||||
# Set a hook to execute when everything is set. | |||||
variable_watch(CMAKE_CURRENT_LIST_DIR _gen_native_cmake_hook) | |||||
add_custom_command( | |||||
OUTPUT "${NATIVE_BUILD_DIR}/CMakeCache.txt" | |||||
COMMAND "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | |||||
DEPENDS "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" | |||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" | |||||
VERBATIM USES_TERMINAL | |||||
) | |||||
add_custom_target(native-cmake-build DEPENDS "${NATIVE_BUILD_DIR}/CMakeCache.txt") | |||||
endif() |
The if is not necessary. Only INTERNAL cache variables are overridden unless FORCE is specified.