diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/cxx/book/src/build | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/cxx/book/src/build')
-rw-r--r-- | vendor/cxx/book/src/build/bazel.md | 106 | ||||
-rw-r--r-- | vendor/cxx/book/src/build/cargo.md | 306 | ||||
-rw-r--r-- | vendor/cxx/book/src/build/cmake.md | 47 | ||||
-rw-r--r-- | vendor/cxx/book/src/build/other.md | 81 |
4 files changed, 540 insertions, 0 deletions
diff --git a/vendor/cxx/book/src/build/bazel.md b/vendor/cxx/book/src/build/bazel.md new file mode 100644 index 000000000..6a2c82b00 --- /dev/null +++ b/vendor/cxx/book/src/build/bazel.md @@ -0,0 +1,106 @@ +{{#title Bazel, Buck — Rust ♡ C++}} +## Bazel, Buck, potentially other similar environments + +Starlark-based build systems with the ability to compile a code generator and +invoke it as a `genrule` will run CXX's C++ code generator via its `cxxbridge` +command line interface. + +The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be built +from the *gen/cmd/* directory of the CXX GitHub repo. + +```console +$ cargo install cxxbridge-cmd + +$ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h +$ cxxbridge src/bridge.rs > path/to/bridge.rs.cc +``` + +The CXX repo maintains working Bazel `BUILD` and Buck `BUCK` targets for the +complete blobstore tutorial (chapter 3) for your reference, tested in CI. These +aren't meant to be directly what you use in your codebase, but serve as an +illustration of one possible working pattern. + +```python +# tools/bazel/rust_cxx_bridge.bzl + +load("@bazel_skylib//rules:run_binary.bzl", "run_binary") +load("@rules_cc//cc:defs.bzl", "cc_library") + +def rust_cxx_bridge(name, src, deps = []): + native.alias( + name = "%s/header" % name, + actual = src + ".h", + ) + + native.alias( + name = "%s/source" % name, + actual = src + ".cc", + ) + + run_binary( + name = "%s/generated" % name, + srcs = [src], + outs = [ + src + ".h", + src + ".cc", + ], + args = [ + "$(location %s)" % src, + "-o", + "$(location %s.h)" % src, + "-o", + "$(location %s.cc)" % src, + ], + tool = "//:codegen", + ) + + cc_library( + name = name, + srcs = [src + ".cc"], + deps = deps + [":%s/include" % name], + ) + + cc_library( + name = "%s/include" % name, + hdrs = [src + ".h"], + ) +``` + +```python +# demo/BUILD + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_rust//rust:defs.bzl", "rust_binary") +load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge") + +rust_binary( + name = "demo", + srcs = glob(["src/**/*.rs"]), + deps = [ + ":blobstore-sys", + ":bridge", + "//:cxx", + ], +) + +rust_cxx_bridge( + name = "bridge", + src = "src/main.rs", + deps = [":blobstore-include"], +) + +cc_library( + name = "blobstore-sys", + srcs = ["src/blobstore.cc"], + deps = [ + ":blobstore-include", + ":bridge/include", + ], +) + +cc_library( + name = "blobstore-include", + hdrs = ["include/blobstore.h"], + deps = ["//:core"], +) +``` diff --git a/vendor/cxx/book/src/build/cargo.md b/vendor/cxx/book/src/build/cargo.md new file mode 100644 index 000000000..82ccfb500 --- /dev/null +++ b/vendor/cxx/book/src/build/cargo.md @@ -0,0 +1,306 @@ +{{#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 = "2018" + +[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") + .flag_if_supported("-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 + +<br><br><br> + +# 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"); +} +``` + +<br> + +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"); +} +``` diff --git a/vendor/cxx/book/src/build/cmake.md b/vendor/cxx/book/src/build/cmake.md new file mode 100644 index 000000000..478552e7f --- /dev/null +++ b/vendor/cxx/book/src/build/cmake.md @@ -0,0 +1,47 @@ +{{#title CMake — Rust ♡ C++}} +# CMake + +There is not an officially endorsed CMake setup for CXX, but a few developers +have shared one that they got working. You can try one of these as a starting +point. If you feel that you have arrived at a CMake setup that is superior to +what is available in these links, feel free to make a PR adding it to this list. + +<br> + +--- + +- **<https://github.com/XiangpengHao/cxx-cmake-example>** + + - Supports cross-language link time optimization (LTO) + +--- + +- **<https://github.com/david-cattermole/cxx-demo-example>** + + - Includes a cbindgen component + - Tested on Windows 10 with MSVC, and on Linux + +--- + +- **<https://github.com/trondhe/rusty_cmake>** + + - Alias target that can be linked into a C++ project + - Tested on Windows 10 with GNU target, and on Linux + +--- + +- **<https://github.com/geekbrother/cxx-corrosion-cmake>** + + - Improved rusty_cmake CMake file to use modern C++ + - Rich examples of using different primitive types and Rust's Result return to C++ + - MacOS and Linux only + +--- + +- **<https://github.com/paandahl/cpp-with-rust>** + + - Same blobstore example as the official demo, but inverted languages + - Minimal CMake configuration + - Tested on Linux, macOS, and Windows + +--- diff --git a/vendor/cxx/book/src/build/other.md b/vendor/cxx/book/src/build/other.md new file mode 100644 index 000000000..af835e658 --- /dev/null +++ b/vendor/cxx/book/src/build/other.md @@ -0,0 +1,81 @@ +{{#title Other build systems — Rust ♡ C++}} +# Some other build system + +You will need to achieve at least these three things: + +- Produce the CXX-generated C++ bindings code. +- Compile the generated C++ code. +- Link the resulting objects together with your other C++ and Rust objects. + +*Not all build systems are created equal. If you're hoping to use a build system +from the '90s, especially if you're hoping to overlaying the limitations of 2 or +more build systems (like automake+cargo) and expect to solve them +simultaneously, then be mindful that your expectations are set accordingly and +seek sympathy from those who have imposed the same approach on themselves.* + +### Producing the generated code + +CXX's Rust code generation automatically happens when the `#[cxx::bridge]` +procedural macro is expanded during the normal Rust compilation process, so no +special build steps are required there. + +But the C++ side of the bindings needs to be generated. Your options are: + +- Use the `cxxbridge` command, which is a standalone command line interface to + the CXX C++ code generator. Wire up your build system to compile and invoke + this tool. + + ```console + $ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h + $ cxxbridge src/bridge.rs > path/to/bridge.rs.cc + ``` + + It's packaged as the `cxxbridge-cmd` crate on crates.io or can be built from + the *gen/cmd/* directory of the CXX GitHub repo. + +- Or, build your own code generator frontend on top of the [cxx-gen] crate. This + is currently unofficial and unsupported. + +[cxx-gen]: https://docs.rs/cxx-gen + +### Compiling C++ + +However you like. We can provide no guidance. + +### Linking the C++ and Rust together + +When linking a binary which contains mixed Rust and C++ code, you will have to +choose between using the Rust toolchain (`rustc`) or the C++ toolchain which you +may already have extensively tuned. + +Rust does not generate simple standalone `.o` files, so you can't just throw the +Rust-generated code into your existing C++ toolchain linker. Instead you need to +choose one of these options: + +* Use `rustc` as the final linker. Pass any non-Rust libraries using `-L + <directory>` and `-l<library>` rustc arguments, and/or `#[link]` directives in + your Rust code. If you need to link against C/C++ `.o` files you can use + `-Clink-arg=file.o`. + +* Use your C++ linker. In this case, you first need to use `rustc` and/or + `cargo` to generate a _single_ Rust `staticlib` target and pass that into your + foreign linker invocation. + + * If you need to link multiple Rust subsystems, you will need to generate a + _single_ `staticlib` perhaps using lots of `extern crate` statements to + include multiple Rust `rlib`s. Multiple Rust `staticlib` files are likely + to conflict. + +Passing Rust `rlib`s directly into your non-Rust linker is not supported (but +apparently sometimes works). + +See the [Rust reference's *Linkage*][linkage] page for some general information +here. + +[linkage]: https://doc.rust-lang.org/reference/linkage.html + +The following open rust-lang issues might hold more recent guidance or +inspiration: [rust-lang/rust#73632], [rust-lang/rust#73295]. + +[rust-lang/rust#73632]: https://github.com/rust-lang/rust/issues/73632 +[rust-lang/rust#73295]: https://github.com/rust-lang/rust/issues/73295 |