Initial libmount function call from Rust
authorMartin Pitt <martin@piware.de>
Fri, 27 Aug 2021 06:43:12 +0000 (08:43 +0200)
committerMartin Pitt <martin@piware.de>
Fri, 27 Aug 2021 08:24:17 +0000 (10:24 +0200)
Follow "A little C with your Rust" [1].

Set up cargo and main.rs skeleton and call one of the simplest possible
functions from libmount: mnt_get_fstab_path().

Use bindgen [1] to translate libmount's header file into a Rust
interface. This requires a few hacks:

 - bindgen does not accept the original header right away, as it can't
   find stdarg.h. Avoid this by dropping the (unnecessary) stdio.h
   include.
 - bindgen does not know about `size_t`. Hack around that with a typedef
   for now.
 - Suppress warnings about constant/identifier naming.

[1] https://rust-lang.github.io/rust-bindgen/command-line-usage.html
[2] https://docs.rust-embedded.org/book/interoperability/c-with-rust.html

.gitignore
call-c-from-rust/.cargo/config [new file with mode: 0644]
call-c-from-rust/Cargo.toml [new file with mode: 0644]
call-c-from-rust/Makefile
call-c-from-rust/src/main.rs [new file with mode: 0644]

index 5c030314fde38609d0fa5ac3ffdedca12d63adae..7ecae2e002a7ed8d2847b55e7db31df18052dfdc 100644 (file)
@@ -3,5 +3,6 @@
 Cargo.lock
 target
 
+libmount.rs
 c-langinfo
 c-mounts
diff --git a/call-c-from-rust/.cargo/config b/call-c-from-rust/.cargo/config
new file mode 100644 (file)
index 0000000..53fb2de
--- /dev/null
@@ -0,0 +1,2 @@
+[build]
+rustflags = "-C link-args=-lmount"
diff --git a/call-c-from-rust/Cargo.toml b/call-c-from-rust/Cargo.toml
new file mode 100644 (file)
index 0000000..535c6b9
--- /dev/null
@@ -0,0 +1,8 @@
+[package]
+name = "learning-c-from-rust"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
index 583e2f2ff345b1df003117a3bf18418b1601b2b9..cbeefdd888c5aab771bb9475593d717fd61aa873 100644 (file)
@@ -1,7 +1,7 @@
 CFLAGS += $(shell pkg-config --cflags mount)
 LIBMOUNT = $(shell pkg-config --libs mount)
 
-all: c-mounts c-langinfo
+all: c-mounts c-langinfo target/debug/learning-c-from-rust
 
 c-mounts: c-mounts.o
        $(CC) -Wall -o $@ $^ $(LIBMOUNT)
@@ -9,13 +9,25 @@ c-mounts: c-mounts.o
 c-langinfo: c-langinfo.o
        $(CC) -Wall -o $@ $^
 
+# HACK: does not find stdarg.h (through stdio.h), missing size_t
+# also avoid hundreds of "should have an upper camel case name" warnings
+src/libmount.rs:
+       sed 's/#include.*stdio.h.*/typedef unsigned long size_t;/' /usr/include/libmount/libmount.h > libmount-hack.h
+       bindgen libmount-hack.h -- -I/usr/include/linux/ > $@.tmp
+       (echo '#![allow(non_camel_case_types,non_upper_case_globals,dead_code)]'; cat $@.tmp) > $@
+       rm libmount-hack.h $@.tmp
+
+target/debug/learning-c-from-rust: src/libmount.rs src/main.rs
+       cargo build
+
 clean:
-       rm -f c-mounts c-langinfo *.o
+       rm -f c-mounts c-langinfo *.o src/libmount.rs
 
 run: all
        LANG=en_US.UTF-8 ./c-langinfo
        LANG=en_GB.UTF-8 ./c-langinfo
        LANG=en_IE.UTF-8 ./c-langinfo
        ./c-mounts
+       target/debug/learning-c-from-rust
 
 .PHONY: clean run
diff --git a/call-c-from-rust/src/main.rs b/call-c-from-rust/src/main.rs
new file mode 100644 (file)
index 0000000..b453d81
--- /dev/null
@@ -0,0 +1,10 @@
+mod libmount;
+
+use std::ffi::CStr;
+
+fn main() {
+    let fstab_path_cstr: &CStr = unsafe { CStr::from_ptr (libmount::mnt_get_fstab_path()) };
+    println!("fstab path C-String: {:?}", fstab_path_cstr);
+    let fstab_path = fstab_path_cstr.to_str().unwrap(); // may cause UTF-8 decoding error
+    println!("fstab path str: {}", fstab_path);
+}