This commit is contained in:
Triss 2025-01-09 23:57:00 +01:00
commit d1a0fdc9dd
11 changed files with 494 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.zig-cache/
build/
cmake-build/

65
CMakeLists.txt Normal file
View File

@ -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")

61
README.md Normal file
View File

@ -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
```

View File

@ -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})

148
cmake/rust-obj.cmake Normal file
View 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()

79
cmake/zig-obj.cmake Normal file
View File

@ -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()

8
inc/clib.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef CLIB_H_
#define CLIB_H_
void print_my_int(int x);
#endif

9
src/clib.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdio.h>
#include "clib.h"
void print_my_int(int x) {
iprintf("the int is: %d\n", x);
}

30
src/main.c Normal file
View File

@ -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;
}

21
src/rustcode.rs Normal file
View File

@ -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 {}
}

8
src/zigcode.zig Normal file
View File

@ -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);
}