16021
|
1 |
## Usage
|
|
2 |
|
|
3 |
### Automatically import crate targets with `corrosion_import_crate`
|
|
4 |
|
|
5 |
In order to integrate a Rust crate into CMake, you first need to import Rust crates from
|
|
6 |
a [package] or [workspace]. Corrosion provides `corrosion_import_crate()` to automatically import
|
|
7 |
crates defined in a Cargo.toml Manifest file:
|
|
8 |
|
|
9 |
{{#include ../../cmake/Corrosion.cmake:corrosion-import-crate}}
|
|
10 |
|
|
11 |
Corrosion will use `cargo metadata` to add a cmake target for each crate defined in the Manifest file
|
|
12 |
and add the necessary rules to build the targets.
|
|
13 |
For Rust executables an [`IMPORTED`] executable target is created with the same name as defined in the `[[bin]]`
|
|
14 |
section of the Manifest corresponding to this target.
|
|
15 |
If no such name was defined the target name defaults to the Rust package name.
|
|
16 |
For Rust library targets an [`INTERFACE`] library target is created with the same name as defined in the `[lib]`
|
|
17 |
section of the Manifest. This `INTERFACE` library links an internal corrosion target, which is either a
|
|
18 |
`SHARED` or `STATIC` `IMPORTED` library, depending on the Rust crate type (`cdylib` vs `staticlib`).
|
|
19 |
|
|
20 |
The created library targets can be linked into other CMake targets by simply using [target_link_libraries].
|
|
21 |
|
|
22 |
Corrosion will by default copy the produced Rust artifacts into `${CMAKE_CURRENT_BINARY_DIR}`. The target location
|
|
23 |
can be changed by setting the CMake `OUTPUT_DIRECTORY` target properties on the imported Rust targets.
|
|
24 |
See the [OUTPUT_DIRECTORY](#cmake-output_directory-target-properties-and-imported_location) section for more details.
|
|
25 |
|
|
26 |
Many of the options available for `corrosion_import_crate` can also be individually set per
|
|
27 |
target, see [Per Target options](#per-target-options) for details.
|
|
28 |
|
|
29 |
[package]: https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html
|
|
30 |
[workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html
|
|
31 |
[`IMPORTED`]: https://cmake.org/cmake/help/latest/prop_tgt/IMPORTED.html
|
|
32 |
[`INTERFACE`]: https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries
|
|
33 |
[target_link_libraries]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html
|
|
34 |
|
|
35 |
### Per Target options
|
|
36 |
|
|
37 |
Some configuration options can be specified individually for each target. You can set them via the
|
|
38 |
`corrosion_set_xxx()` functions specified below:
|
|
39 |
|
|
40 |
- `corrosion_set_env_vars(<target_name> <key1=value1> [... <keyN=valueN>])`: Define environment variables
|
|
41 |
that should be set during the invocation of `cargo build` for the specified target. Please note that
|
|
42 |
the environment variable will only be set for direct builds of the target via cmake, and not for any
|
|
43 |
build where cargo built the crate in question as a dependency for another target.
|
|
44 |
The environment variables may contain generator expressions.
|
|
45 |
- `corrosion_add_target_rustflags(<target_name> <rustflag> [... <rustflagN>])`: When building the target,
|
|
46 |
the `RUSTFLAGS` environment variable will contain the flags added via this function. Please note that any
|
|
47 |
dependencies (built by cargo) will also see these flags. See also: `corrosion_add_target_local_rustflags`.
|
|
48 |
- `corrosion_add_target_local_rustflags(target_name rustc_flag [more_flags ...])`: Support setting
|
|
49 |
rustflags for only the main target (crate) and none of its dependencies.
|
|
50 |
This is useful in cases where you only need rustflags on the main-crate, but need to set different
|
|
51 |
flags for different targets. Without "local" Rustflags this would require rebuilds of the
|
|
52 |
dependencies when switching targets.
|
|
53 |
- `corrosion_set_hostbuild(<target_name>)`: The target should be compiled for the Host target and ignore any
|
|
54 |
cross-compile configuration.
|
|
55 |
- `corrosion_set_features(<target_name> [ALL_FEATURES <Bool>] [NO_DEFAULT_FEATURES] [FEATURES <feature1> ... ])`:
|
|
56 |
For a given target, enable specific features via `FEATURES`, toggle `ALL_FEATURES` on or off or disable all features
|
|
57 |
via `NO_DEFAULT_FEATURES`. For more information on features, please see also the
|
|
58 |
[cargo reference](https://doc.rust-lang.org/cargo/reference/features.html).
|
|
59 |
- `corrosion_set_cargo_flags(<target_name> <flag1> ...])`:
|
|
60 |
For a given target, add options and flags at the end of `cargo build` invocation. This will be appended after any
|
|
61 |
arguments passed through the `FLAGS` during the crate import.
|
|
62 |
- `corrosion_set_linker(target_name linker)`: Use `linker` to link the target.
|
|
63 |
Please note that this only has an effect for targets where the final linker invocation is done
|
|
64 |
by cargo, i.e. targets where foreign code is linked into rust code and not the other way around.
|
|
65 |
Please also note that if you are cross-compiling and specify a linker such as `clang`, you are
|
|
66 |
responsible for also adding a rustflag which adds the necessary `--target=` argument for the
|
|
67 |
linker.
|
|
68 |
|
|
69 |
|
|
70 |
### Global Corrosion Options
|
|
71 |
All of the following variables are evaluated automatically in most cases. In typical cases you
|
|
72 |
shouldn't need to alter any of these. If you do want to specify them manually, make sure to set
|
|
73 |
them **before** `find_package(Corrosion REQUIRED)`.
|
|
74 |
|
|
75 |
- `Rust_TOOLCHAIN:STRING` - Specify a named rustup toolchain to use. Changes to this variable
|
|
76 |
resets all other options. Default: If the first-found `rustc` is a `rustup` proxy, then the default
|
|
77 |
rustup toolchain (see `rustup show`) is used. Otherwise, the variable is unset by default.
|
|
78 |
- `Rust_ROOT:STRING` - CMake provided. Path to a Rust toolchain to use. This is an alternative if
|
|
79 |
you want to select a specific Rust toolchain, but it's not managed by rustup. Default: Nothing
|
|
80 |
- `Rust_COMPILER:STRING` - Path to `rustc`, which should be used for compiling or for toolchain
|
|
81 |
detection (if it is a `rustup` proxy). Default: The `rustc` in the first-found toolchain, either
|
|
82 |
from `rustup`, or from a toolchain available in the user's `PATH`.
|
|
83 |
- `Rust_RESOLVE_RUSTUP_TOOLCHAINS:BOOL` - If the found `rustc` is a `rustup` proxy, resolve a
|
|
84 |
concrete path to a specific toolchain managed by `rustup`, according to the `rustup` toolchain
|
|
85 |
selection rules and other options detailed here. If this option is turned off, the found `rustc`
|
|
86 |
will be used as-is to compile, even if it is a `rustup` proxy, which might increase compilation
|
|
87 |
time. Default: `ON` if the found `rustc` is a rustup proxy or a `rustup` managed toolchain was
|
|
88 |
requested, `OFF` otherwise. Forced `OFF` if `rustup` was not found.
|
|
89 |
- `Rust_CARGO:STRING` - Path to `cargo`. Default: the `cargo` installed next to `${Rust_COMPILER}`.
|
|
90 |
- `Rust_CARGO_TARGET:STRING` - The default target triple to build for. Alter for cross-compiling.
|
|
91 |
Default: On Visual Studio Generator, the matching triple for `CMAKE_VS_PLATFORM_NAME`. Otherwise,
|
|
92 |
the default target triple reported by `${Rust_COMPILER} --version --verbose`.
|
|
93 |
- `CORROSION_NATIVE_TOOLING:BOOL` - Use a native tool (written in Rust) as part of Corrosion. This
|
|
94 |
option increases the configure-time significantly unless Corrosion is installed.
|
|
95 |
Default: `OFF` if CMake >= 3.19.0. Forced `ON` for CMake < 3.19.
|
|
96 |
|
|
97 |
|
|
98 |
#### Developer/Maintainer Options
|
|
99 |
These options are not used in the course of normal Corrosion usage, but are used to configure how
|
|
100 |
Corrosion is built and installed. Only applies to Corrosion builds and subdirectory uses.
|
|
101 |
|
|
102 |
- `CORROSION_DEV_MODE:BOOL` - Indicates that Corrosion is being actively developed. Default: `OFF`
|
|
103 |
if Corrosion is a subdirectory, `ON` if it is the top-level project
|
|
104 |
- `CORROSION_BUILD_TESTS:BOOL` - Build the Corrosion tests. Default: `Off` if Corrosion is a
|
|
105 |
subdirectory, `ON` if it is the top-level project
|
|
106 |
- `CORROSION_GENERATOR_EXECUTABLE:STRING` - Specify a path to the corrosion-generator executable.
|
|
107 |
This is to support scenarios where it's easier to build corrosion-generator outside of the normal
|
|
108 |
bootstrap path, such as in the case of package managers that make it very easy to import Rust
|
|
109 |
crates for fully reproducible, offline builds.
|
|
110 |
- `CORROSION_INSTALL_EXECUTABLE:BOOL` - Controls whether corrosion-generator is installed with the
|
|
111 |
package. Default: `ON` with `CORROSION_GENERATOR_EXECUTABLE` unset, otherwise `OFF`
|
|
112 |
|
|
113 |
|
|
114 |
### Information provided by Corrosion
|
|
115 |
|
|
116 |
For your convenience, Corrosion sets a number of variables which contain information about the version of the rust
|
|
117 |
toolchain. You can use the CMake version comparison operators
|
|
118 |
(e.g. [`VERSION_GREATER_EQUAL`](https://cmake.org/cmake/help/latest/command/if.html#version-comparisons)) on the main
|
|
119 |
variable (e.g. `if(Rust_VERSION VERSION_GREATER_EQUAL "1.57.0")`), or you can inspect the major, minor and patch
|
|
120 |
versions individually.
|
|
121 |
- `Rust_VERSION<_MAJOR|_MINOR|_PATCH>` - The version of rustc.
|
|
122 |
- `Rust_CARGO_VERSION<_MAJOR|_MINOR|_PATCH>` - The cargo version.
|
|
123 |
- `Rust_LLVM_VERSION<_MAJOR|_MINOR|_PATCH>` - The LLVM version used by rustc.
|
|
124 |
- `Rust_IS_NIGHTLY` - 1 if a nightly toolchain is used, otherwise 0. Useful for selecting an unstable feature for a
|
|
125 |
crate, that is only available on nightly toolchains.
|
|
126 |
- Cache variables containing information based on the target triple for the selected target
|
|
127 |
as well as the default host target:
|
|
128 |
- `Rust_CARGO_TARGET_ARCH`, `Rust_CARGO_HOST_ARCH`: e.g. `x86_64` or `aarch64`
|
|
129 |
- `Rust_CARGO_TARGET_VENDOR`, `Rust_CARGO_HOST_VENDOR`: e.g. `apple`, `pc`, `unknown` etc.
|
|
130 |
- `Rust_CARGO_TARGET_OS`, `Rust_CARGO_HOST_OS`: e.g. `darwin`, `linux`, `windows`, `none`
|
|
131 |
- `Rust_CARGO_TARGET_ENV`, `Rust_CARGO_HOST_ENV`: e.g. `gnu`, `musl`
|
|
132 |
|
|
133 |
|
|
134 |
|
|
135 |
|
|
136 |
### Selecting a custom cargo profile
|
|
137 |
|
|
138 |
[Rust 1.57](https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html) stabilized the support for custom
|
|
139 |
[profiles](https://doc.rust-lang.org/cargo/reference/profiles.html). If you are using a sufficiently new rust toolchain,
|
|
140 |
you may select a custom profile by adding the optional argument `PROFILE <profile_name>` to
|
|
141 |
`corrosion_import_crate()`. If you do not specify a profile, or you use an older toolchain, corrosion will select
|
|
142 |
the standard `dev` profile if the CMake config is either `Debug` or unspecified. In all other cases the `release`
|
|
143 |
profile is chosen for cargo.
|
|
144 |
|
|
145 |
### Importing C-Style Libraries Written in Rust
|
|
146 |
Corrosion makes it completely trivial to import a crate into an existing CMake project. Consider
|
|
147 |
a project called [rust2cpp](test/rust2cpp/rust2cpp) with the following file structure:
|
|
148 |
```
|
|
149 |
rust2cpp/
|
|
150 |
rust/
|
|
151 |
src/
|
|
152 |
lib.rs
|
|
153 |
Cargo.lock
|
|
154 |
Cargo.toml
|
|
155 |
CMakeLists.txt
|
|
156 |
main.cpp
|
|
157 |
```
|
|
158 |
|
|
159 |
This project defines a simple Rust lib crate, like so, in [`rust2cpp/rust/Cargo.toml`](test/rust2cpp/rust2cpp/rust/Cargo.toml):
|
|
160 |
```toml
|
|
161 |
[package]
|
|
162 |
name = "rust-lib"
|
|
163 |
version = "0.1.0"
|
|
164 |
authors = ["Andrew Gaspar <andrew.gaspar@outlook.com>"]
|
|
165 |
license = "MIT"
|
|
166 |
edition = "2018"
|
|
167 |
|
|
168 |
[dependencies]
|
|
169 |
|
|
170 |
[lib]
|
|
171 |
crate-type=["staticlib"]
|
|
172 |
```
|
|
173 |
|
|
174 |
In addition to `"staticlib"`, you can also use `"cdylib"`. In fact, you can define both with a
|
|
175 |
single crate and switch between which is used using the standard
|
|
176 |
[`BUILD_SHARED_LIBS`](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) variable.
|
|
177 |
|
|
178 |
This crate defines a simple crate called `rust-lib`. Importing this crate into your
|
|
179 |
[CMakeLists.txt](test/rust2cpp/CMakeLists.txt) is trivial:
|
|
180 |
```cmake
|
|
181 |
# Note: you must have already included Corrosion for `corrosion_import_crate` to be available. See # the `Installation` section above.
|
|
182 |
|
|
183 |
corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
|
|
184 |
```
|
|
185 |
|
|
186 |
Now that you've imported the crate into CMake, all of the executables, static libraries, and dynamic
|
|
187 |
libraries defined in the Rust can be directly referenced. So, merely define your C++ executable as
|
|
188 |
normal in CMake and add your crate's library using target_link_libraries:
|
|
189 |
```cmake
|
|
190 |
add_executable(cpp-exe main.cpp)
|
|
191 |
target_link_libraries(cpp-exe PUBLIC rust-lib)
|
|
192 |
```
|
|
193 |
|
|
194 |
That's it! You're now linking your Rust library to your C++ library.
|
|
195 |
|
|
196 |
#### Generate Bindings to Rust Library Automatically
|
|
197 |
|
|
198 |
Currently, you must manually declare bindings in your C or C++ program to the exported routines and
|
|
199 |
types in your Rust project. You can see boths sides of this in
|
|
200 |
[the Rust code](test/rust2cpp/rust2cpp/rust/src/lib.rs) and in [the C++ code](test/rust2cpp/rust2cpp/main.cpp).
|
|
201 |
|
|
202 |
Integration with [cbindgen](https://github.com/eqrion/cbindgen) is
|
|
203 |
planned for the future.
|
|
204 |
|
|
205 |
### Importing Libraries Written in C and C++ Into Rust
|
|
206 |
|
|
207 |
The rust targets can be imported with `corrosion_import_crate()` into CMake.
|
|
208 |
For targets where the linker should be invoked by Rust corrosion provides
|
|
209 |
`corrosion_link_libraries()` to link your C/C++ libraries with the Rust target.
|
|
210 |
For additional linker flags you may use `corrosion_add_target_local_rustflags()`
|
|
211 |
and pass linker arguments via the `-Clink-args` flag to rustc. These flags will
|
|
212 |
only be passed to the final rustc invocation and not affect any rust dependencies.
|
|
213 |
|
|
214 |
C bindings can be generated via [bindgen](https://github.com/rust-lang/rust-bindgen).
|
|
215 |
Corrosion does not offer any direct integration yet, but you can either generate the
|
|
216 |
bindings in the build-script of your crate, or generate the bindings as a CMake build step
|
|
217 |
(e.g. a custom target) and add a dependency from `cargo-prebuild_<rust_target>` to your
|
|
218 |
custom target for generating the bindings.
|
|
219 |
|
|
220 |
Example:
|
|
221 |
|
|
222 |
```cmake
|
|
223 |
# Import your Rust targets
|
|
224 |
corrosion_import_crate(MANIFEST_PATH rust/Cargo.toml)
|
|
225 |
# Link C/C++ libraries with your Rust target
|
|
226 |
corrosion_link_libraries(target_name c_library)
|
|
227 |
# Optionally explicitly define which linker to use.
|
|
228 |
corrosion_set_linker(target_name your_custom_linker)
|
|
229 |
# Optionally set linker arguments
|
|
230 |
corrosion_add_target_local_rustflags(target_name "-Clink-args=<linker arguments>")
|
|
231 |
# Optionally tell CMake that the rust crate depends on another target (e.g. a code generator)
|
|
232 |
add_dependencies(cargo-prebuild_<target_name> custom_bindings_target)
|
|
233 |
```
|
|
234 |
|
|
235 |
### Cross Compiling
|
|
236 |
Corrosion attempts to support cross-compiling as generally as possible, though not all
|
|
237 |
configurations are tested. Cross-compiling is explicitly supported in the following scenarios.
|
|
238 |
|
|
239 |
In all cases, you will need to install the standard library for the Rust target triple. When using
|
|
240 |
Rustup, you can use it to install the target standard library:
|
|
241 |
|
|
242 |
```bash
|
|
243 |
rustup target add <target-rust-triple>
|
|
244 |
```
|
|
245 |
|
|
246 |
If the target triple is automatically derived, Corrosion will print the target during configuration.
|
|
247 |
For example:
|
|
248 |
|
|
249 |
```
|
|
250 |
-- Rust Target: aarch64-linux-android
|
|
251 |
```
|
|
252 |
|
|
253 |
#### Windows-to-Windows
|
|
254 |
Corrosion supports cross-compiling between arbitrary Windows architectures using the Visual Studio
|
|
255 |
Generator. For example, to cross-compile for ARM64 from any platform, simply set the `-A`
|
|
256 |
architecture flag:
|
|
257 |
|
|
258 |
```bash
|
|
259 |
cmake -S. -Bbuild-arm64 -A ARM64
|
|
260 |
cmake --build build-arm64
|
|
261 |
```
|
|
262 |
|
|
263 |
Please note that for projects containing a build-script at least Rust 1.54 is required due to a bug
|
|
264 |
in previous cargo versions, which causes the build-script to incorrectly be built for the target
|
|
265 |
platform.
|
|
266 |
|
|
267 |
#### Linux-to-Linux
|
|
268 |
In order to cross-compile on Linux, you will need to install a cross-compiler. For example, on
|
|
269 |
Ubuntu, to cross compile for 64-bit Little-Endian PowerPC Little-Endian, install
|
|
270 |
`g++-powerpc64le-linux-gnu` from apt-get:
|
|
271 |
|
|
272 |
```bash
|
|
273 |
sudo apt install g++-powerpc64le-linux-gnu
|
|
274 |
```
|
|
275 |
|
|
276 |
Currently, Corrosion does not automatically determine the target triple while cross-compiling on
|
|
277 |
Linux, so you'll need to specify a matching `Rust_CARGO_TARGET`.
|
|
278 |
|
|
279 |
```bash
|
|
280 |
cmake -S. -Bbuild-ppc64le -DRust_CARGO_TARGET=powerpc64le-unknown-linux-gnu -DCMAKE_CXX_COMPILER=powerpc64le-linux-gnu-g++
|
|
281 |
cmake --build build-ppc64le
|
|
282 |
```
|
|
283 |
|
|
284 |
#### Android
|
|
285 |
|
|
286 |
Cross-compiling for Android is supported on all platforms with the Makefile and Ninja generators,
|
|
287 |
and the Rust target triple will automatically be selected. The CMake
|
|
288 |
[cross-compiling instructions for Android](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android)
|
|
289 |
apply here. For example, to build for ARM64:
|
|
290 |
|
|
291 |
```bash
|
|
292 |
cmake -S. -Bbuild-android-arm64 -GNinja -DCMAKE_SYSTEM_NAME=Android \
|
|
293 |
-DCMAKE_ANDROID_NDK=/path/to/android-ndk-rxxd -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a
|
|
294 |
```
|
|
295 |
|
|
296 |
**Important note:** The Android SDK ships with CMake 3.10 at newest, which Android Studio will
|
|
297 |
prefer over any CMake you've installed locally. CMake 3.10 is insufficient for using Corrosion,
|
|
298 |
which requires a minimum of CMake 3.15. If you're using Android Studio to build your project,
|
|
299 |
follow the instructions in the Android Studio documentation for
|
|
300 |
[using a specific version of CMake](https://developer.android.com/studio/projects/install-ndk#vanilla_cmake).
|
|
301 |
|
|
302 |
|
|
303 |
### CMake `OUTPUT_DIRECTORY` target properties and `IMPORTED_LOCATION`
|
|
304 |
|
|
305 |
Corrosion respects the following `OUTPUT_DIRECTORY` target properties on CMake >= 3.19:
|
|
306 |
- [ARCHIVE_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY.html)
|
|
307 |
- [LIBRARY_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html)
|
|
308 |
- [RUNTIME_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html)
|
|
309 |
- [PDB_OUTPUT_DIRECTORY](https://cmake.org/cmake/help/latest/prop_tgt/PDB_OUTPUT_DIRECTORY.html)
|
|
310 |
|
|
311 |
If the target property is set (e.g. by defining the `CMAKE_XYZ_OUTPUT_DIRECTORY` variable before calling
|
|
312 |
`corrosion_import_crate()`), corrosion will copy the built rust artifacts to the location defined in the
|
|
313 |
target property.
|
|
314 |
Due to limitations in CMake these target properties are evaluated in a deferred manner, to
|
|
315 |
support the user setting the target properties after the call to `corrosion_import_crate()`.
|
|
316 |
This has the side effect that the `IMPORTED_LOCATION` property will be set late, and users should not
|
|
317 |
use `get_property` to read `IMPORTED_LOCATION` at configure time. Instead, generator expressions
|
|
318 |
should be used to get the location of the target artifact.
|
|
319 |
If `IMPORTED_LOCATION` is needed at configure time users may use `cmake_language(DEFER CALL ...)` to defer
|
|
320 |
evaluation to after the `IMPORTED_LOCATION` property is set.
|