initial
This commit is contained in:
commit
d1a0fdc9dd
|
@ -0,0 +1,3 @@
|
|||
.zig-cache/
|
||||
build/
|
||||
cmake-build/
|
|
@ -0,0 +1,65 @@
|
|||
set(PROJECT "rpsdk-mix-c-rs-zig")
|
||||
|
||||
option(PICO_NO_FLASH "Disable writing the compiled program to flash, and only load it to RAM. Useful for testing, but not much else (ON by default)." OFF)
|
||||
option(PICO_COPY_TO_RAM "Run all code in RAM, while the program is also stored on flash. On bootup, everything will be copied to RAM (OFF by default)." OFF)
|
||||
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pico_sdk_import.cmake)
|
||||
|
||||
project(${PROJECT})
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(${PROJECT})
|
||||
|
||||
pico_enable_stdio_uart(${PROJECT} 0)
|
||||
pico_enable_stdio_usb(${PROJECT} 1)
|
||||
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/clib.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/inc/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT}
|
||||
pico_stdlib pico_unique_id hardware_pio hardware_dma hardware_uart
|
||||
hardware_pwm cmsis_core pico_multicore
|
||||
pico_stdlib
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(${PROJECT})
|
||||
|
||||
### hacks start here
|
||||
|
||||
set(RUST_TARGET thumbv6m-none-eabi)
|
||||
set(RUST_CPU cortex-m0plus)
|
||||
list(APPEND BINDGEN_CFLAGS "--use-core" "--rust-edition=2021")
|
||||
list(APPEND RUST_CFLAGS "--edition=2021")
|
||||
include(cmake/rust-obj.cmake)
|
||||
add_rust_object(${PROJECT}
|
||||
# rust top level module
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rustcode.rs
|
||||
# optional: path to header file to use for c2rs bindgen stuff (currently limited to one, sorry)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/inc/clib.h
|
||||
)
|
||||
|
||||
set(ZIG_TARGET thumb-freestanding-gnueabi)
|
||||
set(ZIG_CPU cortex_m0plus)
|
||||
list(APPEND ZIG_CFLAGS "-ffunction-sections" "-fdata-sections")
|
||||
include(cmake/zig-obj.cmake)
|
||||
add_zig_object(${PROJECT}
|
||||
# zig top level module
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/zigcode.zig
|
||||
)
|
||||
|
||||
### hacks end here
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type -Werror=aggressive-loop-optimizations")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--cref")
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
# rpsdk-mix-c-rs-zig
|
||||
|
||||
Mix C, Rust and Zig in a Raspberry Pico SDK (CMake) project.
|
||||
|
||||
Yeah.
|
||||
|
||||
## Usage
|
||||
|
||||
Don't.
|
||||
|
||||
Other than that,
|
||||
|
||||
### Add Rust code to your project
|
||||
|
||||
```cmake
|
||||
set(RUST_TARGET thumbv6m-none-eabi)
|
||||
set(RUST_CPU cortex-m0plus)
|
||||
list(APPEND BINDGEN_CFLAGS "--use-core" "--rust-edition=2021")
|
||||
list(APPEND RUST_CFLAGS "--edition=2021")
|
||||
include(cmake/rust-obj.cmake)
|
||||
add_rust_object(${PROJECT}
|
||||
# rust top level module
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rustcode.rs
|
||||
# optional: path to header file to use for c2rs bindgen stuff (currently limited to one, sorry)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/inc/clib.h
|
||||
)
|
||||
```
|
||||
|
||||
Bindgen and CBindgen are used automatically to generate C headers from the Rust
|
||||
code, and vice versa.
|
||||
|
||||
### Add Zig code to your project
|
||||
|
||||
```cmake
|
||||
set(ZIG_TARGET thumb-freestanding-gnueabi)
|
||||
set(ZIG_CPU cortex_m0plus)
|
||||
list(APPEND ZIG_CFLAGS "-ffunction-sections" "-fdata-sections")
|
||||
include(cmake/zig-obj.cmake)
|
||||
add_zig_object(${PROJECT}
|
||||
# zig top level module
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/zigcode.zig
|
||||
)
|
||||
```
|
||||
|
||||
## Known issues and limitations
|
||||
|
||||
* Sometimes, compilation fails with `rustc` failing to copy an object file to
|
||||
the destination path. Reason for this is unknown, just retrying the build
|
||||
seems to work.
|
||||
* References between Zig and Rust code aren't really possible automatically
|
||||
(can't generate Rust via Bindgen from Zig-generated headers, or include
|
||||
Bindgen-generated C headers in Zig code). This is because Zig can't generate
|
||||
these headers without also compiling the code.
|
||||
* Only one C header can be Bindgen'ed per Rust "root" module/crate (one crate
|
||||
gets compiled into an object file and included in the main link).
|
||||
|
||||
## License
|
||||
|
||||
```
|
||||
be gay, do crimes, death to america
|
||||
```
|
|
@ -0,0 +1,62 @@
|
|||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
# =============================================================================
|
||||
# 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()
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
# =============================================================================
|
||||
# first, get some info about the compiler
|
||||
|
||||
# get zig binary
|
||||
if(NOT DEFINED ZIG_BIN OR ZIG_BIN STREQUAL "")
|
||||
find_program(ZIG_BIN zig REQUIRED)
|
||||
endif()
|
||||
set(ZIG_BIN ${ZIG_BIN} CACHE FILEPATH "Zig command")
|
||||
message(NOTICE "-- ZIG_BIN is ${ZIG_BIN}")
|
||||
|
||||
# get zig libdir (for zig.h)
|
||||
execute_process(
|
||||
COMMAND ${ZIG_BIN} env
|
||||
OUTPUT_VARIABLE ZIG_LIBDIR
|
||||
)
|
||||
string(JSON ZIG_LIBDIR GET ${ZIG_LIBDIR} lib_dir)
|
||||
set(ZIG_LIBDIR ${ZIG_LIBDIR} CACHE PATH "from `zig env`")
|
||||
|
||||
# =============================================================================
|
||||
# set compile options
|
||||
|
||||
if(DEFINED ZIG_TARGET)
|
||||
list(APPEND ZIG_CFLAGS "-target" "${ZIG_TARGET}")
|
||||
endif()
|
||||
if(DEFINED ZIG_CPU)
|
||||
list(APPEND ZIG_CFLAGS "-mcpu=${ZIG_CPU}")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED ZIG_OPTLEVEL)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
set(ZIG_OPTLEVEL ReleaseFast)
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo)
|
||||
set(ZIG_OPTLEVEL ReleaseSafe)
|
||||
elseif(CMAKE_BUILD_TYPE STREQUAL MinSizeRel)
|
||||
set(ZIG_OPTLEVEL ReleaseSmall)
|
||||
else()
|
||||
# also the Debug case
|
||||
set(ZIG_OPTLEVEL ${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND ZIG_CFLAGS "-O" "${ZIG_OPTLEVEL}")
|
||||
|
||||
# =============================================================================
|
||||
# now define the macro we'll be using
|
||||
|
||||
function(add_zig_object TOP_PROJECT ZIG_TOP_SOURCE_FILE)
|
||||
if(ARGC GREATER 2)
|
||||
set(TARGET_NAME ${ARGV2})
|
||||
else()
|
||||
cmake_path(GET ZIG_TOP_SOURCE_FILE STEM TARGET_NAME)
|
||||
endif()
|
||||
|
||||
# directory the header file will be in
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated/zig_${TARGET_NAME}/)
|
||||
# the compile command
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj
|
||||
# TODO: when is this generator expression evaluated??? (matters for direct rust<->zig references)
|
||||
COMMAND ${ZIG_BIN} build-obj ${ZIG_CFLAGS} -femit-bin=${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj -femit-h=${CMAKE_CURRENT_BINARY_DIR}/generated/zig_${TARGET_NAME}/${TARGET_NAME}.h "$<LIST:TRANSFORM,$<TARGET_PROPERTY:${TOP_PROJECT},INCLUDE_DIRECTORIES>,PREPEND,-I>" ${ZIG_TOP_SOURCE_FILE}
|
||||
# ${TARGET_NAME}.obj.o is a bug in zig currently
|
||||
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.obj.o ${CMAKE_CURRENT_BINARY_DIR}/generated/zig_${TARGET_NAME}/${TARGET_NAME}.h
|
||||
MAIN_DEPENDENCY ${ZIG_TOP_SOURCE_FILE}
|
||||
DEPENDS ${ZIG_TOP_SOURCE_FILE}
|
||||
#DEPFILE ${TARGET_NAME}.obj.d # no way to generate it :/
|
||||
VERBATIM
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
# 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>)
|
||||
# add directory of zig.h and the generated header to the top project's stuff
|
||||
target_include_directories(${TOP_PROJECT} PRIVATE ${ZIG_LIBDIR} ${CMAKE_CURRENT_BINARY_DIR}/generated/zig_${TARGET_NAME}/)
|
||||
# work around https://github.com/ziglang/zig/issues/16730
|
||||
target_compile_definitions(${TOP_PROJECT} PUBLIC ZIG_TARGET_MAX_INT_ALIGNMENT="\(sizeof\(intmax_t\)\)")
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#ifndef CLIB_H_
|
||||
#define CLIB_H_
|
||||
|
||||
void print_my_int(int x);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "clib.h"
|
||||
|
||||
void print_my_int(int x) {
|
||||
iprintf("the int is: %d\n", x);
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/stdio.h>
|
||||
#include <pico/time.h>
|
||||
|
||||
|
||||
// same filenames as .rs/.zig files, but with a .h extension of course
|
||||
#include "rustcode.h"
|
||||
#include "zigcode.h"
|
||||
|
||||
int main() {
|
||||
busy_wait_ms(16);
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
iprintf("[main] hello world from C!\n");
|
||||
|
||||
iprintf("[main] call into rust: ");
|
||||
add_and_print(413, 612);
|
||||
|
||||
iprintf("[main] call into zig: ");
|
||||
mul_and_print(20, 25);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#![no_std]
|
||||
|
||||
use clib_bindgen; // c header file basename + _bindgen suffix
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn add_and_print(a: i32, b: i32) {
|
||||
clib_bindgen::print_my_int(a + b);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn non_existent_fn();
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
pub fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
unsafe {
|
||||
non_existent_fn(); // makes sure to cause linker errors if the rust code would ever
|
||||
// actually use this function
|
||||
}
|
||||
loop {}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
const c = @cImport({
|
||||
@cInclude("clib.h");
|
||||
});
|
||||
|
||||
export fn mul_and_print(a: i32, b: i32) void {
|
||||
c.print_my_int(a * b);
|
||||
}
|
Loading…
Reference in New Issue