How to specify CMake dep in Rust, if Rust exe is built within CMake?

I use CMake+ninjabuild as the top level build system

Within CMake:

  1. there is a C++ static library called foo which is built by CMake add_library
  2. There is a C++ executable called bar which links foo
  3. There is a Rust execuable called example-rs, which is built inside CMake by
    add_custom_command(COMMAND cargo build -p example-rs)
    This executable need to link foo

What is the best way to specify that example-rs needs to build after foo?

I need cmake --build . --target all to build all of foo, bar and example-rs
Currently it is done by add_custom_command(COMMAND cargo build -p example-rs DEPENDS foo)

But this makes cargo test be unware of the dependency, so I have to manually rebuild foo,
before cargo test during development

The alternative solution would be using cmake crate in build.rs,
which build foo within build.rs,
but I do not know how to solve the diamond problem.

The top level cmake and the cmake called within build.rs uses the same CMAKE_BINARY_DIR,
The top level cmake and build.rs cmake may both compile foo in parallel,
so this may cause a conflict in disk file.

The problem above may be solved by using both add_custom_command(DEPENDS) and build.rs,
but what if there are two Rust executables within CMake project, which both needs to link foo?
When cargo test, if both of them rebuilding foo within build.rs, there is also a conflict.

NOTE: Creating multiple cmake build directory (CMAKE_BINARY_DIR) is not preferred.
The project is big and CMake configuration takes several minutes.

Can't you somehow launch cargo test as a custom command from cmake and make it depend on foo?

add_custom_command(COMMAND cargo test -p example-rs DEPENDS foo)

This is very complicate, and I want to simplify run cargo test without need to -p

Also I found this project example that claims to also be able to call rust unit tests from cmake

https://github.com/micahsnyder/cmake-rust-demo

The standard way to do that is to make foo-sys crate that has build.rs which checks an env variable like FOO_LIB_DIR to emit linking instructions for Cargo. It will have to assume the foo lib is already built, as otherwise you'd end up with a sandwich of cmake -> cargo -> build.rs -> cmake.

https://kornel.ski/rust-sys-crate

1 Like