summaryrefslogtreecommitdiff
path: root/doc/interoperability/c-from-rust
diff options
context:
space:
mode:
Diffstat (limited to 'doc/interoperability/c-from-rust')
-rw-r--r--doc/interoperability/c-from-rust/README.md150
-rw-r--r--doc/interoperability/c-from-rust/ROOT0
-rw-r--r--doc/interoperability/c-from-rust/TARGETS7
-rw-r--r--doc/interoperability/c-from-rust/etc/repos.json26
-rw-r--r--doc/interoperability/c-from-rust/foo/TARGETS10
-rw-r--r--doc/interoperability/c-from-rust/foo/foo.c7
-rw-r--r--doc/interoperability/c-from-rust/foo/foo.h3
-rw-r--r--doc/interoperability/c-from-rust/main.rs21
8 files changed, 224 insertions, 0 deletions
diff --git a/doc/interoperability/c-from-rust/README.md b/doc/interoperability/c-from-rust/README.md
new file mode 100644
index 0000000..b67b827
--- /dev/null
+++ b/doc/interoperability/c-from-rust/README.md
@@ -0,0 +1,150 @@
+# Call C code from Rust
+
+This tutorial demonstrates how C code can be called from a Rust
+binary. We will write a program that reads a number from `stdin` and
+prints its absolute value, which is computed via a call to a function
+implemented in C.
+
+## Project structure
+
+```sh
+$ tree
+.
+├── etc
+│ └── repos.json
+├── foo
+│ ├── foo.c
+│ ├── foo.h
+│ └── TARGETS
+├── main.rs
+├── README.md
+├── ROOT
+└── TARGETS
+
+2 directories, 8 files
+```
+
+## Required repositories
+
+In the `repos.json` file we need to import both the rules for
+compiling Rust and C code
+
+```jsonc
+// file: etc/repos.json
+
+{ "main": "example"
+, "repositories":
+ { "example":
+ { "repository": {"type": "file", "path": "."}
+ , "bindings": {"rules-rust": "rules-rust", "rules-cc": "rules-cc"}
+ }
+ , "rules-rust":
+ { "repository":
+ { "type": "git"
+ , "repository": "https://github.com/just-buildsystem/rules-rust"
+ , "branch": "master"
+ , "commit": "ed652442176aea086104479bb31aced501df48a2"
+ , "subdir": "rules"
+ }
+ }
+ , "rules-cc":
+ { "repository":
+ { "type": "git"
+ , "repository": "https://github.com/just-buildsystem/rules-cc"
+ , "branch": "master"
+ , "commit": "fac7e7680e00dfc63eec41a33dff86d31571eb4b"
+ , "subdir": "rules"
+ }
+ }
+ }
+}
+```
+
+## Target definition
+
+No special attention should be given in the target definition --
+differently from the [rust-from-c tutorial](../rust-from-c/README.md)
+-- therefore the C library is defined as a normal C library
+
+``` jsonc
+// file: foo/TARGETS
+
+{ "foo":
+ { "type": ["@", "rules-cc", "CC", "library"]
+ , "pure C": ["true"]
+ , "name": ["foo"]
+ , "srcs": ["foo.c"]
+ , "hdrs": ["foo.h"]
+ , "stage": ["foo"]
+ , "ldflags": ["-lm"]
+ }
+}
+```
+
+and the `"main"` is defined as a simple Rust binary that depends on a
+library
+
+``` jsonc
+//file: TARGETS
+
+{ "main":
+ { "type": ["@", "rules-rust", "rust", "binary"]
+ , "name": ["main"]
+ , "crate_root": ["main.rs"]
+ , "deps": [["foo", "foo"]]
+ }
+}
+```
+
+## The `main`
+
+For the sake of completeness, this is how the `main.rs` crate looks
+
+```rust
+// file: main.rs
+
+use std::env;
+
+// declaration of the function implemented in the C library
+extern "C" {
+ fn c_func(input: i32) -> i32;
+}
+
+// wrapper to call the C function
+fn c_call(i: i32) -> i32 {
+ unsafe {
+ return c_func(i);
+ }
+}
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ match args[1].parse::<i32>() {
+ Ok(i) => println!("Absolute value of {} is {}", i, c_call(i)),
+ Err(..) => println!("Wrong argument {}", args[1]),
+ };
+}
+```
+
+## How to compile
+
+The `"main"` target can be built with the following command
+
+```sh
+$ just-mr build main
+```
+
+Please refer to the "Let's build" section of the [getting-started
+tutorial](../../getting-started/README.md) for more details on how to
+find/select the `rustc` compiler.
+
+## Additional exercises
+
+To get more familiarity with the rules, you may want to:
+
+ - write a Rust library that wraps the C library, and add a
+ `["@","rules-rust", "rust", "test"]` to test the library. Of course,
+ the main will only have the new Rust library as a dependency.
+
+ - add a `["@", "rules-cc", "shell/script", "test"]` to test that the
+ main actually works.
diff --git a/doc/interoperability/c-from-rust/ROOT b/doc/interoperability/c-from-rust/ROOT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/doc/interoperability/c-from-rust/ROOT
diff --git a/doc/interoperability/c-from-rust/TARGETS b/doc/interoperability/c-from-rust/TARGETS
new file mode 100644
index 0000000..821f46c
--- /dev/null
+++ b/doc/interoperability/c-from-rust/TARGETS
@@ -0,0 +1,7 @@
+{ "main":
+ { "type": ["@", "rules-rust", "rust", "binary"]
+ , "name": ["main"]
+ , "crate_root": ["main.rs"]
+ , "deps": [["foo", "foo"]]
+ }
+}
diff --git a/doc/interoperability/c-from-rust/etc/repos.json b/doc/interoperability/c-from-rust/etc/repos.json
new file mode 100644
index 0000000..4a3d134
--- /dev/null
+++ b/doc/interoperability/c-from-rust/etc/repos.json
@@ -0,0 +1,26 @@
+{ "main": "example"
+, "repositories":
+ { "example":
+ { "repository": {"type": "file", "path": "."}
+ , "bindings": {"rules-rust": "rules-rust", "rules-cc": "rules-cc"}
+ }
+ , "rules-rust":
+ { "repository":
+ { "type": "git"
+ , "repository": "https://github.com/just-buildsystem/rules-rust"
+ , "branch": "master"
+ , "commit": "ed652442176aea086104479bb31aced501df48a2"
+ , "subdir": "rules"
+ }
+ }
+ , "rules-cc":
+ { "repository":
+ { "type": "git"
+ , "repository": "https://github.com/just-buildsystem/rules-cc"
+ , "branch": "master"
+ , "commit": "fac7e7680e00dfc63eec41a33dff86d31571eb4b"
+ , "subdir": "rules"
+ }
+ }
+ }
+}
diff --git a/doc/interoperability/c-from-rust/foo/TARGETS b/doc/interoperability/c-from-rust/foo/TARGETS
new file mode 100644
index 0000000..804b9e8
--- /dev/null
+++ b/doc/interoperability/c-from-rust/foo/TARGETS
@@ -0,0 +1,10 @@
+{ "foo":
+ { "type": ["@", "rules-cc", "CC", "library"]
+ , "pure C": ["true"]
+ , "name": ["foo"]
+ , "srcs": ["foo.c"]
+ , "hdrs": ["foo.h"]
+ , "stage": ["foo"]
+ , "ldflags": ["-lm"]
+ }
+}
diff --git a/doc/interoperability/c-from-rust/foo/foo.c b/doc/interoperability/c-from-rust/foo/foo.c
new file mode 100644
index 0000000..e419fa4
--- /dev/null
+++ b/doc/interoperability/c-from-rust/foo/foo.c
@@ -0,0 +1,7 @@
+#include <math.h>
+
+#include "foo/foo.h"
+
+int c_func(int x){
+ return sqrt(x*x);
+}
diff --git a/doc/interoperability/c-from-rust/foo/foo.h b/doc/interoperability/c-from-rust/foo/foo.h
new file mode 100644
index 0000000..6ce2745
--- /dev/null
+++ b/doc/interoperability/c-from-rust/foo/foo.h
@@ -0,0 +1,3 @@
+#pragma once
+int c_func(int);
+
diff --git a/doc/interoperability/c-from-rust/main.rs b/doc/interoperability/c-from-rust/main.rs
new file mode 100644
index 0000000..ff27dd7
--- /dev/null
+++ b/doc/interoperability/c-from-rust/main.rs
@@ -0,0 +1,21 @@
+use std::env;
+
+// declaration of the function implemented in the C library
+extern "C" {
+ fn c_func(input: i32) -> i32;
+}
+
+// wrapper to call the C function
+fn c_call(i: i32) -> i32 {
+ unsafe {
+ return c_func(i);
+ }
+}
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ match args[1].parse::<i32>() {
+ Ok(i) => println!("Absolute value of {} is {}", i, c_call(i)),
+ Err(..) => println!("Wrong argument {}", args[1]),
+ };
+}