# Crubit: C++/Rust Bidirectional Interop Tool
[![Build status](https://badge.buildkite.com/7a57a14e68aa3a0ab70972cbf2a35fd79d342ba152fee4a5b4.svg)](https://buildkite.com/bazel/crubit)
NOTE: Crubit currently expects deep integration with the build system, and is
difficult to deploy to environments dissimilar to Google's monorepo. We do not
have our tooling set up to accept external contributions at this time.
Crubit is a bidirectional bindings generator for C++ and Rust, with the goal of
integrating the C++ and Rust ecosystems.
## Status
See the [status](http:///overview/status) page for an overview of the
current supported features.
## Example
### C++ {.new-tab}
Consider the following C++ function:
```c++
bool IsGreater(int lhs, int rhs);
```
This function, if present in a header file which is processed by Crubit, becomes
callable from Rust as if it were defined as:
```rs
pub fn IsGreater(lhs: ffi::c_int, rhs: ffi::c_int) -> bool {...}
```
Note: There are some temporary restrictions on the API shape. For example,
functions that accept a type like `std::string` can't be called from Rust
directly via Crubit. These restrictions will be relaxed over time.
### Rust {.new-tab}
Consider the following Rust function:
```rust
pub fn is_greater(lhs: i32, rhs: i32) -> bool { ... }
```
This function becomes callable from C++ as if it were defined as:
```c++
bool is_greater(int32_t lhs, int32_t rhs);
```
Note: There are some temporary restrictions on the API shape. For example,
functions that accept two mutable references can't be called from C++
directly via Crubit. These restrictions will be relaxed over time.
## Getting Started
We have detailed walkthroughs on how to use C++ from Rust, or Rust from C++,
using Crubit, as well as copy-pastable example code. The example code also
includes spanshots of what the generated bindings look like.
* Walkthrough:
[Rust Bindings for C++ Libraries](https://github.com/google/crubit/tree/main/docs/cpp/)
* Examples:
[`examples/cpp/`](http://examples/cpp)
* Walkthrough:
[C++ Bindings for Rust Libraries](https://github.com/google/crubit/tree/main/docs/rust/)
* Examples:
[`examples/rust/`](http://examples/rust)
## Building Crubit
### Cargo
Prerequisites:
* Requires LLVM and Clang libraries to be built and installed.
* They must be built with support for compression (zlib), which is the default
build config.
* Requires Abseil libraries to be built and installed.
* Requires zlib (e.g. libz.so) to be available in the system include and lib
paths.
* An up-to-date stable Rust toolchain.
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:
```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
# Paths for Crubit's cargo to use.
## 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.
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
cargo build --bin rs_bindings_from_cc
```
### Bazel
```sh
apt install clang lld bazel
git clone [email protected]:google/crubit.git
cd crubit
bazel build --linkopt=-fuse-ld=/usr/bin/ld.lld //rs_bindings_from_cc:rs_bindings_from_cc_impl
```
#### Using a prebuilt LLVM tree
```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
cd ../crubit
LLVM_INSTALL_PATH=../llvm-project/install bazel build //rs_bindings_from_cc:rs_bindings_from_cc_impl
```