Hello,
I'm attempting to get pico-tflmicro bindings for the Raspberry Pi Pico. I've actually successfully created the bindings, and from what I can tell, my CMake build is working properly; however, for some weird reason, when I try running/building the model I'm getting the following errors...
rust-lld: error: undefined symbol: getModel
>>> referenced by hello_world.rs:44 (src/bin/hello_world.rs:44)
>>> /Users/bjorn/Desktop/pico-tflmicro-rs/examples/target/thumbv6m-none-eabi/debug/deps/hello_world-591127861856ae71.2uos94dh9jm3yjgu.rcgu.o:(hello_world::____embassy_main_task::_$u7b$$u7b$closure$u7d$$u7d$::h048d0f64de96e722)
rust-lld: error: undefined symbol: createEmptyResolver
>>> referenced by hello_world.rs:45 (src/bin/hello_world.rs:45)
>>> /Users/bjorn/Desktop/pico-tflmicro-rs/examples/target/thumbv6m-none-eabi/debug/deps/hello_world-591127861856ae71.2uos94dh9jm3yjgu.rcgu.o:(hello_world::____embassy_main_task::_$u7b$$u7b$closure$u7d$$u7d$::h048d0f64de96e722)
rust-lld: error: undefined symbol: addResolver
>>> referenced by hello_world.rs:46 (src/bin/hello_world.rs:46)
>>> /Users/bjorn/Desktop/pico-tflmicro-rs/examples/target/thumbv6m-none-eabi/debug/deps/hello_world-591127861856ae71.2uos94dh9jm3yjgu.rcgu.o:(hello_world::____embassy_main_task::_$u7b$$u7b$closure$u7d$$u7d$::h048d0f64de96e722)
rust-lld: error: undefined symbol: getInterpreter
>>> referenced by hello_world.rs:47 (src/bin/hello_world.rs:47)
>>> /Users/bjorn/Desktop/pico-tflmicro-rs/examples/target/thumbv6m-none-eabi/debug/deps/hello_world-591127861856ae71.2uos94dh9jm3yjgu.rcgu.o:(hello_world::____embassy_main_task::_$u7b$$u7b$closure$u7d$$u7d$::h048d0f64de96e722)
rust-lld: error: undefined symbol: getTensorInput
>>> referenced by hello_world.rs:49 (src/bin/hello_world.rs:49)
>>> /Users/bjorn/Desktop/pico-tflmicro-rs/examples/target/thumbv6m-none-eabi/debug/deps/hello_world-591127861856ae71.2uos94dh9jm3yjgu.rcgu.o:(hello_world::____embassy_main_task::_$u7b$$u7b$closure$u7d$$u7d$::h048d0f64de96e722)
This is weird, as the library I'm linking to statically has the following definitions.
wrapped.h
#ifndef WRAPPED_TF_HEADERS
#define WRAPPED_TF_HEADERS
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_log.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/c/common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct MicroInterpreter MicroInterpreter;
typedef struct Model Model;
typedef struct MicroMutableOpResolver MicroMutableOpResolver;
enum AddableResolver {
AddAbs,
AddAdd,
AddAddN,
AddArgMax,
AddArgMin,
AddAssignVariable,
AddAveragePool2D,
AddBatchMatMul,
AddBatchToSpaceNd,
AddBroadcastArgs,
AddBroadcastTo,
AddCallOnce,
AddCast,
AddCeil,
AddCircularBuffer,
AddConcatenation,
AddConv2D,
AddCos,
AddCumSum,
AddDelay,
AddDepthToSpace,
AddDepthwiseConv2D,
AddDequantize,
AddDetectionPostprocess,
AddDiv,
AddEmbeddingLookup,
AddEnergy,
AddElu,
AddEqual,
AddEthosU,
AddExp,
AddExpandDims,
AddFftAutoScale,
AddFill,
AddFilterBank,
AddFilterBankLog,
AddFilterBankSquareRoot,
AddFilterBankSpectralSubtraction,
AddFloor,
AddFloorDiv,
AddFloorMod,
AddFramer,
AddFullyConnected,
AddGather,
AddGatherNd,
AddGreater,
AddGreaterEqual,
AddHardSwish,
AddIf,
AddIrfft,
AddL2Normalization,
AddL2Pool2D,
AddLeakyRelu,
AddLess,
AddLessEqual,
AddLog,
AddLogicalAnd,
AddLogicalNot,
AddLogicalOr,
AddLogistic,
AddLogSoftmax,
AddMaximum,
AddMaxPool2D,
AddMirrorPad,
AddMean,
AddMinimum,
AddMul,
AddNeg,
AddNotEqual,
AddOverlapAdd,
AddPack,
AddPad,
AddPadV2,
AddPCAN,
AddPrelu,
AddQuantize,
AddReadVariable,
AddReduceMax,
AddRelu,
AddRelu6,
AddReshape,
AddResizeBilinear,
AddResizeNearestNeighbor,
AddRfft,
AddRound,
AddRsqrt,
AddSelectV2,
AddShape,
AddSin,
AddSlice,
AddSoftmax,
AddSpaceToBatchNd,
AddSpaceToDepth,
AddSplit,
AddSplitV,
AddSqueeze,
AddSqrt,
AddSquare,
AddSquaredDifference,
AddStridedSlice,
AddStacker,
AddSub,
AddSum,
AddSvdf,
AddTanh,
AddTransposeConv,
AddTranspose,
AddUnpack,
AddUnidirectionalSequenceLSTM,
AddVarHandle,
AddWhile,
AddWindow,
AddZerosLike
};
const Model* getModel(const void* buffer, size_t len);
void destroyModel(const Model* model);
MicroInterpreter* getInterpreter(const Model* model, MicroMutableOpResolver* resolver, int kTensorArenaSize);
void destroyInterpreter(MicroInterpreter* interpreter);
TfLiteStatus allocateTensors(MicroInterpreter* interpreter);
MicroMutableOpResolver* createEmptyResolver();
void destroyResolver(MicroMutableOpResolver* resolver);
TfLiteStatus addCustomResolver(MicroMutableOpResolver* resolver, char* name, TFLMRegistration* registration);
TfLiteStatus addResolver(MicroMutableOpResolver* resolver, AddableResolver resolverToAdd);
TfLiteTensor* getTensorInput(MicroInterpreter* interpreter, size_t n);
TfLiteStatus invokeInterpreter(MicroInterpreter* interpreter);
TfLiteTensor* getTensorOutput(MicroInterpreter* interpreter, size_t n);
#ifdef __cplusplus
}
#endif
#endif
wrapped.cpp
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_log.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/system_setup.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/c/common.h"
#include "wrapped.h"
extern "C" {
const Model* getModel(const void* buffer, size_t len) {
auto verifier = flatbuffers::Verifier((uint8_t *)buffer, len);
if (!::tflite::VerifyModelBuffer(verifier)) {
return NULL;
}
const tflite::Model* model = ::tflite::GetModel(buffer);
return reinterpret_cast<const Model*>(model);
}
void destroyModel(const Model* model) {
delete reinterpret_cast<const tflite::Model*>(model);
}
MicroInterpreter* getInterpreter(const Model* model, MicroMutableOpResolver* resolver, int kTensorArenaSize) {
const tflite::Model* tflite_model = reinterpret_cast<const tflite::Model*>(model);
tflite::MicroMutableOpResolver<128>* tflite_resolver = reinterpret_cast<tflite::MicroMutableOpResolver<128>*>(resolver);
uint8_t tensor_arena[kTensorArenaSize];
tflite::MicroInterpreter* interpreter = nullptr;
static tflite::MicroInterpreter static_interpreter(tflite_model, *tflite_resolver, tensor_arena, kTensorArenaSize);
interpreter = &static_interpreter;
return reinterpret_cast<MicroInterpreter*>(interpreter);
}
void destroyInterpreter(MicroInterpreter* interpreter) {
delete reinterpret_cast<tflite::MicroInterpreter*>(interpreter);
}
TfLiteStatus allocateTensors(MicroInterpreter* interpreter) {
tflite::MicroInterpreter* tflite_interpreter = reinterpret_cast<tflite::MicroInterpreter*>(interpreter);
if (tflite_interpreter == nullptr) {
printf("Got NULL!\n");
return kTfLiteError;
}
printf("Allocated Tensors!\n");
TfLiteStatus allocate_status = tflite_interpreter->AllocateTensors();
return allocate_status;
}
MicroMutableOpResolver* createEmptyResolver() {
static tflite::MicroMutableOpResolver<128>* resolver = new tflite::MicroMutableOpResolver<128>();
return reinterpret_cast<MicroMutableOpResolver*>(resolver);
}
void destroyResolver(MicroMutableOpResolver* resolver) {
delete reinterpret_cast<tflite::MicroMutableOpResolver<128>*>(resolver);
}
TfLiteStatus addCustomResolver(MicroMutableOpResolver* resolver, char* name, TFLMRegistration* registration) {
static tflite::MicroMutableOpResolver<128>* tflite_resolver = reinterpret_cast<tflite::MicroMutableOpResolver<128>*>(resolver);
return tflite_resolver->AddCustom(name, registration);
}
TfLiteStatus addResolver(MicroMutableOpResolver* resolver, AddableResolver resolverToAdd) {
static tflite::MicroMutableOpResolver<128>* tflite_resolver = reinterpret_cast<tflite::MicroMutableOpResolver<128>*>(resolver);
switch (resolverToAdd) {
case AddAbs:
return tflite_resolver->AddAbs();
break;
case AddAdd:
return tflite_resolver->AddAdd();
break;
case AddAddN:
return tflite_resolver->AddAddN();
break;
case AddArgMax:
return tflite_resolver->AddArgMax();
break;
case AddArgMin:
return tflite_resolver->AddArgMin();
break;
case AddAssignVariable:
return tflite_resolver->AddAssignVariable();
break;
case AddAveragePool2D:
return tflite_resolver->AddAveragePool2D();
break;
case AddBatchMatMul:
return tflite_resolver->AddBatchMatMul();
break;
case AddBatchToSpaceNd:
return tflite_resolver->AddBatchToSpaceNd();
break;
case AddBroadcastArgs:
return tflite_resolver->AddBroadcastArgs();
break;
case AddBroadcastTo:
return tflite_resolver->AddBroadcastTo();
break;
case AddCallOnce:
return tflite_resolver->AddCallOnce();
break;
case AddCast:
return tflite_resolver->AddCast();
break;
case AddCeil:
return tflite_resolver->AddCeil();
break;
case AddCircularBuffer:
return tflite_resolver->AddCircularBuffer();
break;
case AddConcatenation:
return tflite_resolver->AddConcatenation();
break;
case AddConv2D:
return tflite_resolver->AddConv2D();
break;
case AddCos:
return tflite_resolver->AddCos();
break;
case AddCumSum:
return tflite_resolver->AddCumSum();
break;
case AddDelay:
return tflite_resolver->AddDelay();
break;
case AddDepthToSpace:
return tflite_resolver->AddDepthToSpace();
break;
case AddDepthwiseConv2D:
return tflite_resolver->AddDepthwiseConv2D();
break;
case AddDequantize:
return tflite_resolver->AddDequantize();
break;
case AddDetectionPostprocess:
return tflite_resolver->AddDetectionPostprocess();
break;
case AddDiv:
return tflite_resolver->AddDiv();
break;
case AddEmbeddingLookup:
return tflite_resolver->AddEmbeddingLookup();
break;
case AddEnergy:
return tflite_resolver->AddEnergy();
break;
case AddElu:
return tflite_resolver->AddElu();
break;
case AddEqual:
return tflite_resolver->AddEqual();
break;
case AddEthosU:
return tflite_resolver->AddEthosU();
break;
case AddExp:
return tflite_resolver->AddExp();
break;
case AddExpandDims:
return tflite_resolver->AddExpandDims();
break;
case AddFftAutoScale:
return tflite_resolver->AddFftAutoScale();
break;
case AddFill:
return tflite_resolver->AddFill();
break;
case AddFilterBank:
return tflite_resolver->AddFilterBank();
break;
case AddFilterBankLog:
return tflite_resolver->AddFilterBankLog();
break;
case AddFilterBankSquareRoot:
return tflite_resolver->AddFilterBankSquareRoot();
break;
case AddFilterBankSpectralSubtraction:
return tflite_resolver->AddFilterBankSpectralSubtraction();
break;
case AddFloor:
return tflite_resolver->AddFloor();
break;
case AddFloorDiv:
return tflite_resolver->AddFloorDiv();
break;
case AddFloorMod:
return tflite_resolver->AddFloorMod();
break;
case AddFramer:
return tflite_resolver->AddFramer();
break;
case AddFullyConnected:
return tflite_resolver->AddFullyConnected();
break;
case AddGather:
return tflite_resolver->AddGather();
break;
case AddGatherNd:
return tflite_resolver->AddGatherNd();
break;
case AddGreater:
return tflite_resolver->AddGreater();
break;
case AddGreaterEqual:
return tflite_resolver->AddGreaterEqual();
break;
case AddHardSwish:
return tflite_resolver->AddHardSwish();
break;
case AddIf:
return tflite_resolver->AddIf();
break;
case AddIrfft:
return tflite_resolver->AddIrfft();
break;
case AddL2Normalization:
return tflite_resolver->AddL2Normalization();
break;
case AddL2Pool2D:
return tflite_resolver->AddL2Pool2D();
break;
case AddLeakyRelu:
return tflite_resolver->AddLeakyRelu();
break;
case AddLess:
return tflite_resolver->AddLess();
break;
case AddLessEqual:
return tflite_resolver->AddLessEqual();
break;
case AddLog:
return tflite_resolver->AddLog();
break;
case AddLogicalAnd:
return tflite_resolver->AddLogicalAnd();
break;
case AddLogicalNot:
return tflite_resolver->AddLogicalNot();
break;
case AddLogicalOr:
return tflite_resolver->AddLogicalOr();
break;
case AddLogistic:
return tflite_resolver->AddLogistic();
break;
case AddLogSoftmax:
return tflite_resolver->AddLogSoftmax();
break;
case AddMaximum:
return tflite_resolver->AddMaximum();
break;
case AddMaxPool2D:
return tflite_resolver->AddMaxPool2D();
break;
case AddMirrorPad:
return tflite_resolver->AddMirrorPad();
break;
case AddMean:
return tflite_resolver->AddMean();
break;
case AddMinimum:
return tflite_resolver->AddMinimum();
break;
case AddMul:
return tflite_resolver->AddMul();
break;
case AddNeg:
return tflite_resolver->AddNeg();
break;
case AddNotEqual:
return tflite_resolver->AddNotEqual();
break;
case AddOverlapAdd:
return tflite_resolver->AddOverlapAdd();
break;
case AddPack:
return tflite_resolver->AddPack();
break;
case AddPad:
return tflite_resolver->AddPad();
break;
case AddPadV2:
return tflite_resolver->AddPadV2();
break;
case AddPCAN:
return tflite_resolver->AddPCAN();
break;
case AddPrelu:
return tflite_resolver->AddPrelu();
break;
case AddQuantize:
return tflite_resolver->AddQuantize();
break;
case AddReadVariable:
return tflite_resolver->AddReadVariable();
break;
case AddReduceMax:
return tflite_resolver->AddReduceMax();
break;
case AddRelu:
return tflite_resolver->AddRelu();
break;
case AddRelu6:
return tflite_resolver->AddRelu6();
break;
case AddReshape:
return tflite_resolver->AddReshape();
break;
case AddResizeBilinear:
return tflite_resolver->AddResizeBilinear();
break;
case AddResizeNearestNeighbor:
return tflite_resolver->AddResizeNearestNeighbor();
break;
case AddRfft:
return tflite_resolver->AddRfft();
break;
case AddRound:
return tflite_resolver->AddRound();
break;
case AddRsqrt:
return tflite_resolver->AddRsqrt();
break;
case AddSelectV2:
return tflite_resolver->AddSelectV2();
break;
case AddShape:
return tflite_resolver->AddShape();
break;
case AddSin:
return tflite_resolver->AddSin();
break;
case AddSlice:
return tflite_resolver->AddSlice();
break;
case AddSoftmax:
return tflite_resolver->AddSoftmax();
break;
case AddSpaceToBatchNd:
return tflite_resolver->AddSpaceToBatchNd();
break;
case AddSpaceToDepth:
return tflite_resolver->AddSpaceToDepth();
break;
case AddSplit:
return tflite_resolver->AddSplit();
break;
case AddSplitV:
return tflite_resolver->AddSplitV();
break;
case AddSqueeze:
return tflite_resolver->AddSqueeze();
break;
case AddSqrt:
return tflite_resolver->AddSqrt();
break;
case AddSquare:
return tflite_resolver->AddSquare();
break;
case AddSquaredDifference:
return tflite_resolver->AddSquaredDifference();
break;
case AddStridedSlice:
return tflite_resolver->AddStridedSlice();
break;
case AddStacker:
return tflite_resolver->AddStacker();
break;
case AddSub:
return tflite_resolver->AddSub();
break;
case AddSum:
return tflite_resolver->AddSum();
break;
case AddSvdf:
return tflite_resolver->AddSvdf();
break;
case AddTanh:
return tflite_resolver->AddTanh();
break;
case AddTransposeConv:
return tflite_resolver->AddTransposeConv();
break;
case AddTranspose:
return tflite_resolver->AddTranspose();
break;
case AddUnpack:
return tflite_resolver->AddUnpack();
break;
case AddUnidirectionalSequenceLSTM:
return tflite_resolver->AddUnidirectionalSequenceLSTM();
break;
case AddVarHandle:
return tflite_resolver->AddVarHandle();
break;
case AddWhile:
return tflite_resolver->AddWhile();
break;
case AddWindow:
return tflite_resolver->AddWindow();
break;
case AddZerosLike:
return tflite_resolver->AddZerosLike();
break;
default:
return kTfLiteError;
}
}
TfLiteTensor* getTensorInput(MicroInterpreter* interpreter, size_t n) {
tflite::MicroInterpreter* tflite_interpreter = reinterpret_cast<tflite::MicroInterpreter*>(interpreter);
if (tflite_interpreter == nullptr) {
return NULL;
}
return tflite_interpreter->input(n);
}
TfLiteStatus invokeInterpreter(MicroInterpreter* interpreter) {
tflite::MicroInterpreter* tflite_interpreter = reinterpret_cast<tflite::MicroInterpreter*>(interpreter);
if (tflite_interpreter == nullptr) {
return kTfLiteError;
}
return tflite_interpreter->Invoke();
}
TfLiteTensor* getTensorOutput(MicroInterpreter* interpreter, size_t n) {
tflite::MicroInterpreter* tflite_interpreter = reinterpret_cast<tflite::MicroInterpreter*>(interpreter);
if (tflite_interpreter == nullptr) {
return NULL;
}
return tflite_interpreter->output(n);
}
}
With this CMakelists.txt
cmake_minimum_required(VERSION 3.12)
project(exe C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
add_library(pico-tflmicro-wrapped STATIC)
target_include_directories(pico-tflmicro-wrapped
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src
)
set_target_properties(
pico-tflmicro-wrapped
PROPERTIES
COMPILE_FLAGS -Os
COMPILE_FLAGS -fno-rtti
COMPILE_FLAGS -fno-exceptions
COMPILE_FLAGS -fno-threadsafe-statics
COMPILE_FLAGS -nostdlib
)
target_link_libraries(
pico-tflmicro-wrapped
pico-tflmicro
)
target_sources(pico-tflmicro
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/src/wrapped.cpp
${CMAKE_CURRENT_LIST_DIR}/src/wrapped.h
)
add_executable(exe "")
target_include_directories(exe
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/.
)
set_target_properties(
exe
PROPERTIES
COMPILE_FLAGS -fno-rtti
COMPILE_FLAGS -fno-exceptions
COMPILE_FLAGS -fno-threadsafe-statics
COMPILE_FLAGS -nostdlib
)
target_sources(exe
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/empty.c
)
target_link_libraries(
exe
pico-tflmicro-wrapped
)
And this build.rs
// Build procedure is based on esp-idf-sys: https://github.com/esp-rs/esp-idf-sys/blob/155299bde700905fd2ddb040d7a13fb73559ac68/build/native/cargo_driver.rs
use std::path::PathBuf;
use anyhow::{Context, Error};
use embuild::build::LinkArgsBuilder;
use embuild::cmake::file_api::codemodel::target::CompileGroup;
use embuild::cmake::file_api::codemodel::Language;
use embuild::cmake::file_api::{ObjKind, Query};
use embuild::cmake::Config;
use embuild::{bindgen, cargo};
#[allow(unused_macros)]
macro_rules! p {
($($tokens: tt)*) => {
println!("cargo:warning={}", format!($($tokens)*))
}
}
pub fn get_sysroot(target: &str) -> Result<String, anyhow::Error> {
let mut sysroot = cc::Build::new();
let sysroot = sysroot
.target(target)
.get_compiler()
.to_command()
.arg("--print-sysroot")
.output()
.context("Couldn't find target GCC executable.")
.and_then(|output| {
if output.status.success() {
Ok(String::from_utf8(output.stdout)?)
} else {
panic!("Couldn't read output from GCC.")
}
})?;
Ok(sysroot.trim().to_string())
}
fn generate_bindings(compile_group: &CompileGroup, compiler: &PathBuf, target: &str) {
let cpp_headers = get_cpp_headers(compiler).expect("Couldn't find headers");
let sysroot = get_sysroot(target).expect("Failed to get sysroot");
let binder = bindgen::Factory::from_cmake(compile_group)
.unwrap()
.with_linker(compiler)
.with_sysroot(sysroot);
let mut binder = binder
.builder()
.unwrap()
.clang_arg(format!("-I/submodules/pico-tflmicro/src/tensorflow"))
.derive_eq(true)
.use_core()
.clang_arg("-xc++")
.clang_arg("-std=c++11")
.allowlist_recursively(true)
.prepend_enum_name(false)
.impl_debug(true)
.layout_tests(false)
.enable_cxx_namespaces()
.derive_default(true)
.size_t_is_usize(true)
.ctypes_prefix("cty")
// Types - blacklist
.blocklist_type("std")
.derive_partialeq(true)
.derive_eq(true)
.detect_include_paths(false);
p!("cpp headers: {:?}", cpp_headers);
for include in cpp_headers {
binder = binder.clang_arg(format!(
"-I{}",
include.into_os_string().into_string().unwrap()
));
}
let wrapper_header = "submodules/pico-tflmicro/wrapped/src/wrapped.h";
println!("cargo:rerun-if-changed={}", wrapper_header);
let _ = binder
.allowlist_file(wrapper_header)
.header(wrapper_header)
.generate()
.unwrap()
.write_to_file("src/bindings.rs");
}
pub fn get_compiler(target: &str) -> String {
let mut compiler = cc::Build::new();
let compiler = compiler.target(target).get_compiler();
let compiler = compiler.path();
compiler
.to_str()
.expect(&format!("Failed to find compiler for target '{}'", target))
.to_string()
}
pub fn get_cpp_headers(compiler: &PathBuf) -> Result<Vec<PathBuf>, anyhow::Error> {
let mut cpp_headers = cc::Build::new();
cpp_headers
.cpp(true)
.no_default_flags(true)
.compiler(compiler)
.get_compiler()
.to_command()
.arg("-E")
.arg("-Wp,-v")
.arg("-xc++")
.arg(".")
.output()
.context("Couldn't find target GCC executable.")
.and_then(|output| {
// We have to scrape the gcc console output to find where
// the c++ headers are. If we only needed the c headers we
// could use `--print-file-name=include` but that's not
// possible.
let gcc_out = String::from_utf8(output.stderr)?;
// Scrape the search paths
let search_start = gcc_out.find("search starts here").unwrap();
let search_paths: Vec<PathBuf> = gcc_out[search_start..]
.split('\n')
.map(|p| PathBuf::from(p.trim()))
.filter(|path| path.exists())
.collect();
Ok(search_paths)
})
}
fn main() {
let target = "thumbv6m-none-eabi";
let cmake_build_dir = cargo::out_dir().join("build");
p!("cmake build dir: {}", cmake_build_dir.display());
// Set CMake to output API files https://cmake.org/cmake/help/git-stage/manual/cmake-file-api.7.html
let query = Query::new(
&cmake_build_dir,
"cargo",
&[ObjKind::Codemodel, ObjKind::Toolchains, ObjKind::Cache],
)
.unwrap();
// Build C part
let dst = Config::new("submodules/pico-tflmicro")
.generator("Ninja")
.build_target("exe")
.build();
p!("dst: {:?}", dst.display());
println!("cargo:rustc-link-search={}/{}", cmake_build_dir.display(), "wrapped");
println!("cargo:rustc-link-lib=static=pico-tflmicro-wrapped");
// Retrieve information from CMake API files
let replies = query.get_replies().unwrap();
let codemodel = replies.get_codemodel().unwrap();
let exe_target = codemodel
.into_first_conf()
.get_target("exe")
.unwrap()
.unwrap();
let link = exe_target.link.unwrap();
let compile_group = exe_target
.compile_groups
.get(0)
.expect("Failed to get compile group");
let link_args = LinkArgsBuilder::try_from(&link)
.unwrap()
.linker("arm-none-eabi-gcc")
.working_directory(&cmake_build_dir)
.build()
.unwrap();
p!("linker args {:?}", link_args);
// link_args.output();
let compiler = replies.get_toolchains();
let compiler = compiler
.and_then(|mut t| {
t.take(Language::C)
.ok_or_else(|| Error::msg("No C toolchain"))
})
.and_then(|t| {
t.compiler
.path
.ok_or_else(|| Error::msg("No compiler path set"))
})
.context("Could not determine the compiler from cmake")
.unwrap();
// #[cfg(feature = "generate_bindings")]
generate_bindings(compile_group, &compiler, target);
}
Please note that these errors will be generated even if you do not have a Raspberry Pi Pico to build.
Here is the code I've been developing for pico-tflmicro-rs. If you want to test the code just follow the instructions in the README.md.
Any help would be greatly appreciated!!