rpsdk-mix-c-rs-zig/cmake/rust-obj.cmake

149 lines
7.2 KiB
CMake

# =============================================================================
# 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 $<TARGET_PROPERTY:c2rs_${TARGET_NAME}_tgt,SOURCES>)
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 $<TARGET_PROPERTY:${TARGET_NAME},SOURCES>)
endfunction()