Skip to content

Conversation

dtolnay
Copy link
Owner

@dtolnay dtolnay commented Oct 8, 2020

This is the second near complete rewrite of cxx-build (following #276) but I am feeling good about this one.

Background

References:

Cargo has some functionality for build scripts where they can emit metadata as key-value pairs to be made available as environment variables to the build scripts of directly dependent crates. This is exactly the limitation that we want to impose. By building on this, we're able to require that your crate declare a direct dependency on the other crate in order to be able to #include their headers in your C++ build. Headers from transitive dependencies are not made available.

Additionally, the key-value metadata feature forces the the dependency's manifest to contain a links key. This is important because Cargo imposes no ordering on the execution of build scripts not having a links key. When exposing a generated header from a dependency, we need to be sure the dependency's build script has already finished executing and emitted that generated header. Prior to this PR, there wasn't necessarily that ordering and builds which included a header from a dependency could flake depending on what order those build scripts happened to be executed by Cargo.

Directory layout

This PR lays out the OUT_DIR as follows. Everything is namespaced under a cxxbridge subdirectory to avoid stomping on other things that the caller's build script might be doing inside OUT_DIR.

$OUT_DIR/
   cxxbridge/
      crate/
         $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
      include/
         rust/
            cxx.h
         $CARGO_PKG_NAME/
            .../
               lib.rs.h
      sources/
         $CARGO_PKG_NAME/
            .../
               lib.rs.cc

Include paths

The generated crate/ and include/ directories are placed on the #include path for the current build as well as for downstream builds that have a direct dependency on the current crate.

We always place include/ before crate/ on the include line so that #include "path/to/file.rs" from C++ magically works and refers to the API generated from that Rust source file. The canonical import path which we'd show in docs is still "path/to/file.rs.h" but I've heard some people really dig the "include a .rs file" style.

@dtolnay dtolnay merged commit 1f7edf8 into master Oct 8, 2020
@dtolnay dtolnay deleted the build branch October 8, 2020 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant