# ############################################################################## # cmake/nuttx_add_rust.cmake # # Licensed to the Apache Software Foundation (ASF) under one or more contributor # license agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. The ASF licenses this # file to you under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. # # ############################################################################## include(nuttx_parse_function_args) # ~~~ # Convert architecture type to Rust NuttX target # # Supported architectures: # - armv7a: armv7a-nuttx-eabi, armv7a-nuttx-eabihf # - thumbv6m: thumbv6m-nuttx-eabi # - thumbv7a: thumbv7a-nuttx-eabi, thumbv7a-nuttx-eabihf # - thumbv7m: thumbv7m-nuttx-eabi # - thumbv7em: thumbv7em-nuttx-eabihf # - thumbv8m.main: thumbv8m.main-nuttx-eabi, thumbv8m.main-nuttx-eabihf # - thumbv8m.base: thumbv8m.base-nuttx-eabi, thumbv8m.base-nuttx-eabihf # - riscv32: riscv32imc/imac/imafc-unknown-nuttx-elf # - riscv64: riscv64imac/imafdc-unknown-nuttx-elf # - x86: i686-unknown-nuttx # - x86_64: x86_64-unknown-nuttx-macho for sim on macOS, # x86_64-unknown-nuttx otherwise # - aarch64: aarch64-unknown-nuttx-macho for sim on macOS, # aarch64-unknown-nuttx otherwise # # Inputs: # ARCHTYPE - Architecture type (e.g. thumbv7m, riscv32) # ABITYPE - ABI type (e.g. eabi, eabihf) # CPUTYPE - CPU type (e.g. cortex-m4, sifive-e20) # # Output: # OUTPUT - Rust target triple (e.g. riscv32imac-unknown-nuttx-elf, # thumbv7m-nuttx-eabi, thumbv7em-nuttx-eabihf) # ~~~ function(nuttx_rust_target_triple ARCHTYPE ABITYPE CPUTYPE OUTPUT) if(ARCHTYPE STREQUAL "x86_64") if(CONFIG_ARCH_SIM AND CONFIG_HOST_MACOS) set(TARGET_TRIPLE "${PROJECT_SOURCE_DIR}/tools/x86_64-unknown-nuttx-macho.json") else() set(TARGET_TRIPLE "${PROJECT_SOURCE_DIR}/tools/x86_64-unknown-nuttx.json") endif() elseif(ARCHTYPE STREQUAL "x86") set(TARGET_TRIPLE "${PROJECT_SOURCE_DIR}/tools/i486-unknown-nuttx.json") elseif(ARCHTYPE STREQUAL "aarch64") if(CONFIG_ARCH_SIM AND CONFIG_HOST_MACOS) set(TARGET_TRIPLE "${PROJECT_SOURCE_DIR}/tools/aarch64-unknown-nuttx-macho.json") else() set(TARGET_TRIPLE "${PROJECT_SOURCE_DIR}/tools/aarch64-unknown-nuttx.json") endif() elseif(ARCHTYPE MATCHES "thumb") if(ARCHTYPE MATCHES "thumbv8m") # Extract just the base architecture type (thumbv8m.main or thumbv8m.base) if(ARCHTYPE MATCHES "thumbv8m.main") set(ARCH_BASE "thumbv8m.main") elseif(ARCHTYPE MATCHES "thumbv8m.base") set(ARCH_BASE "thumbv8m.base") else() # Otherwise determine if we should use thumbv8m.main or thumbv8m.base # based on CPU type if(CPUTYPE MATCHES "cortex-m23") set(ARCH_BASE "thumbv8m.base") else() set(ARCH_BASE "thumbv8m.main") endif() endif() set(TARGET_TRIPLE "${ARCH_BASE}-nuttx-${ABITYPE}") else() set(TARGET_TRIPLE "${ARCHTYPE}-nuttx-${ABITYPE}") endif() elseif(ARCHTYPE STREQUAL "riscv32") if(CPUTYPE STREQUAL "sifive-e20") set(TARGET_TRIPLE "riscv32imc-unknown-nuttx-elf") elseif(CPUTYPE STREQUAL "sifive-e31") set(TARGET_TRIPLE "riscv32imac-unknown-nuttx-elf") elseif(CPUTYPE STREQUAL "sifive-e76") set(TARGET_TRIPLE "riscv32imafc-unknown-nuttx-elf") else() set(TARGET_TRIPLE "riscv32imc-unknown-nuttx-elf") endif() elseif(ARCHTYPE STREQUAL "riscv64") if(CPUTYPE STREQUAL "sifive-s51") set(TARGET_TRIPLE "riscv64imac-unknown-nuttx-elf") elseif(CPUTYPE STREQUAL "sifive-u54") set(TARGET_TRIPLE "riscv64imafdc-unknown-nuttx-elf") else() set(TARGET_TRIPLE "riscv64imac-unknown-nuttx-elf") endif() endif() if(NOT TARGET_TRIPLE) message( FATAL_ERROR "Unsupported Rust target: LLVM_ARCHTYPE=${ARCHTYPE}, LLVM_ABITYPE=${ABITYPE}, LLVM_CPUTYPE=${CPUTYPE}" ) endif() set(${OUTPUT} ${TARGET_TRIPLE} PARENT_SCOPE) endfunction() # ~~~ # nuttx_add_rust # # Description: # Build a Rust crate and add it as a static library to the NuttX build system # # Example: # nuttx_add_rust( # CRATE_NAME # hello # CRATE_PATH # ${CMAKE_CURRENT_SOURCE_DIR}/hello # FEATURES # sim # ) # ~~~ function(nuttx_add_rust) # parse arguments into variables nuttx_parse_function_args( FUNC nuttx_add_rust ONE_VALUE CRATE_NAME CRATE_PATH MULTI_VALUE FEATURES REQUIRED CRATE_NAME CRATE_PATH ARGN ${ARGN}) # Determine build profile based on CONFIG_DEBUG_FULLOPT if(CONFIG_DEBUG_FULLOPT) set(RUST_PROFILE_FLAG "--release") set(RUST_PROFILE "release") set(RUST_PANIC_FLAGS "-Zunstable-options -Cpanic=immediate-abort") else() set(RUST_PROFILE_FLAG "") set(RUST_PROFILE "debug") set(RUST_PANIC_FLAGS "") endif() foreach(feature ${FEATURES}) list(APPEND RUST_FEATURE_FLAGS --features ${feature}) endforeach() # Get the Rust target triple nuttx_rust_target_triple(${LLVM_ARCHTYPE} ${LLVM_ABITYPE} ${LLVM_CPUTYPE} RUST_TARGET) # Get binary directory path using target triple base name if it's a JSON file if(RUST_TARGET MATCHES ".json$") get_filename_component(TARGET_BASE ${RUST_TARGET} NAME_WE) else() set(TARGET_BASE ${RUST_TARGET}) endif() set(RUST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CRATE_NAME}/target) set(RUST_LIB_PATH ${RUST_BUILD_DIR}/${TARGET_BASE}/${RUST_PROFILE}/lib${CRATE_NAME}.a) # Create build directory file(MAKE_DIRECTORY ${RUST_BUILD_DIR}) # Collect Rust source files and manifests as dependencies so that changes in # the crate trigger a rebuild via CMake/Ninja. file( GLOB_RECURSE RUST_CRATE_SOURCES CONFIGURE_DEPENDS "${CRATE_PATH}/Cargo.toml" "${CRATE_PATH}/Cargo.lock" "${CRATE_PATH}/build.rs" "${CRATE_PATH}/src/*.rs" "${CRATE_PATH}/src/**/*.rs") # Add a custom command to build the Rust crate add_custom_command( OUTPUT ${RUST_LIB_PATH} COMMAND ${CMAKE_COMMAND} -E env NUTTX_INCLUDE_DIR=${PROJECT_SOURCE_DIR}/include:${CMAKE_BINARY_DIR}/include:${CMAKE_BINARY_DIR}/include/arch RUSTFLAGS=${RUST_PANIC_FLAGS} cargo build ${RUST_PROFILE_FLAG} -Zbuild-std=std,panic_abort -Zjson-target-spec --manifest-path ${CRATE_PATH}/Cargo.toml --target ${RUST_TARGET} --target-dir ${RUST_BUILD_DIR} ${RUST_FEATURE_FLAGS} DEPENDS ${RUST_CRATE_SOURCES} COMMENT "Building Rust crate ${CRATE_NAME}" VERBATIM) # Add a custom target that depends on the built library add_custom_target(${CRATE_NAME}_build ALL DEPENDS ${RUST_LIB_PATH}) # Add imported library target add_library(${CRATE_NAME} STATIC IMPORTED GLOBAL) set_target_properties(${CRATE_NAME} PROPERTIES IMPORTED_LOCATION ${RUST_LIB_PATH}) # Add the Rust library to NuttX build nuttx_add_extra_library(${RUST_LIB_PATH}) # Ensure the Rust library is built before linking add_dependencies(${CRATE_NAME} ${CRATE_NAME}_build) endfunction()