blob: 7b53f65df83ba82408b6b0ea5a8c32ba447b1750 [file] [view] [edit]
<!-- Part of the Crubit project, under the Apache License v2.0 with LLVM -->
<!-- Exceptions. See /LICENSE for license information. -->
<!-- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -->
# Building
This page is about calling **C++ from Rust** with `rust_api_from_cpp`. If you
want to call Rust from C++, see [C++ bindings for Rust
libraries](../rust/building.md) instead.
## Using `rust_api_from_cpp` in your build
`rust_api_from_cpp` is available in **Bazel**, through the `rules_crubit`
module. See [Bazel](../overview/bazel.md#rust_api_from_cpp) for setup
instructions. Bazel builds the `rs_bindings_from_cc` tool for you, including
the LLVM libraries it depends on, so there is nothing else to install.
<!-- TODO(b/574505910): Link to a rust_api_from_cpp example and CI job once
examples/build_systems/bazel covers it. -->
CMake and Cargo integrations for `rust_api_from_cpp` are planned
<!-- TODO(b/539627008) --> but not available yet. See
[Build System Integrations](../overview/build_systems.md) for the current
status of every build system.
## Building `rs_bindings_from_cc` yourself
If you're integrating Crubit into another build system, you can build the
`rs_bindings_from_cc` binary yourself and run it the way the
[Bazel rules](https://github.com/google/crubit/tree/main/rs_bindings_from_cc/bazel_support)
do.
`rs_bindings_from_cc` is a Rust program that links against Clang's C++
libraries, plus Abseil and Protobuf. It is built against a specific
`llvm-project` commit, pinned in `MODULE.bazel` and updated regularly by CI.
Open-source CI covers Linux x86_64.
There are two ways to build it: with Bazel (which builds LLVM from source for
you) or with Cargo against your own LLVM, Abseil, and Protobuf installation.
### Bazel
This is how Crubit's CI builds the tool. Bazel downloads the Rust and Clang
toolchains, and it builds LLVM from source at the commit pinned in
[`MODULE.bazel`](https://github.com/google/crubit/blob/main/MODULE.bazel).
Because it builds LLVM, the first build takes a long time.
Prerequisites: `bazelisk`, `python3`, and the development headers for zlib,
libxml2, and zstd in `/usr/include`. On Debian or Ubuntu, install them with
`apt install zlib1g-dev libxml2-dev libzstd-dev`.
```sh
git clone https://github.com/google/crubit.git
cd crubit
bazelisk build //rs_bindings_from_cc:rs_bindings_from_cc_main
```
To build against a different `llvm-project` commit, set the
`CRUBIT_LLVM_COMMIT` environment variable to the full commit SHA.
### Cargo, with your own LLVM, Abseil, and Protobuf
This option is for packagers and for projects that already build LLVM, such as
Chromium. CI doesn't test it.
#### Prerequisites
* LLVM and Clang libraries, built and installed from the `llvm-project`
commit pinned in `MODULE.bazel` (or one close to it).
* They must be built with compression support (zlib), which is the
default build config.
* Abseil libraries, built and installed.
* Protobuf libraries and the `protoc` compiler (v27.1 or later), installed.
Crubit's CI uses Protobuf 36.1.
* zlib (for example, `libz.so`) in the system include and lib paths.
* A recent Rust toolchain. In a Crubit checkout, `rustup` automatically
selects the nightly toolchain from `rust-toolchain.toml`.
Linux-specific setup:
```sh
# Choice of compiler is optional.
export CC=/path/to/clang
export CXX=/path/to/clang++
# We must use `lld` linker via clang. It must be in the PATH.
export PATH="$PATH:/dir/containing/lld"
export RUSTFLAGS="$RUSTFLAGS -Clinker=/path/to/clang"
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-fuse-ld=lld"
# If you want to use a sysroot.
# SYSROOT_FLAG=--sysroot=$SYSROOT
# export CXXFLAGS="$CXXFLAGS $SYSROOT_FLAG"
# export RUSTFLAGS="$RUSTFLAGS -Clink-arg=$SYSROOT_FLAG"
```
macOS-specific setup (untested):
```sh
export CC=clang
export CXX=clang++
export RUSTFLAGS="$RUSTFLAGS -Clinker=clang"
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-fuse-ld=lld"
# Point to the Xcode sysroot.
export CXXFLAGS="$CXXFLAGS -isysroot $(xcrun --show-sdk-path)"
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-isysroot -Clink-arg=$(xcrun --show-sdk-path)"
```
Windows-specific setup:
* **Windows is currently unsupported**, and the APIs generated by Crubit may
not compile and will change over time.
* All commands must be run from a development shell, where MSVC environment
variables are set up.
```sh
# We use clang compiler (clang-cl); MSVC may work too but is unsupported.
export CC=clang-cl
export CXX=clang-cl
# We must use lld to link, which is spelt lld-link. So user-specified linker
# flags must be in MSVC format.
export RUSTFLAGS="$RUSTFLAGS -Clinker=/path/to/lld-link"
# LLVM was built with Zlib support. Point Crubit to the same library.
export CXXFLAGS="$CXXFLAGS /I/path/to/zlib"
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=/LIBPATH:/path/to/zlib"
# Avoid deprecation warnings.
export CXXFLAGS="$CXXFLAGS /D_CRT_SECURE_NO_DEPRECATE"
# If LLVM (-DCMAKE_MSVC_RUNTIME_LIBRARY) and Abseil (-DABSL_MSVC_STATIC_RUNTIME)
# are built against static CRT, then Rust needs to match, or vice-versa.
# export RUSTFLAGS="$RUSTFLAGS -Ctarget-feature=+crt-static"
```
Run the build step via cargo:
```sh
# Pre-generate the C++ headers for Crubit's own .proto files. This avoids
# races during the parallel Cargo build.
python3 cargo/build/generate_proto_headers.py \
--protoc=/path/to/protoc --out_dir=/path/to/generated_headers
export PROTOC=/path/to/protoc
# Paths for Crubit's cargo to use. Most accept a comma-separated list.
## This path contains clang/ and llvm/ dirs with their respective headers.
export CLANG_INCLUDE_PATH=/path/to/llvm/and/clang/headers
## This path contains libLLVM*.a and libclang*.a. On Windows it may also hold the
## import libraries of LLVM's DLLs (LLVM-C.lib and friends); those are recognised by
## their contents and skipped, so the whole `lib` dir can be given as-is.
export CLANG_LIB_STATIC_PATH=/path/to/llvm/and/clang/libs
## This path contains absl/ dir with all the includes.
export ABSL_INCLUDE_PATH=/path/to/absl/include/dir
## This path contains libabsl_*
export ABSL_LIB_STATIC_PATH=/path/to/absl/libs
## These paths contain google/protobuf/ dir with all the includes, and the
## headers generated above.
export PROTOBUF_INCLUDE_PATH=/path/to/protobuf/include/dir,/path/to/generated_headers
## This path contains libprotobuf.a and libutf8_validity.a. Other archives that a
## protobuf install tree holds (libutf8_range.a, libprotobuf-lite.a, libprotoc.a,
## libupb.a) are ignored; the first two would collide with the ones above.
export PROTOBUF_LIB_STATIC_PATH=/path/to/protobuf/libs
# Tell Crubit which LLVM it is compiled against, as the commit date (YYYYMMDD) of
# your llvm-project checkout.
LLVM_DATE=$(python3 cargo/build/get_llvm_commit_date.py <llvm_commit_sha>)
export CXXFLAGS="$CXXFLAGS -DCRUBIT_LLVM_DEV_DATE=${LLVM_DATE}"
cargo build --locked --release -p rs_bindings_from_cc
```
[Cargo build of Crubit](../overview/cargo_build.md#custom-build-systems-chromium-android-or-other-projects)
explains each of these variables in more detail.
If you need to build LLVM and Clang yourself, here is an example:
```sh
git clone https://github.com/llvm/llvm-project
cd llvm-project
CC=clang CXX=clang++ cmake -S llvm -B build -DLLVM_ENABLE_PROJECTS='clang' -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install
cmake --build build -j
# wait...
cmake --install build
```