initial rust skeleton project. Probably doesn't work.
parent
cb346d25ff
commit
992e83d8ea
|
|
@ -30,6 +30,7 @@ option(LIBICSNEO_ENABLE_TCP "Enable devices which communicate over TCP" OFF)
|
||||||
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
|
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
|
||||||
|
|
||||||
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
|
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
|
||||||
|
option(LIBICSNEO_ENABLE_BINDINGS_RUST "Enable Rust library" OFF)
|
||||||
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,18 @@
|
||||||
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
|
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
|
||||||
add_subdirectory(python)
|
add_subdirectory(python)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LIBICSNEO_ENABLE_BINDINGS_RUST)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
Corrosion
|
||||||
|
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||||
|
GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(Corrosion)
|
||||||
|
|
||||||
|
corrosion_import_crate(MANIFEST_PATH ${CMAKE_SOURCE_DIR}/bindings/rust/icsneors/Cargo.toml)
|
||||||
|
else()
|
||||||
|
message(STATUS "Not building rust bindings")
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# RustRover
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "icsneors"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
static = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bindgen = "0.71.1"
|
||||||
|
path-clean = "1.0.1"
|
||||||
|
cmake = "0.1.52"
|
||||||
|
which = "7.0.0"
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
use cmake::Config;
|
||||||
|
use path_clean::{clean, PathClean};
|
||||||
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
|
fn libicsneo_path() -> PathBuf {
|
||||||
|
// Get the path of libicsneo
|
||||||
|
let path = std::env::var("LIBICSNEO_PATH")
|
||||||
|
.unwrap_or(format!("{}/../../../", env!("CARGO_MANIFEST_DIR")));
|
||||||
|
let libicsneo_path = std::path::PathBuf::from(clean(&path));
|
||||||
|
|
||||||
|
libicsneo_path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn libicsneo_include_path() -> PathBuf {
|
||||||
|
let path = libicsneo_path().join("include");
|
||||||
|
path.clean()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn libicsneo_header_path() -> PathBuf {
|
||||||
|
let path = libicsneo_include_path().join("icsneo").join("icsneo.h");
|
||||||
|
path.clean()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detects the cargo build profile, true = release, otherwise false
|
||||||
|
fn is_release_build() -> bool {
|
||||||
|
let profile = std::env::var("PROFILE").unwrap();
|
||||||
|
match profile.as_str() {
|
||||||
|
"debug" => return false,
|
||||||
|
"release" => return true,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the cmake build string that is normally passed to -DCMAKE_BUILD_TYPE=
|
||||||
|
fn cmake_build_config_type() -> String {
|
||||||
|
let build_config_type = if is_release_build() {
|
||||||
|
"Release"
|
||||||
|
} else {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
// Rust runtime is linked with /MD on windows MSVC... MSVC takes Debug and forces /MDd
|
||||||
|
// https://www.reddit.com/r/rust/comments/dvmzo2/cargo_external_c_library_windows_debugrelease_hell/
|
||||||
|
"RelWithDebInfo"
|
||||||
|
} else {
|
||||||
|
"Debug"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
build_config_type.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build libicsneo through cmake, returns the build directory
|
||||||
|
fn build_libicsneo() -> PathBuf {
|
||||||
|
let libicsneo_path = libicsneo_path();
|
||||||
|
// Check to make sure CMakeLists.txt exists
|
||||||
|
if !libicsneo_path.join("CMakeLists.txt").exists() {
|
||||||
|
panic!("CMakeLists.txt not found at {}", libicsneo_path.display());
|
||||||
|
}
|
||||||
|
let build_config_type = cmake_build_config_type();
|
||||||
|
// Run cmake on libicsneo
|
||||||
|
let mut config = Config::new(libicsneo_path.clone());
|
||||||
|
let config = config
|
||||||
|
.build_target("ALL_BUILD")
|
||||||
|
// .define("LIBICSNEO_BUILD_ICSNEOC_STATIC:BOOL", "ON")
|
||||||
|
// .define("LIBICSNEO_BUILD_EXAMPLES:BOOL", "OFF")
|
||||||
|
// .define("LIBICSNEO_BUILD_ICSNEOLEGACY:BOOL", "OFF")
|
||||||
|
.profile(&build_config_type);
|
||||||
|
// Lets use ninja if it exists
|
||||||
|
let config = match which::which("ninja") {
|
||||||
|
Ok(_) => config.generator("Ninja Multi-Config").build_target("all"),
|
||||||
|
Err(_e) => config,
|
||||||
|
};
|
||||||
|
config.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_linker_libs(build_path: &PathBuf) {
|
||||||
|
let build_config_type = cmake_build_config_type();
|
||||||
|
// output for lib path
|
||||||
|
println!(
|
||||||
|
"cargo:warning=build search path: {:?}",
|
||||||
|
build_path
|
||||||
|
.join(format!("build/{build_config_type}"))
|
||||||
|
.display()
|
||||||
|
);
|
||||||
|
// icsneo lib/dll linker search path
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-link-search=native={}",
|
||||||
|
build_path
|
||||||
|
.join(format!("build/{build_config_type}"))
|
||||||
|
.display()
|
||||||
|
);
|
||||||
|
// fatfs linker search path and addition
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-link-search=native={}/build/third-party/fatfs/{build_config_type}",
|
||||||
|
build_path.display()
|
||||||
|
);
|
||||||
|
// libicsneo libraries
|
||||||
|
println!("cargo:rustc-link-lib=fatfs");
|
||||||
|
println!("cargo:rustc-link-lib=static=icsneocpp");
|
||||||
|
if cfg!(feature = "static") {
|
||||||
|
println!("cargo:rustc-link-lib=static=icsneo-static");
|
||||||
|
} else {
|
||||||
|
println!("cargo:rustc-link-lib=dylib=icsneo");
|
||||||
|
}
|
||||||
|
// Platform specific libraries
|
||||||
|
match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
|
||||||
|
"windows" => {
|
||||||
|
// FTD3xx linker search path and addition
|
||||||
|
println!(
|
||||||
|
"cargo:rustc-link-search=native={}/build/_deps/ftdi3xx-src",
|
||||||
|
build_path.display()
|
||||||
|
);
|
||||||
|
println!("cargo:rustc-link-lib=FTD3XX");
|
||||||
|
}
|
||||||
|
"linux" => {}
|
||||||
|
"macos" => {
|
||||||
|
println!("cargo:rustc-link-lib=static=icsneo-static");
|
||||||
|
println!("cargo:rustc-link-lib=framework=IOKit");
|
||||||
|
println!("cargo:rustc-link-lib=framework=CoreFoundation");
|
||||||
|
}
|
||||||
|
target_os => panic!("Target OS not supported: {target_os}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_git_submodule() {
|
||||||
|
// We don't need to checkout the submodule if we are using a custom libicsneo path
|
||||||
|
if std::env::var("LIBICSNEO_PATH").is_ok() {
|
||||||
|
println!("cargo:warning=Using custom LIBICSNEO_PATH, skipping checking out submodules");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let libicsneo_path = libicsneo_path();
|
||||||
|
// This seems to not be needed when including this as a dependency? Why?
|
||||||
|
// checkout the submodule if needed
|
||||||
|
let output = std::process::Command::new("git")
|
||||||
|
.args(["submodule", "update", "--init"])
|
||||||
|
.current_dir(libicsneo_path)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to fetch git submodules!");
|
||||||
|
// Make sure git was successful!
|
||||||
|
if !output.status.success() {
|
||||||
|
println!("cargo:warning=git return code: {}", output.status);
|
||||||
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
||||||
|
for line in stdout.split("\n") {
|
||||||
|
println!("cargo:warning=git stdout: {}", line);
|
||||||
|
}
|
||||||
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
||||||
|
for line in stderr.split("\n") {
|
||||||
|
println!("cargo:warning=git stderr: {}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_bindings() {
|
||||||
|
let header = libicsneo_header_path();
|
||||||
|
let bindings = bindgen::Builder::default()
|
||||||
|
.header(header.to_str().unwrap())
|
||||||
|
.default_enum_style(bindgen::EnumVariation::Rust {
|
||||||
|
non_exhaustive: false,
|
||||||
|
})
|
||||||
|
.clang_args(&[format!("-I{}", libicsneo_include_path().display()).as_str()])
|
||||||
|
.blocklist_file("stdint.h")
|
||||||
|
.blocklist_file("stdbool.h")
|
||||||
|
.use_core()
|
||||||
|
// .allowlist_function("icsneo_.*")
|
||||||
|
// .allowlist_type("neodevice_t")
|
||||||
|
// .allowlist_type("neonetid_t")
|
||||||
|
// .allowlist_type("neomessage_.*")
|
||||||
|
// .allowlist_type("neoversion_t")
|
||||||
|
// .allowlist_type("neoevent_t")
|
||||||
|
.formatter(bindgen::Formatter::Rustfmt)
|
||||||
|
.derive_default(true)
|
||||||
|
.derive_debug(true)
|
||||||
|
.derive_partialeq(true)
|
||||||
|
.derive_copy(true)
|
||||||
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||||
|
//.clang_args(clang_args())
|
||||||
|
.generate()
|
||||||
|
.expect("Unable to generate bindings");
|
||||||
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
println!("cargo:warning=out_path: {:?}", out_path.display());
|
||||||
|
bindings
|
||||||
|
.write_to_file(out_path.join("bindings.rs"))
|
||||||
|
.expect("Couldn't write bindings");
|
||||||
|
|
||||||
|
let out_path = std::path::PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
bindings
|
||||||
|
.write_to_file(out_path.join("bindings.rs"))
|
||||||
|
.expect("Couldn't write bindings!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let header = libicsneo_header_path();
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed={}", header.to_str().unwrap());
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBMSVC_PATH");
|
||||||
|
|
||||||
|
prepare_git_submodule();
|
||||||
|
generate_bindings();
|
||||||
|
// We can skip building if its for docs.rs
|
||||||
|
if std::env::var("DOCS_RS").is_err() {
|
||||||
|
let build_directory = build_libicsneo();
|
||||||
|
setup_linker_libs(&build_directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Suppress the flurry of warnings caused by using "C" naming conventions
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
|
|
||||||
|
pub fn add(left: u64, right: u64) -> u64 {
|
||||||
|
left + right
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let result = add(2, 2);
|
||||||
|
assert_eq!(result, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue