|
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. |