{{#title Cargo-based setup — Rust ♡ C++}} # Cargo-based builds As one aspect of delivering a good Rust–C++ interop experience, CXX turns Cargo into a quite usable build system for C++ projects published as a collection of crates.io packages, including a consistent and frictionless experience `#include`-ing C++ headers across dependencies. ## Canonical setup CXX's integration with Cargo is handled through the [cxx-build] crate. [cxx-build]: https://docs.rs/cxx-build ```toml,hidelines=... # Cargo.toml ...[package] ...name = "..." ...version = "..." ...edition = "2021" [dependencies] cxx = "1.0" [build-dependencies] cxx-build = "1.0" ``` The canonical build script is as follows. The indicated line returns a [`cc::Build`] instance (from the usual widely used `cc` crate) on which you can set up any additional source files and compiler flags as normal. [`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html ```rust,noplayground // build.rs fn main() { cxx_build::bridge("src/main.rs") // returns a cc::Build .file("src/demo.cc") .std("c++11") .compile("cxxbridge-demo"); println!("cargo:rerun-if-changed=src/main.rs"); println!("cargo:rerun-if-changed=src/demo.cc"); println!("cargo:rerun-if-changed=include/demo.h"); } ``` The `rerun-if-changed` lines are optional but make it so that Cargo does not spend time recompiling your C++ code when only non-C++ code has changed since the previous Cargo build. By default without any `rerun-if-changed`, Cargo will re-execute the build script after *any* file changed in the project. If stuck, try comparing what you have against the *demo/* directory of the CXX GitHub repo, which maintains a working Cargo-based setup for the blobstore tutorial (chapter 3). ## Header include paths With cxx-build, by default your include paths always start with the crate name. This applies to both `#include` within your C++ code, and `include!` in the `extern "C++"` section of your Rust cxx::bridge. Your crate name is determined by the `name` entry in Cargo.toml. For example if your crate is named `yourcratename` and contains a C++ header file `path/to/header.h` relative to Cargo.toml, that file will be includable as: ```cpp #include "yourcratename/path/to/header.h" ``` A crate can choose a prefix for its headers that is different from the crate name by modifying **[`CFG.include_prefix`][CFG]** from build.rs: [CFG]: https://docs.rs/cxx-build/*/cxx_build/static.CFG.html ```rust,noplayground // build.rs use cxx_build::CFG; fn main() { CFG.include_prefix = "my/project"; cxx_build::bridge(...)... } ``` Subsequently the header located at `path/to/header.h` would now be includable as: ```cpp #include "my/project/path/to/header.h" ``` The empty string `""` is a valid include prefix and will make it possible to have `#include "path/to/header.h"`. However, if your crate is a library, be considerate of possible name collisions that may occur in downstream crates. If using an empty include prefix, you'll want to make sure your headers' local path within the crate is sufficiently namespaced or unique. ## Including generated code If your `#[cxx::bridge]` module contains an `extern "Rust"` block i.e. types or functions exposed from Rust to C++, or any shared data structures, the CXX-generated C++ header declaring those things is available using a `.rs.h` extension on the Rust source file's name. ```cpp // the header generated from path/to/lib.rs #include "yourcratename/path/to/lib.rs.h" ``` For giggles, it's also available using just a plain `.rs` extension as if you were including the Rust file directly. Use whichever you find more palatable. ```cpp #include "yourcratename/path/to/lib.rs" ``` ## Including headers from dependencies You get to include headers from your dependencies, both handwritten ones contained as `.h` files in their Cargo package, as well as CXX-generated ones. It works the same as an include of a local header: use the crate name (or their include\_prefix if their crate changed it) followed by the relative path of the header within the crate. ```cpp #include "dependencycratename/path/to/their/header.h` ``` Note that cross-crate imports are only made available between **direct dependencies**. You must directly depend on the other crate in order to #include its headers; a transitive dependency is not sufficient. Additionally, headers from a direct dependency are only importable if the dependency's Cargo.toml manifest contains a `links` key. If not, its headers will not be importable from outside of the same crate. See *[the `links` manifest key][links]* in the Cargo reference. [links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key


# Advanced features The following CFG settings are only relevant to you if you are writing a library that needs to support downstream crates `#include`-ing its C++ public headers. ## Publicly exporting header directories **[`CFG.exported_header_dirs`][CFG]** (vector of absolute paths) defines a set of additional directories from which the current crate, directly dependent crates, and further crates to which this crate's headers are exported (more below) will be able to `#include` headers. Adding a directory to `exported_header_dirs` is similar to adding it to the current build via the `cc` crate's [`Build::include`], but *also* makes the directory available to downstream crates that want to `#include` one of the headers from your crate. If the dir were added only using `Build::include`, the downstream crate including your header would need to manually add the same directory to their own build as well. [`Build::include`]: https://docs.rs/cc/1/cc/struct.Build.html#method.include When using `exported_header_dirs`, your crate must also set a `links` key for itself in Cargo.toml. See [*the `links` manifest key*][links]. The reason is that Cargo imposes no ordering on the execution of build scripts without a `links` key, which means the downstream crate's build script might otherwise execute before yours decides what to put into `exported_header_dirs`. ### Example One of your crate's headers wants to include a system library, such as `#include "Python.h"`. ```rust,noplayground // build.rs use cxx_build::CFG; use std::path::PathBuf; fn main() { let python3 = pkg_config::probe_library("python3").unwrap(); let python_include_paths = python3.include_paths.iter().map(PathBuf::as_path); CFG.exported_header_dirs.extend(python_include_paths); cxx_build::bridge("src/bridge.rs").compile("demo"); } ``` ### Example Your crate wants to rearrange the headers that it exports vs how they're laid out locally inside the crate's source directory. Suppose the crate as published contains a file at `./include/myheader.h` but wants it available to downstream crates as `#include "foo/v1/public.h"`. ```rust,noplayground // build.rs use cxx_build::CFG; use std::path::Path; use std::{env, fs}; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let headers = Path::new(&out_dir).join("headers"); CFG.exported_header_dirs.push(&headers); // We contain `include/myheader.h` locally, but // downstream will use `#include "foo/v1/public.h"` let foo = headers.join("foo").join("v1"); fs::create_dir_all(&foo).unwrap(); fs::copy("include/myheader.h", foo.join("public.h")).unwrap(); cxx_build::bridge("src/bridge.rs").compile("demo"); } ``` ## Publicly exporting dependencies **[`CFG.exported_header_prefixes`][CFG]** (vector of strings) each refer to the `include_prefix` of one of your direct dependencies, or a prefix thereof. They describe which of your dependencies participate in your crate's C++ public API, as opposed to private use by your crate's implementation. As a general rule, if one of your headers `#include`s something from one of your dependencies, you need to put that dependency's `include_prefix` into `CFG.exported_header_prefixes` (*or* their `links` key into `CFG.exported_header_links`; see below). On the other hand if only your C++ implementation files and *not* your headers are importing from the dependency, you do not export that dependency. The significance of exported headers is that if downstream code (crate **𝒜**) contains an `#include` of a header from your crate (**ℬ**) and your header contains an `#include` of something from your dependency (**𝒞**), the exported dependency **𝒞** becomes available during the downstream crate **𝒜**'s build. Otherwise the downstream crate **𝒜** doesn't know about **𝒞** and wouldn't be able to find what header your header is referring to, and would fail to build. When using `exported_header_prefixes`, your crate must also set a `links` key for itself in Cargo.toml. ### Example Suppose you have a crate with 5 direct dependencies and the `include_prefix` for each one are: - "crate0" - "group/api/crate1" - "group/api/crate2" - "group/api/contrib/crate3" - "detail/crate4" Your header involves types from the first four so we re-export those as part of your public API, while crate4 is only used internally by your cc file not your header, so we do not export: ```rust,noplayground // build.rs use cxx_build::CFG; fn main() { CFG.exported_header_prefixes = vec!["crate0", "group/api"]; cxx_build::bridge("src/bridge.rs") .file("src/impl.cc") .compile("demo"); } ```
For more fine grained control, there is **[`CFG.exported_header_links`][CFG]** (vector of strings) which each refer to the `links` attribute ([*the `links` manifest key*][links]) of one of your crate's direct dependencies. This achieves an equivalent result to `CFG.exported_header_prefixes` by re-exporting a C++ dependency as part of your crate's public API, except with finer control for cases when multiple crates might be sharing the same `include_prefix` and you'd like to export some but not others. Links attributes are guaranteed to be unique identifiers by Cargo. When using `exported_header_links`, your crate must also set a `links` key for itself in Cargo.toml. ### Example ```rust,noplayground // build.rs use cxx_build::CFG; fn main() { CFG.exported_header_links.push("git2"); cxx_build::bridge("src/bridge.rs").compile("demo"); } ```