183 lines
9.9 KiB
CMake
183 lines
9.9 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 ""))
|
|
set(_BINDGEN_CFLAGS
|
|
$<TARGET_PROPERTY:${TOP_PROJECT},COMPILE_OPTIONS>
|
|
$<LIST:TRANSFORM,$<LIST:SORT,$<TARGET_PROPERTY:${TOP_PROJECT},COMPILE_DEFINITIONS>>,PREPEND,-D>
|
|
$<LIST:TRANSFORM,$<TARGET_PROPERTY:${TOP_PROJECT},INCLUDE_DIRECTORIES>,PREPEND,-isystem>
|
|
# $<LIST:TRANSFORM,$<LIST:SORT,$<TARGET_PROPERTY:${TOP_PROJECT},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>>,PREPEND,-isystem>
|
|
)
|
|
|
|
# preprocess C headers with top_project C compiler -- might use different system dirs & compatibility stuff & whatnot
|
|
add_custom_command(
|
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h
|
|
# yeah, need two commands........
|
|
COMMAND ${CMAKE_C_COMPILER} ${_BINDGEN_CFLAGS} -E -MM -MF ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h.d ${HEADER_PATH}
|
|
COMMAND ${CMAKE_C_COMPILER} ${_BINDGEN_CFLAGS} -E -o ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h ${HEADER_PATH}
|
|
DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h.d
|
|
MAIN_DEPENDENCY ${HEADER_PATH}
|
|
VERBATIM
|
|
COMMAND_EXPAND_LISTS
|
|
)
|
|
add_custom_target(c2rs_${TARGET_NAME}_src_tgt_hdr_pre DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h)
|
|
|
|
# generate rs from c headers
|
|
if(DEFINED RUST_TARGET)
|
|
# necessary for bindgen itself, but not for preprocessor stuff above
|
|
set(_BINDGEN_CFLAGS -target ${RUST_TARGET}) #${_BINDGEN_CFLAGS}
|
|
endif()
|
|
set(_BINDGEN_COMMAND_START ${BINDGEN_BIN} ${BINDGEN_CFLAGS}
|
|
--depfile ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.d
|
|
${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h
|
|
)
|
|
# need to prepend the generated rust source with some directives to not make the compiler blow up
|
|
set(_PYTHON_SCRIPT "import sys\;f=open\(sys.argv[-1]+'.tmp','r'\).read\(\)\;open\(sys.argv[-1],'w'\).write\('#\![allow(non_camel_case_types,non_snake_case,nonstandard_style)]'+chr(10)+f\)")
|
|
if("--use-core" IN_LIST BINDGEN_CFLAGS)
|
|
set(_PYTHON_SCRIPT "import sys\;f=open\(sys.argv[-1]+'.tmp','r'\).read\(\)\;open\(sys.argv[-1],'w'\).write\('#\![no_std]'+chr(10)+'#\![allow(non_camel_case_types,non_snake_case,nonstandard_style)]'+chr(10)+f\)")
|
|
endif()
|
|
add_custom_command(
|
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs
|
|
COMMAND ${_BINDGEN_COMMAND_START} -o ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen.rs.tmp -- ${_BINDGEN_CFLAGS}
|
|
COMMAND python -c ${_PYTHON_SCRIPT} ${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 ${CMAKE_CURRENT_BINARY_DIR}/generated/rust_${TARGET_NAME}/${HEADER_NAME}_bindgen_pre.h
|
|
VERBATIM
|
|
# COMMAND_EXPAND_LISTS
|
|
)
|
|
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 compilation
|
|
set(_SHELL_SCRIPT "${CMAKE_AR} vd \"${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a.tmp\" \"$(${CMAKE_AR} t ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a.tmp | grep \"lib${TARGET_NAME}\.${TARGET_NAME}\..*\.o\")\"")
|
|
# the compile command
|
|
add_custom_command(
|
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a
|
|
COMMAND ${RUSTC_BIN} ${RUST_CFLAGS} --emit=link,dep-info=${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj.d,obj=${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj --crate-type=staticlib -o ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a.tmp ${RUST_TOP_SOURCE_FILE}
|
|
# remove object file itself from the static library, so two-way references are possible.
|
|
# now the static library only contains dependency code from core etc
|
|
COMMAND bash -c ${_SHELL_SCRIPT}
|
|
COMMAND mv ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a.tmp ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a
|
|
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a.tmp
|
|
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_library(rdep_${TARGET_NAME} OBJECT ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a)
|
|
# add generated object file from the library to the code to compile
|
|
target_sources(${TOP_PROJECT} PUBLIC $<TARGET_PROPERTY:${TARGET_NAME},SOURCES>)
|
|
# also make top project depend on rdep, so stuff from eg the core crate will also get linked in
|
|
target_link_libraries(${TOP_PROJECT} ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a)
|
|
|
|
### 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 ${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET_NAME}.a
|
|
#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) # ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj)
|
|
|
|
# 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}/)
|
|
endfunction()
|
|
|