aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/2022-05-30-cmake-cargo-example.md
blob: 6b7d71f99c650f33ed4614ee500e293759dc7e56 (plain) (blame)
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
+++
title = "Example: integrate cargo into cmake"

[taxonomies]
tags = ["rust", "c++", "cmake"]
+++

This post outlines an example on how to integrate a library written in `rust`
into a cmake based `C/C++` project using the [ExternalProject][cmake-ext_prj]
module.
I created that post mainly as reference for myself but hopefully it is helpful
to someone else who stumbles across it :^)

The rust library is compiled as static library and then linked into the
executable written in C. The top-level cmake file to build the executable just
includes the rust crate via [add_subdirectory][cmake-add_sub] and then adds a
link dependency.

```cmake
{{ include(path="content/2022-05-30-cmake-cargo-example/CMakeLists.txt") }}
```

The more interesting bits are included in the rust crate.

First we have to tell cargo to output a static library. This can be done with
the following configuration in the [Cargo.toml][cargo-toml] file.
```toml
[lib]
crate-type = ["staticlib"]
```
> A header file with the C definitions is automatically generated using the
> [cbindgen][cbindgen] crate invoked from the [build.rs][build-rs] script.

Finally we can write a `CMakeLists.txt` file which exposes a pseudo target
`libcalc` to cmake which consumers can depend on. The pseudo target depends on
the `ext_libcalc` ([ExternalProject][cmake-ext_prj]) target.

The `BUILD_COMMAND` contains an generator expression to build the rust crate in
release mode in case `CMAKE_BUILD_TYPE=Release` is configured.

Additionally, the properties of the `libcalc` pseudo target are setup to
automatically add the correct static library and add the include path
accordingly for consumers.

With this setup, the rust crate is nicely build out of source. This is achieved
by the following two configurations:
- Pass `--target-dir` to cargo to specify the build directory.
- Setup `LIBCALC_BUILD_DIR` before invoking cargo to tell [build.rs][build-rs]
  where to generate the C header.

```cmake
{{ include(path="content/2022-05-30-cmake-cargo-example/libcalc/CMakeLists.txt") }}
```

The sources referenced in this post are available [here][post-src]. This
repository includes the following Makefile to build and run the calc
executable.
```make
{{ include(path="content/2022-05-30-cmake-cargo-example/Makefile") }}
```

[post-src]: https://git.memzero.de/blog/tree/content/2022-05-30-cmake-cargo-example?h=main
[cargo-toml]: https://git.memzero.de/blog/tree/content/2022-05-30-cmake-cargo-example/libcalc/Cargo.toml?h=main
[build-rs]: https://git.memzero.de/blog/tree/content/2022-05-30-cmake-cargo-example/libcalc/build.rs?h=main
[make]: https://git.memzero.de/blog/tree//content/2022-05-30-cmake-cargo-example/Makefile?h=main
[cbindgen]:https://lib.rs/crates/cbindgen
[cmake-add_sub]: https://cmake.org/cmake/help/latest/command/add_subdirectory.html?highlight=add_subdirectory
[cmake-ext_prj]: https://cmake.org/cmake/help/latest/module/ExternalProject.html