diff options
Diffstat (limited to 'doc/interoperability/c-from-rust')
-rw-r--r-- | doc/interoperability/c-from-rust/README.md | 150 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/ROOT | 0 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/TARGETS | 7 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/etc/repos.json | 26 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/foo/TARGETS | 10 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/foo/foo.c | 7 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/foo/foo.h | 3 | ||||
-rw-r--r-- | doc/interoperability/c-from-rust/main.rs | 21 |
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]), + }; +} |