# ============================================================================= # first, get some info about the compiler (and bindgen) # get rustc binary if(NOT DEFINED RUSTC_BIN OR "${RUSTC_BIN}" STREQUAL "") find_program(RUSTC_BIN rustc REQUIRED) endif() set(RUSTC_BIN ${RUSTC_BIN} CACHE FILEPATH "rustc command") message(NOTICE "-- RUSTC_BIN is ${RUSTC_BIN}") # get cbindgen binary if(NOT DEFINED CBINDGEN_BIN OR "${CBINDGEN_BIN}" STREQUAL "") find_program(CBINDGEN_BIN cbindgen REQUIRED) endif() set(CBINDGEN_BIN ${CBINDGEN_BIN} CACHE FILEPATH "cbindgen command") message(NOTICE "-- CBINDGEN_BIN is ${CBINDGEN_BIN}") # get bindgen binary if(NOT DEFINED BINDGEN_BIN OR "${BINDGEN_BIN}" STREQUAL "") find_program(BINDGEN_BIN bindgen REQUIRED) endif() set(BINDGEN_BIN ${BINDGEN_BIN} CACHE FILEPATH "bindgen command") message(NOTICE "-- BINDGEN_BIN is ${BINDGEN_BIN}") # ============================================================================= # set compile options if(DEFINED RUST_TARGET) list(APPEND RUST_CFLAGS "--target=${RUST_TARGET}") endif() if(DEFINED RUST_CPU) list(APPEND RUST_CFLAGS "-C" "target-cpu=${RUST_CPU}") endif() if(CMAKE_BUILD_TYPE STREQUAL Debug) list(APPEND RUST_CFLAGS "-C" "opt-level=0" "-g") elseif(CMAKE_BUILD_TYPE STREQUAL Release) list(APPEND RUST_CFLAGS "-C" "opt-level=3") elseif(CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo) list(APPEND RUST_CFLAGS "-C" "opt-level=2" "-g") elseif(CMAKE_BUILD_TYPE STREQUAL MinSizeRel) list(APPEND RUST_CFLAGS "-C" "opt-level=z") endif() list(APPEND BINDGEN_CFLAGS "--explicit-padding" "--formatter=none") list(APPEND CBINDGEN_CFLAGS "--cpp-compat" "-l" "C") if(CMAKE_BUILD_TYPE STREQUAL Debug) list(APPEND CBINDGEN_CFLAGS "--profile" "Debug") elseif(CMAKE_BUILD_TYPE STREQUAL Release OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo OR CMAKE_BUILD_TYPE STREQUAL MinSizeRel) list(APPEND CBINDGEN_CFLAGS "--profile" "Release") endif() # ============================================================================= # now define the macro we'll be using function(add_rust_object TOP_PROJECT RUST_TOP_SOURCE_FILE) if(ARGC GREATER 3) set(TARGET_NAME ${ARGV3}) else() cmake_path(GET RUST_TOP_SOURCE_FILE STEM TARGET_NAME) endif() # directory the header file will be in file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/) ### C-to-rust bindings (generate .rs from C headers, bindgen) set(HEADER_PATH "") set(MAIN_RUST_DEP "") if(ARGC GREATER 2) set(HEADER_PATH ${ARGV2}) cmake_path(GET HEADER_PATH STEM HEADER_NAME) if(NOT(HEADER_PATH STREQUAL "")) # generate rs from c headers if("--use-core" IN_LIST BINDGEN_CFLAGS) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs COMMAND ${BINDGEN_BIN} ${BINDGEN_CFLAGS} --depfile ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.d -o ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.tmp ${HEADER_PATH} COMMAND python -c "import sys;f=open\(sys.argv[1]+'.tmp','r'\).read\(\);open\(sys.argv[1],'w'\).write\('#![no_std]'+chr(10)+f\)" ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.tmp DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.d MAIN_DEPENDENCY ${RUST_TOP_SOURCE_FILE} VERBATIM ) else() add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs COMMAND ${BINDGEN_BIN} ${BINDGEN_CFLAGS} --depfile ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.d -o ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs ${HEADER_PATH} DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.d MAIN_DEPENDENCY ${RUST_TOP_SOURCE_FILE} VERBATIM ) endif() add_custom_target(c2rs_${TARGET_NAME}_src_tgt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs) # build crate from it so we can actually import it add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${HEADER_NAME}_bindgen.rlib COMMAND ${RUSTC_BIN} ${RUST_CFLAGS} --crate-type=rlib --emit=link,dep-info=${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${HEADER_NAME}_bindgen.rlib.d -o ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${HEADER_NAME}_bindgen.rlib ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${HEADER_NAME}_bindgen.rlib.d MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs VERBATIM ) add_custom_target(c2rs_${TARGET_NAME}_tgt DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${HEADER_NAME}_bindgen.rlib) add_library(c2rs_${TARGET_NAME} OBJECT $) list(APPEND RUST_CFLAGS "--extern" "${HEADER_NAME}_bindgen=${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${HEADER_NAME}_bindgen.rlib") set(MAIN_RUST_DEP "c2rs_${TARGET_NAME}_tgt") endif() endif() ### rust-to-C bindings (generate C headers from .rs, cbindgen) # cbindgen call add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${TARGET_NAME}.h COMMAND ${CBINDGEN_BIN} ${CBINDGEN_CFLAGS} -d --depfile ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${TARGET_NAME}.h.d -o ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${TARGET_NAME}.h ${RUST_TOP_SOURCE_FILE} DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${TARGET_NAME}.h.d MAIN_DEPENDENCY ${RUST_TOP_SOURCE_FILE} VERBATIM ) # make a virtual library for the header files add_library(rs2c_${TARGET_NAME} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${TARGET_NAME}.h) # add dependency to ensure build order and stuff target_link_libraries(${TOP_PROJECT} rs2c_${TARGET_NAME}) # and add include directories target_include_directories(${TOP_PROJECT} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/) ### rust compilation # the compile command add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj COMMAND ${RUSTC_BIN} ${RUST_CFLAGS} --emit=obj,dep-info=${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj.d --crate-type=staticlib -o ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj ${RUST_TOP_SOURCE_FILE} DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj.d # ensures the bindgen happens before the rustc compilation #DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/lib${TARGET_NAME}_bindgen.rlib DEPENDS ${MAIN_RUST_DEP} MAIN_DEPENDENCY ${RUST_TOP_SOURCE_FILE} VERBATIM ) # add a virtual library that can be reused and referred to (not possible with a bare add_custom_command()) add_library(${TARGET_NAME} OBJECT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj) # add generated object file from the library to the code to compile target_sources(${TOP_PROJECT} PUBLIC $) endfunction()