tools/corrosion/doc/src/usage.md
branchtransitional_engine
changeset 16050 6a3dc15b78b9
equal deleted inserted replaced
16038:7544a7d7c819 16050:6a3dc15b78b9
       
     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.