From c5cecd45e1c6ca17d148c14c65f0fa0553dc88a9 Mon Sep 17 00:00:00 2001 From: Scott Hutton Date: Thu, 18 Jan 2024 09:54:25 -0800 Subject: [PATCH] Refactor universal binary build --- cmake/FindRust.cmake | 84 +++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/cmake/FindRust.cmake b/cmake/FindRust.cmake index e38cc6fab0..9c98b41223 100644 --- a/cmake/FindRust.cmake +++ b/cmake/FindRust.cmake @@ -142,6 +142,10 @@ if(NOT DEFINED CARGO_HOME) endif() endif() +# +# Environment for most invocations of `cargo` +# + include(FindPackageHandleStandardArgs) function(find_rust_program RUST_PROGRAM) @@ -191,6 +195,7 @@ function(cargo_vendor) # for online builds when we run `cpack --config CPackSourceConfig.cmake` message(STATUS "Running `cargo vendor` to collect dependencies for ${ARGS_TARGET}. This may take a while if the local crates.io index needs to be updated ...") make_directory(${ARGS_SOURCE_DIRECTORY}/.cargo) + GetCargoLocalDirEnv(_cargo_local_dir_env) execute_process( COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" ${cargo_EXECUTABLE} vendor ".cargo/vendor" WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" @@ -216,6 +221,24 @@ directory = \".cargo/vendor\" endif() endfunction() +# Export the project name (including upstream project) and maintainer mode +# status for use by build scripts +function(GetCargoExtraEnv result) + set(_result "PROJECT_NAME=${PROJECT_NAME}") + list(APPEND _result "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}") + list(APPEND _result "MAINTAINER_MODE=${MAINTAINER_MODE}") + # Propagate any additional Rust compiler flags + list(APPEND _result "RUSTFLAGS=${RUSTFLAGS}") + set("${result}" "${_result}" PARENT_SCOPE) +endfunction() + +function(GetCargoLocalDirEnv result) + # Specify the destination directory for build products + set(_env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}") + list(APPEND _env "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"") + set(${result} "${_env}" PARENT_SCOPE) +endfunction() + function(add_rust_executable) set(options) set(oneValueArgs TARGET SOURCE_DIRECTORY BINARY_DIRECTORY) @@ -233,10 +256,14 @@ function(add_rust_executable) list(APPEND MY_CARGO_ARGS "--target-dir" ${ARGS_BINARY_DIRECTORY}) list(JOIN MY_CARGO_ARGS " " MY_CARGO_ARGS_STRING) + GetCargoExtraEnv(_cargo_extra_env) + GetCargoLocalDirEnv(_cargo_local_dir_env) + # Build the executable. add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND ${CMAKE_COMMAND} -E env "${_cargo_extra_env}" "${_cargo_local_dir_env}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND_EXPAND_LISTS WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${EXE_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with:\n\t ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") @@ -283,39 +310,42 @@ function(add_rust_library) list(APPEND MY_CARGO_ARGS "--target-dir" ${ARGS_BINARY_DIRECTORY}) list(JOIN MY_CARGO_ARGS " " MY_CARGO_ARGS_STRING) - # Build the library and generate the c-binding - if("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(arm64;x86_64|x86_64;arm64)$") + GetCargoExtraEnv(_cargo_extra_env) + GetCargoLocalDirEnv(_cargo_local_dir_env) + + if(RUST_COMPILER_TARGET STREQUAL "universal-apple-darwin") + foreach(arch IN LISTS CMAKE_OSX_ARCHITECTURES) + message("Making custom command for OSX arch ${arch}") + if(arch STREQUAL "arm64") + # Convert to rustc's designation + set(arch "aarch64") + endif() + set(this_output "${ARGS_BINARY_DIRECTORY}/${arch}-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a") + list(APPEND lipo_inputs "${this_output}") + add_custom_command( + OUTPUT "${this_output}" + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "${_cargo_extra_env}" "${_cargo_local_dir_env}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=${arch}-apple-darwin + COMMAND_EXPAND_LISTS + WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" + DEPENDS ${LIB_SOURCES} + COMMENT "Building ${ARGS_TARGET} for ${arch} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") + endforeach() + # `lipo` will provide the Universal binary add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "PROJECT_NAME=${PROJECT_NAME}" "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "PROJECT_NAME=${PROJECT_NAME}" "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin COMMAND ${CMAKE_COMMAND} -E make_directory "${ARGS_BINARY_DIRECTORY}/${RUST_COMPILER_TARGET}/${CARGO_BUILD_TYPE}" COMMAND lipo -create ${ARGS_BINARY_DIRECTORY}/x86_64-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a ${ARGS_BINARY_DIRECTORY}/aarch64-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a -output "${OUTPUT}" WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" - DEPENDS ${LIB_SOURCES} - COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") - elseif("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(arm64)$") - add_custom_command( - OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "PROJECT_NAME=${PROJECT_NAME}" "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin - WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" - DEPENDS ${LIB_SOURCES} - COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") - elseif("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(x86_64)$") - add_custom_command( - OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "PROJECT_NAME=${PROJECT_NAME}" "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin - COMMAND ${CMAKE_COMMAND} -E make_directory "${ARGS_BINARY_DIRECTORY}/${RUST_COMPILER_TARGET}/${CARGO_BUILD_TYPE}" - WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" - DEPENDS ${LIB_SOURCES} - COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") + DEPENDS ${lipo_inputs} + COMMENT "Composing universal binary in ${ARGS_BINARY_DIRECTORY}") else() add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "PROJECT_NAME=${PROJECT_NAME}" "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "${_cargo_extra_env}" "${_cargo_local_dir_env}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND_EXPAND_LISTS WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} - COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") + COMMENT "Building ${ARGS_TARGET} for ${arch} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") endif() # Create a target from the build output @@ -370,9 +400,13 @@ function(add_rust_test) ) endif() + GetCargoExtraEnv(_cargo_extra_env) + GetCargoLocalDirEnv(_cargo_local_dir_env) + add_test( NAME ${ARGS_NAME} - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=test" "PROJECT_NAME=${PROJECT_NAME}" "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --color always + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=test" "${_cargo_extra_env}" "${_cargo_local_dir_env}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --color always + COMMAND_EXPAND_LISTS WORKING_DIRECTORY ${ARGS_SOURCE_DIRECTORY} ) endfunction()