From fdd538a64fd9fceffc87824d45c4f631090955f3 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Tue, 19 Sep 2023 17:10:50 +0200 Subject: [PATCH] make workspace and upload c-bindings --- .gitignore | 1 + Cargo.lock | 36 +++++++++++++++++++++++ Cargo.toml | 18 ++++++++++++ members/c-bindings/Cargo.toml | 14 +++++++++ members/c-bindings/lib/CMakeLists.txt | 15 ++++++++++ members/c-bindings/lib/test.c | 24 +++++++++++++++ members/c-bindings/lib/test.h | 6 ++++ members/c-bindings/src/build.rs | 11 +++++++ members/c-bindings/src/main.rs | 42 +++++++++++++++++++++++++++ src/main.rs | 13 +++++++++ 10 files changed, 180 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 members/c-bindings/Cargo.toml create mode 100644 members/c-bindings/lib/CMakeLists.txt create mode 100644 members/c-bindings/lib/test.c create mode 100644 members/c-bindings/lib/test.h create mode 100644 members/c-bindings/src/build.rs create mode 100644 members/c-bindings/src/main.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..366b039 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,36 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "c-bindings" +version = "0.1.0" +dependencies = [ + "cc", + "cty", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "rs-unsafe" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ee65c64 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[workspace] +members = [ + ".", + "members/c-bindings" +] +default-members = [ + ".", + "members/c-bindings" +] + +[package] +name = "rs-unsafe" +version = "0.1.0" +edition = "2021" +authors = ["Christoph J. Scherr "] +publish = false +autobins = true +default-run = "rs-unsafe" diff --git a/members/c-bindings/Cargo.toml b/members/c-bindings/Cargo.toml new file mode 100644 index 0000000..23a9a38 --- /dev/null +++ b/members/c-bindings/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "c-bindings" +version = "0.1.0" +edition = "2021" +links = "test" # this is the important part! cargo will search for some library called `test` (i.e. libtest.a) +build = "src/build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cty = "0.2.2" + +[build-dependencies] +cc = "1.0.83" diff --git a/members/c-bindings/lib/CMakeLists.txt b/members/c-bindings/lib/CMakeLists.txt new file mode 100644 index 0000000..66e5a57 --- /dev/null +++ b/members/c-bindings/lib/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.9) +project(test VERSION 1.0.1 DESCRIPTION "test lib") +include(GNUInstallDirs) +add_library(test STATIC test.c) +set_target_properties(test PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION 1 + PUBLIC_HEADER test.h) +# configure_file(test.pc.in test.pc @ONLY) +target_include_directories(test PRIVATE .) +install(TARGETS test + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(FILES ${CMAKE_BINARY_DIR}/test.pc + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) diff --git a/members/c-bindings/lib/test.c b/members/c-bindings/lib/test.c new file mode 100644 index 0000000..494180a --- /dev/null +++ b/members/c-bindings/lib/test.c @@ -0,0 +1,24 @@ +#include "test.h" +#include +#include +#include + +int ret19() { + return 19; +} + +char* structInfo(MyStruct *st) { + char* buf = malloc(1024*sizeof(char)); + sprintf(buf, + "Infos about the struct:\n" + "\tfoo:\t%d\n" + "\tbar:\t%c\n" + "\n" + "greetings from C" + , + st->foo, + st->bar + ); + + return buf; +} diff --git a/members/c-bindings/lib/test.h b/members/c-bindings/lib/test.h new file mode 100644 index 0000000..b669d58 --- /dev/null +++ b/members/c-bindings/lib/test.h @@ -0,0 +1,6 @@ +int ret19(); +typedef struct MyStruct { + int foo; + char bar; +} MyStruct; +char* stuctInfo(MyStruct st); diff --git a/members/c-bindings/src/build.rs b/members/c-bindings/src/build.rs new file mode 100644 index 0000000..04d6c3a --- /dev/null +++ b/members/c-bindings/src/build.rs @@ -0,0 +1,11 @@ +/// we could simply do this to compile the test lib to a static lib, +/// but that solution might not scale as good as calling a professional +/// build system +#[allow(unused)] +fn main() { + // Tell Cargo that if the given file changes, to rerun this build script. + println!("cargo:rerun-if-changed=src/hello.c"); + cc::Build::new() + .file("lib/test.c") + .compile("test"); +} diff --git a/members/c-bindings/src/main.rs b/members/c-bindings/src/main.rs new file mode 100644 index 0000000..50c9968 --- /dev/null +++ b/members/c-bindings/src/main.rs @@ -0,0 +1,42 @@ +use cty; + +// we first need to declare bindings for our C code. +// This can be automated too, but I did it myself here. +#[derive(Debug)] +#[repr(C)] +pub struct MyStruct { + pub foo: cty::c_int, + pub bar: cty::c_char, +} + +// The functions too of course +extern "C" { + pub fn ret19() -> isize; + pub fn structInfo(st: &MyStruct) -> *const cty::c_char; +} + +/////////////////////////////////////////////////////////////////////// + +fn main() { + // calling random C functions is generally treated as unsafe. + // Best practice is programming wrapper functions that give it + // confirmed safe inputs + let qux = unsafe { ret19() }; + println!("`ret19()` returned {qux}"); + let st = MyStruct { + foo: 17, bar: 0x41 + }; + // converting a c "string" to a real rust String is + // a bit complicated + let info: &str = unsafe { + // convert the returned value to a rust internal CStr. + std::ffi::CStr::from_ptr( + // the function returns a pointer to a array of chars on the heap + structInfo(&st) + ) + // now to a string slice (result) + .to_str() + .unwrap() + }; + println!("{info}"); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..63865b3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,13 @@ +fn main() { + println!( +"The dark power of unsafe rust awakens! + +This is the default executable! It does not do much, use another executable. + +Select your target like this: +`cargo run --bin $TARGET` + +To see a list of all runnable binaries, you can use the following command. +`cargo run --bin` +"); +}