1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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.
|