diff --git a/cmake/modules/CustomCommandWithDepFile.cmake b/cmake/modules/CustomCommandWithDepFile.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/CustomCommandWithDepFile.cmake @@ -0,0 +1,12 @@ +# Allow to easily create a custom command that uses dep file. +# depfile are a ninja only feature and a hard fail using other generators. + +function(add_custom_command_with_depfile) + cmake_parse_arguments("" "" "DEPFILE" "" ${ARGN}) + + if(_DEPFILE AND "${CMAKE_GENERATOR}" MATCHES "Ninja") + set(_dep_file_arg DEPFILE "${_DEPFILE}") + endif() + + add_custom_command(${_UNPARSED_ARGUMENTS} ${_dep_file_arg}) +endfunction() diff --git a/cmake/modules/NativeExecutable.cmake b/cmake/modules/NativeExecutable.cmake --- a/cmake/modules/NativeExecutable.cmake +++ b/cmake/modules/NativeExecutable.cmake @@ -13,6 +13,10 @@ # 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) +# 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) if(__IS_NATIVE_BUILD) add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN}) @@ -32,17 +36,32 @@ if(RELATIVE_PATH) string(PREPEND NATIVE_TARGET "${RELATIVE_PATH}/") 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_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 # executable has the same name as the executable itself. # https://cmake.org/pipermail/cmake/2019-May/069480.html - add_custom_command( - OUTPUT "native-${NAME}" + add_custom_command_with_depfile( + OUTPUT "${NATIVE_LINK}" COMMENT "Building native ${NATIVE_TARGET}" - COMMAND ${CMAKE_COMMAND} --build "${NATIVE_BUILD_DIR}" --target "${NAME}" - COMMAND ${CMAKE_COMMAND} -E create_symlink "${NATIVE_BINARY}" "native-${NAME}" - DEPENDS native-cmake-build ${ARGN} + COMMAND "${CMAKE_CURRENT_BINARY_DIR}/build_native_${NAME}.sh" + DEPENDS + native-cmake-build + "${CMAKE_CURRENT_BINARY_DIR}/build_native_${NAME}.sh" + ${ARGN} + DEPFILE "${NATIVE_LINK}.d" VERBATIM USES_TERMINAL ) @@ -51,7 +70,7 @@ # 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_custom_target("build-native-${NAME}" DEPENDS "${NATIVE_LINK}") add_dependencies(${NAME} "build-native-${NAME}") endif() endfunction(add_native_executable) @@ -96,17 +115,13 @@ # Set a hook to execute when everything is set. variable_watch(CMAKE_CURRENT_LIST_DIR _gen_native_cmake_hook) - if("${CMAKE_GENERATOR}" MATCHES "Ninja") - set(cmake_cache_dep_file DEPFILE "${NATIVE_BUILD_DIR}/CMakeFiles/CMakeCache.txt.d") - endif() - - add_custom_command( + add_custom_command_with_depfile( OUTPUT "${NATIVE_BUILD_DIR}/CMakeCache.txt" COMMENT "Preparing native build..." COMMAND "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" DEPENDS "${CMAKE_BINARY_DIR}/config/run_native_cmake.sh" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - ${cmake_cache_dep_file} + DEPFILE "${NATIVE_BUILD_DIR}/CMakeFiles/CMakeCache.txt.d" VERBATIM USES_TERMINAL ) diff --git a/cmake/templates/NativeBuildRunner.cmake.in b/cmake/templates/NativeBuildRunner.cmake.in new file mode 100755 --- /dev/null +++ b/cmake/templates/NativeBuildRunner.cmake.in @@ -0,0 +1,14 @@ +#!/bin/sh + +cd "${NATIVE_BUILD_DIR}" +"${CMAKE_COMMAND}" --build "${NATIVE_BUILD_DIR}" --target "${TARGET}" +"${CMAKE_COMMAND}" -E create_symlink "${NATIVE_BINARY}" "${NATIVE_LINK}" + +# Ok let's generate a depfile if we can. +if test "x${CMAKE_GENERATOR}" = "xNinja"; then + "${CMAKE_SOURCE_DIR}/cmake/utils/gen-ninja-deps.py" \ + --build-dir "${NATIVE_BUILD_DIR}" \ + --base-dir "${CMAKE_BINARY_DIR}" \ + --ninja "${CMAKE_MAKE_PROGRAM}" \ + "${RELATIVE_PATH}/native-${NAME}" "${TARGET}" > "${NATIVE_LINK}.d" +fi diff --git a/cmake/templates/NativeCmakeRunner.cmake.in b/cmake/templates/NativeCmakeRunner.cmake.in --- a/cmake/templates/NativeCmakeRunner.cmake.in +++ b/cmake/templates/NativeCmakeRunner.cmake.in @@ -9,11 +9,11 @@ # Ok let's generate a depfile if we can. if test "x${CMAKE_GENERATOR}" = "xNinja"; then - "${CMAKE_SOURCE_DIR}/cmake/utils/gen-ninja-deps.py" \ - --build-dir "${NATIVE_BUILD_DIR}" \ - --base-dir "${CMAKE_BINARY_DIR}" \ - --ninja "${CMAKE_MAKE_PROGRAM}" \ - native/CMakeCache.txt build.ninja \ - --extra-deps build.ninja \ - > "${NATIVE_BUILD_DIR}/CMakeFiles/CMakeCache.txt.d" + "${CMAKE_SOURCE_DIR}/cmake/utils/gen-ninja-deps.py" \ + --build-dir "${NATIVE_BUILD_DIR}" \ + --base-dir "${CMAKE_BINARY_DIR}" \ + --ninja "${CMAKE_MAKE_PROGRAM}" \ + native/CMakeCache.txt build.ninja \ + --extra-deps build.ninja \ + > "${NATIVE_BUILD_DIR}/CMakeFiles/CMakeCache.txt.d" fi diff --git a/cmake/utils/gen-ninja-deps.py b/cmake/utils/gen-ninja-deps.py --- a/cmake/utils/gen-ninja-deps.py +++ b/cmake/utils/gen-ninja-deps.py @@ -171,7 +171,7 @@ # Collapse everything under the base target. -basedeps = set(d.encode() for d in extra_deps) +basedeps = set() if extra_deps is None else set(d.encode() for d in extra_deps) for d in deps.values(): basedeps.update(d)