Safe interop between Rust and C++

Overview

CXX — safe FFI between Rust and C++

github crates.io docs.rs build status

This library provides a safe mechanism for calling C++ code from Rust and Rust code from C++, not subject to the many ways that things can go wrong when using bindgen or cbindgen to generate unsafe C-style bindings.

This doesn't change the fact that 100% of C++ code is unsafe. When auditing a project, you would be on the hook for auditing all the unsafe Rust code and all the C++ code. The core safety claim under this new model is that auditing just the C++ side would be sufficient to catch all problems, i.e. the Rust side can be 100% safe.

[dependencies]
cxx = "1.0"

[build-dependencies]
cxx-build = "1.0"

Compiler support: requires rustc 1.48+ and c++11 or newer
Release notes


Guide

Please see https://cxx.rs for a tutorial, reference material, and example code.


Overview

The idea is that we define the signatures of both sides of our FFI boundary embedded together in one Rust module (the next section shows an example). From this, CXX receives a complete picture of the boundary to perform static analyses against the types and function signatures to uphold both Rust's and C++'s invariants and requirements.

If everything checks out statically, then CXX uses a pair of code generators to emit the relevant extern "C" signatures on both sides together with any necessary static assertions for later in the build process to verify correctness. On the Rust side this code generator is simply an attribute procedural macro. On the C++ side it can be a small Cargo build script if your build is managed by Cargo, or for other build systems like Bazel or Buck we provide a command line tool which generates the header and source file and should be easy to integrate.

The resulting FFI bridge operates at zero or negligible overhead, i.e. no copying, no serialization, no memory allocation, no runtime checks needed.

The FFI signatures are able to use native types from whichever side they please, such as Rust's String or C++'s std::string, Rust's Box or C++'s std::unique_ptr, Rust's Vec or C++'s std::vector, etc in any combination. CXX guarantees an ABI-compatible signature that both sides understand, based on builtin bindings for key standard library types to expose an idiomatic API on those types to the other language. For example when manipulating a C++ string from Rust, its len() method becomes a call of the size() member function defined by C++; when manipulating a Rust string from C++, its size() member function calls Rust's len().


Example

In this example we are writing a Rust application that wishes to take advantage of an existing C++ client for a large-file blobstore service. The blobstore supports a put operation for a discontiguous buffer upload. For example we might be uploading snapshots of a circular buffer which would tend to consist of 2 chunks, or fragments of a file spread across memory for some other reason.

A runnable version of this example is provided under the demo directory of this repo. To try it out, run cargo run from that directory.

#[cxx::bridge]
mod ffi {
    // Any shared structs, whose fields will be visible to both languages.
    struct BlobMetadata {
        size: usize,
        tags: Vec<String>,
    }

    extern "Rust" {
        // Zero or more opaque types which both languages can pass around but
        // only Rust can see the fields.
        type MultiBuf;

        // Functions implemented in Rust.
        fn next_chunk(buf: &mut MultiBuf) -> &[u8];
    }

    unsafe extern "C++" {
        // One or more headers with the matching C++ declarations. Our code
        // generators don't read it but it gets #include'd and used in static
        // assertions to ensure our picture of the FFI boundary is accurate.
        include!("demo/include/blobstore.h");

        // Zero or more opaque types which both languages can pass around but
        // only C++ can see the fields.
        type BlobstoreClient;

        // Functions implemented in C++.
        fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
        fn put(&self, parts: &mut MultiBuf) -> u64;
        fn tag(&self, blobid: u64, tag: &str);
        fn metadata(&self, blobid: u64) -> BlobMetadata;
    }
}

Now we simply provide Rust definitions of all the things in the extern "Rust" block and C++ definitions of all the things in the extern "C++" block, and get to call back and forth safely.

Here are links to the complete set of source files involved in the demo:

To look at the code generated in both languages for the example by the CXX code generators:

   # run Rust code generator and print to stdout
   # (requires https://github.com/dtolnay/cargo-expand)
$ cargo expand --manifest-path demo/Cargo.toml

   # run C++ code generator and print to stdout
$ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs

Details

As seen in the example, the language of the FFI boundary involves 3 kinds of items:

  • Shared structs — their fields are made visible to both languages. The definition written within cxx::bridge is the single source of truth.

  • Opaque types — their fields are secret from the other language. These cannot be passed across the FFI by value but only behind an indirection, such as a reference &, a Rust Box, or a UniquePtr. Can be a type alias for an arbitrarily complicated generic language-specific type depending on your use case.

  • Functions — implemented in either language, callable from the other language.

Within the extern "Rust" part of the CXX bridge we list the types and functions for which Rust is the source of truth. These all implicitly refer to the super module, the parent module of the CXX bridge. You can think of the two items listed in the example above as being like use super::MultiBuf and use super::next_chunk except re-exported to C++. The parent module will either contain the definitions directly for simple things, or contain the relevant use statements to bring them into scope from elsewhere.

Within the extern "C++" part, we list types and functions for which C++ is the source of truth, as well as the header(s) that declare those APIs. In the future it's possible that this section could be generated bindgen-style from the headers but for now we need the signatures written out; static assertions will verify that they are accurate.

Your function implementations themselves, whether in C++ or Rust, do not need to be defined as extern "C" ABI or no_mangle. CXX will put in the right shims where necessary to make it all work.


Comparison vs bindgen and cbindgen

Notice that with CXX there is repetition of all the function signatures: they are typed out once where the implementation is defined (in C++ or Rust) and again inside the cxx::bridge module, though compile-time assertions guarantee these are kept in sync. This is different from bindgen and cbindgen where function signatures are typed by a human once and the tool consumes them in one language and emits them in the other language.

This is because CXX fills a somewhat different role. It is a lower level tool than bindgen or cbindgen in a sense; you can think of it as being a replacement for the concept of extern "C" signatures as we know them, rather than a replacement for a bindgen. It would be reasonable to build a higher level bindgen-like tool on top of CXX which consumes a C++ header and/or Rust module (and/or IDL like Thrift) as source of truth and generates the cxx::bridge, eliminating the repetition while leveraging the static analysis safety guarantees of CXX.

But note in other ways CXX is higher level than the bindgens, with rich support for common standard library types. Frequently with bindgen when we are dealing with an idiomatic C++ API we would end up manually wrapping that API in C-style raw pointer functions, applying bindgen to get unsafe raw pointer Rust functions, and replicating the API again to expose those idiomatically in Rust. That's a much worse form of repetition because it is unsafe all the way through.

By using a CXX bridge as the shared understanding between the languages, rather than extern "C" C-style signatures as the shared understanding, common FFI use cases become expressible using 100% safe code.

It would also be reasonable to mix and match, using CXX bridge for the 95% of your FFI that is straightforward and doing the remaining few oddball signatures the old fashioned way with bindgen and cbindgen, if for some reason CXX's static restrictions get in the way. Please file an issue if you end up taking this approach so that we know what ways it would be worthwhile to make the tool more expressive.


Cargo-based setup

For builds that are orchestrated by Cargo, you will use a build script that runs CXX's C++ code generator and compiles the resulting C++ code along with any other C++ code for your crate.

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.

# Cargo.toml

[build-dependencies]
cxx-build = "1.0"
// 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");
}

Non-Cargo setup

For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate way of invoking the C++ code generator as a standalone command line tool. The tool is packaged as the cxxbridge-cmd crate on crates.io or can be built from the gen/cmd directory of this repo.

$ cargo install cxxbridge-cmd

$ cxxbridge src/main.rs --header > path/to/mybridge.h
$ cxxbridge src/main.rs > path/to/mybridge.cc

Safety

Be aware that the design of this library is intentionally restrictive and opinionated! It isn't a goal to be powerful enough to handle arbitrary signatures in either language. Instead this project is about carving out a reasonably expressive set of functionality about which we can make useful safety guarantees today and maybe extend over time. You may find that it takes some practice to use CXX bridge effectively as it won't work in all the ways that you are used to.

Some of the considerations that go into ensuring safety are:

  • By design, our paired code generators work together to control both sides of the FFI boundary. Ordinarily in Rust writing your own extern "C" blocks is unsafe because the Rust compiler has no way to know whether the signatures you've written actually match the signatures implemented in the other language. With CXX we achieve that visibility and know what's on the other side.

  • Our static analysis detects and prevents passing types by value that shouldn't be passed by value from C++ to Rust, for example because they may contain internal pointers that would be screwed up by Rust's move behavior.

  • To many people's surprise, it is possible to have a struct in Rust and a struct in C++ with exactly the same layout / fields / alignment / everything, and still not the same ABI when passed by value. This is a longstanding bindgen bug that leads to segfaults in absolutely correct-looking code (rust-lang/rust-bindgen#778). CXX knows about this and can insert the necessary zero-cost workaround transparently where needed, so go ahead and pass your structs by value without worries. This is made possible by owning both sides of the boundary rather than just one.

  • Template instantiations: for example in order to expose a UniquePtr<T> type in Rust backed by a real C++ unique_ptr, we have a way of using a Rust trait to connect the behavior back to the template instantiations performed by the other language.


Builtin types

In addition to all the primitive types (i32 <=> int32_t), the following common types may be used in the fields of shared structs and the arguments and returns of functions.

name in Rust name in C++ restrictions
String rust::String
&str rust::Str
&[T] rust::Slice<const T> cannot hold opaque C++ type
&mut [T] rust::Slice<T> cannot hold opaque C++ type
CxxString std::string cannot be passed by value
Box<T> rust::Box<T> cannot hold opaque C++ type
UniquePtr<T> std::unique_ptr<T> cannot hold opaque Rust type
SharedPtr<T> std::shared_ptr<T> cannot hold opaque Rust type
[T; N] std::array<T, N> cannot hold opaque C++ type
Vec<T> rust::Vec<T> cannot hold opaque C++ type
CxxVector<T> std::vector<T> cannot be passed by value, cannot hold opaque Rust type
fn(T, U) -> V rust::Fn<V(T, U)> only passing from Rust to C++ is implemented so far
Result<T> throw/catch allowed as return type only

The C++ API of the rust namespace is defined by the include/cxx.h file in this repo. You will need to include this header in your C++ code when working with those types.

The following types are intended to be supported "soon" but are just not implemented yet. I don't expect any of these to be hard to make work but it's a matter of designing a nice API for each in its non-native language.

name in Rust name in C++
BTreeMap<K, V> tbd
HashMap<K, V> tbd
Arc<T> tbd
Option<T> tbd
tbd std::map<K, V>
tbd std::unordered_map<K, V>

Remaining work

This is still early days for CXX; I am releasing it as a minimum viable product to collect feedback on the direction and invite collaborators. Please check the open issues.

Especially please report issues if you run into trouble building or linking any of this stuff. I'm sure there are ways to make the build aspects friendlier or more robust.

Finally, I know more about Rust library design than C++ library design so I would appreciate help making the C++ APIs in this project more idiomatic where anyone has suggestions.


License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Comments
  • Need an explicit way for cxxbridge to produce header/source file

    Need an explicit way for cxxbridge to produce header/source file

    The cxxbridge-cmd is not ideal:

    1. The cxxbridge-cmd version might be different from cxx version, which can cause problems
    2. It's hard to track file changes outside rust project, i.e. determine the best time to re-generate the header/source file

    I used the side-effect from cxx_build::bridge(...) to generate the necessary files https://github.com/XiangpengHao/cxx-cmake-example/blob/27dfab58ff4888d4ede71fdad45a7d112640d2b0/rust_part/build.rs#L2 and then copy those files to desired locations https://github.com/XiangpengHao/cxx-cmake-example/blob/27dfab58ff4888d4ede71fdad45a7d112640d2b0/rust_part/CMakeLists.txt#L20

    It would be great if we have some ways to explictly write the ouput file, maybe something like

    // build.rs
    fn main() {
        cxx_build::bridge("src/lib.rs").header("/path/lib.rs.h").source("/path/lib.rs.cpp");
    
        println!("cargo:rerun-if-changed=src/lib.rs");
    }
    
    integration 
    opened by XiangpengHao 18
  • Generation of cxx::bridge from existing C++ code

    Generation of cxx::bridge from existing C++ code

    The cxx help says:

    It would be reasonable to build a higher level bindgen-like tool on top of CXX which consumes a C++ header ... as source of truth and generates the cxx::bridge, eliminating the repetition while leveraging the static analysis safety guarantees of CXX.

    It is looking to me like that's exactly the model we may need in order to get permission to use Rust within the large codebase in which I work.

    Could we use this issue to speculate about how this might work? It's not something I'm about to start hacking together, but it's conceivable that we could dedicate significant effort in the medium term, if we can become convinced of a solid plan.

    Here are my early thoughts.

    Note that C++ remains the undisputed ruler in our codebase, so all of this is based around avoiding any C++ changes whatsoever. That might not be practical.

    Bits of cxx to keep unchanged

    • Built-in types (notably, which objects can be passed by reference/pointer/etc.... a major concern about Rust/C++ interop in my organisation is that C++ objects often have internal pointers; the fact that you can't pass them by value into Rust within cxx neatly sidesteps that concern)
    • C++-side and Rust-side shim generation
    • Magical emergent behavior where an unsafe keyword is only used if you're doing something that actually is a bit iffy with C++ object lifetimes
    • Declaration of any Rust functions which C++ should be able to call (for now). This proposal only talks about calls from Rust into C++.
    • The fact that the wrapper shims should work nicely with cross-language LTO inlining and thus (in the optimal case where there are no type conversions) shrink down to nothing
    • cxxbridge tool.

    Bits where we'll need to do something different

    • No cxx::bridge section. Instead, declarations are read from C++ headers. A simple include_cpp! macro instead. ("Simple" in the user's sense, very much not in the implementation sense, where we'd need to replicate much of bindgen)
    • Generation of C++ wrapper functions only for those which are actually used. An include_cpp! macro may pull in hundreds of header files with thousands of functions. The cxxbridge C++-generation tool would have to work incredibly hard for every .rs file if it generated wrappers for each one. So, instead, the call sites into C++ from Rust would probably need to be recognizable by that tool such that it could generate the minimum number of shims. (Procedural macro in statement position? cpp_call!?)
    • Perhaps some way to avoid duplication of cxxbridge effort if hundreds of .rs files use the same include_cpp! macro(s). This might be purely a build-system thing; I haven't thought it through.
    • If such a function call refers to a struct which can be represented in cxx::bridge (e.g. because it contains only unique_ptrs and ints) then said struct is fully defined such that it's accessible to both Rust and C++. If a struct is not representable in cxx then it is declared in the virtual cxx::bridge as an opaque type (and thus can only be referenced from unique_ptrs etc.)
    • Passing the C++ include paths and #defines into rustc. I can't think of a better way to do this than to rely on the env! macro. Ugh.
    • If Rust code calls a C++ function which can't be translated, a compile-time error occurs with information about why cxx can't handle it (e.g. C++ object passed by value). Ideally this could (in future) be improved by C++ annotations that tell Rust users where and how to use a wrapper function that may already have been defined (input to clippy/rust-analyzer/etc. in future? Highly ambitious.)
    • This involves a possible mindset shift. At the moment, we're using cxx in localized places where it wraps up C++ function calls with an idiomatic Rust wrapper. This proposal involves instead allowing production Rust code to freely call C++ classes and functions. There may be some major leaps here to make this practical, which I might not have thought of (as I say, these are early thoughts...)
    • A few things orthogonal to this feature and beyond the scope of this issue: class method calls, enums, extensible support for our shared pointer types, etc.

    Next steps our side

    • We need to list out the sorts of C++ function calls and class accesses which typical Rust code would need to do in our codebase. We then need to analyze the types involved and find out if this plan is actually practical for our codebase. If we find a significant proportion of likely function calls involve passing C++ types by value that can't be represented by cxx, we're in trouble. My hope is that this isn't the case, but work is required to figure this out.

    Meanwhile though I wanted to raise this to find out if this is the sort of thing you were thinking, when you wrote that comment in the docs!

    integration 
    opened by adetaylor 12
  • WIP: Embedding Rust into a C++ CMake project

    WIP: Embedding Rust into a C++ CMake project

    It's not a real PR, more like a question about the demo code in demo-cxx/ and demo-rs/.

    The setup is an existing C++ CMake project, the goal is to be able to add Rust code to it. The C++ project is internally structured as a main application and shared libraries. In this demo we will have a main C++ application and a shared library. The shared library will be entirely in Rust except for the interface, the FFI will provide the C++ interface so the main application could link to it as to a regular C++ shared library.

    I haven't found any main.cpp in the demo-cxx/ or demo-rs/, so there is probably a space for this kind of demo.

    The first step is creating the demo-cmake/ dir, dumping the cmake-cargo into it, fixing workspace errors. Then testing their build:

    mkdir ../build
    cd ../build
    cmake ../cxx/demo-cmake
    make -j
    

    The application of interest is demo-cmake/test/rust2cpp, it does the C-like variation of what we want. So the second step is adding parts of demo-cxx/ and demo-rs/ to that application (main.rs turns into lib.rs, demo.h turns into a pure-C++ interface for the library).

    There are minor things such as: hardcoded include paths in demo.cc and build.rs, hardcoded cxx dependency path, cxxbridge complaining about the "target path" that has to end with "target" but instead ends with "out". I'm currently looking into this error that occurs while building the library:

    src/lib.rs:1:1: error[E0658]: custom attributes cannot be applied to modules
    

    So it doesn't compile yet. I suppose most of the work that is left is related to the Rust/cxx build system side.

    Suggestions welcome. Maybe I've missed an obvious solution or maybe somebody has already done such an integration.

    opened by ChipmunkV 11
  • C++ std::vector<T> and Rust std::vec::Vec<T> support

    C++ std::vector and Rust std::vec::Vec support

    I've hacked in some preliminary std::vector<T> support to allow passing C++ vectors to Rust.

    https://github.com/myronahn/cxx/tree/master

    Right now it works for std::vector<uint8_t> since that was my primary need but it would be very easy to add in support for all the basic types.

    Adding support for general types is a bit harder as the orphan rule is keeping me from defining macro-expanded trait impls for both the Vector class and the UniquePtr class. I'm currently wondering what the best workaround would be for this.

    It would be great to get a once-over from you if you have any spare time to take a look. Is it worth continuing work on this, or are you in the middle of implementing something bigger/better?

    Thanks in advance.

    new binding 
    opened by myronahn 11
  • Define shared struct in separate file

    Define shared struct in separate file

    Hello to everybody. Is it possible to define shared structs in a separate file?

    Use case: I have generated Rust structs from a Protobuf definition and would like to expose them as shared structs in my bridge definition. From what I can tell, the fields on the generated structs are supported (except Option, but I saw its WIP). As a workaround, I tried to use the include! Macro in the bridge definition, Unfortunately, it doesn't work.

    another question Until the Option enum becomes supported, is there a temporary solution I can use to move Option in a shared struct?

    opened by ShayMusachanov-dev 10
  • Support for using shared types from one bridge in another bridge module

    Support for using shared types from one bridge in another bridge module

    I've been working on introducing cxx to Fuchsia as a safer, better way for us to write Rust/C++ FFIs. As part of this, I'd like to provide a library or two with some common types for others to reuse in their own FFIs.

    For example, see the handle types from #274; these would be a bridge between our C++ and Rust handle wrappers. These are important to write once and reuse because there's a lot of ways to implement them in a way that would cause resource leaks. Another example is a reusable Result type; we don't use exceptions and panicking on every error result is undesirable.

    To do this, I'd like to be able to reuse shared types defined in one bridge module in another bridge module without having to treat them as opaque Rust types in the using module (so that they can be passed by value without boxing). Today these seem to just be recognized as unsupported types. For example:

    // handle.rs
    #[cxx::bridge(namespace = zx::ffi)]
    mod ffi {
        struct Process {
            raw: u32,
        }
    
        struct Job {
            raw: u32,
        }
    
        // ... and so on
    }
    
    impl Drop for ffi::Process { ... }
    impl Drop for ffi::Job { ... }
    // ... and so on, From impls to convert, etc.
    
    // usage.rs
    #[cxx::bridge(namespace = my_usage::ffi)]
    mod ffi {
        extern "Rust" {
            fn create_process(name: &CxxString, job: &handle::ffi::Job) -> handle::ffi::Process;
        }
    }
    
    opened by sbrocket 10
  • Cannot generate rust bindings for fbx c++ library

    Cannot generate rust bindings for fbx c++ library

    Hello! I'm trying to generate rust bindings for the autodesk fbx c++ library to be able to use the fbx functionalities inside a rust application. The fbx library is comprised of precompiled dynamic libraries and header files and it's publicly available. I created a build.rs file like this:

    fn main() {
        println!("cargo:rustc-link-search=/path/to/lib/gcc/x64/release/"); // path to the compiled fbx library
        println!("cargo:rustc-link-lib=fbxsdk");
    
        cxx_build::bridge("src/main.rs")
            .flag_if_supported("-std=c++11")
            .include("/path/to/lib/include")  // path to the fbx headers files
            .compile("cxxbridge-demo");
        println!("cargo:rerun-if-changed=src/main.rs");
        println!("cargo:rerun-if-changed=src/shim.h");
    }
    

    My main.rs file is like this:

    #[cxx::bridge]
    mod ffi {
        unsafe extern "C++" {
            include!("testcxx/lib/include/fbxsdk.h");
            include!("testcxx/src/shim.h");
    
            type FbxManager;
    
            fn FbxManager_Create() -> UniquePtr<FbxManager>;
        }
    }
    fn main() {
        let mgr = ffi::FbxManager_Create();
    }
    

    In shim.h I tried to create a shim for the FbxManager::Create() static method which is usually the first method called to initilaize the library. This is shim.h

    #pragma once
    #include <fbxsdk.h>
    #include <memory>
    
    std::unique_ptr<FbxManager> FbxManager_Create() {
        return std::unique_ptr<FbxManager>(FbxManager::Create());
    }
    

    When I run cargo build with this situation I get an ld error that says:

    path/to/testcxx/target/debug/build/testcxx-59666266ff383069/out/libcxxbridge-demo.a(main.rs.o): in function `FbxManager_Create()':
              /path/to/testcxx/target/debug/build/testcxx-59666266ff383069/out/cxxbridge/crate/testcxx/src/shim.h:6: undefined reference to `fbxsdk::FbxManager::Create()'
              collect2: error: ld returned 1 exit status
    

    I would like to ask help for this specific case but also how in general I should behave when trying to bind to c++ static methods and creating instances of c++ classes. Many thanks, Frank

    opened by franksl 9
  • Using msvc and crt-static

    Using msvc and crt-static

    Moved from https://github.com/dtolnay/cxx/pull/927#issuecomment-911138782.

    It looks like the target-features don't flow from the top crate down to the crates it consumes, at least not if it's scoped to the package's own .cargo/config.toml. If I only set this in my project's .cargo/config.toml, when it builds cxx, the flag is missing and it's not listed in the CARGO_CFG_TARGET_FEATURE output for cxx, but it is used in my project.

    It turns out cc also has support for this already by default 😄, but because it's not flowing from the top-level package config.toml down to its dependencies and their dependencies, it doesn't kick in. It does work if you set the RUSTFLAGS environment variable before running cargo, and it works for user-wide ~/.cargo/config.toml as well, but this would let a consumer handle it automatically with feature flags in the Cargo.toml.

    opened by dtolnay 9
  • ExternTypes may be safely passed and returned by value

    ExternTypes may be safely passed and returned by value

            unsafe impl cxx::ExternType for bindgen::Bob {
                type Id = cxx::type_id!("Bob");
            }
            mod bindgen {
                #[repr(C)]
                pub struct Bob {
                    pub a: u32,
                    pub b: u32,
                }
            }
            #[cxx::bridge]
            pub mod cxxbridge {
                extern "C" {
                    include!("input.h");
                    pub fn give_bob() -> Bob;
                    type Bob = super::bindgen::Bob;
                }
            }
    

    doesn't work because we can't return ExternTypes by value.

    Each extern type may be one of three fundamental categories of type:

    • An alias to another cxx::bridge type (in which case it's a simple alias and we don't do anything in the current instantiation)
    • A type which is_trivially_move_constructible && is_trivially_destructible. If so, we allow allow it to be passed by value into/our of cxx types, and we check this with static_asserts as discussed in #280. ("trivial" types for short henceforth)
    • A type which isn't trivially move constructable/destructable. In these cases we don't allow use by value but we do allow generation of UniquePtr traits etc. as per #312.

    This distinction is implied by #280 but this could be done as a pre-requisite step first. I also feel it would be desirable to pin this down before finalizing design for #312.

    The question is, for a given ExternType, how does cxx know which of these three categories of type it is? What's your plan there? Is it to require the developer to implement an extra trait for trivial types which is then checked for safety using static_assert? Or did you plan to do something funky to auto-detect trivial types at build time?

    (NB for this last category of types, my higher-level code generator plans to create shims which allow us to call pre-existing C++ APIs that take a T by instead passing a UniquePtr<T>. I have yet to do this bit. It makes superficial sense that "complicated" types need to be entirely allocated, accessed, and managed within C++ but can still be owned by Rust. Figuring out whether this is ergonomic in practice is arguably the entire point of my https://github.com/google/autocxx experiments... if this doesn't work out it's back to the drawing board!)

    opened by adetaylor 9
  • Implement shared type aliases from another bridge module

    Implement shared type aliases from another bridge module

    This is still a WIP but the core of this is working now. Two main things to do:

    • Figure out how to handle both bridges trying to emit the Vec/Box functions, and how to make usage in UniquePtr/CxxVector work if the remote bridge doesn't use the shared type in that way
    • Clean up TODOs about adding ui tests

    My other PR (#298) will also need to rebased on this or vice versa. The first 4 commits here are duplicated between them.

    Fixes #297

    opened by sbrocket 9
  • Switch to workspace dir as the include path

    Switch to workspace dir as the include path

    This commit reworks how files are placed so that anyone who overrides CARGO_TARGET_DIR or the associated cargo config setting will be able to use the crate. It is a breaking change because the cargo manifest directory is now included by default, not the directory that is the parent of the target directory. It also places the rust/cxx.h file in $OUT_DIR/cxxbridge instead of inside of $TARGET_DIR/cxxbridge. This also removes the need to symlink it.

    overtaken by events 
    opened by tylerhawkes 9
  • Support rust `char` binding, mapping to new cpp `rust::Char`

    Support rust `char` binding, mapping to new cpp `rust::Char`

    Proof of concept to support the rust type char which is mapped to rust::Char.

    This should be seen as the rust counterpart to https://github.com/dtolnay/cxx/pull/725, and address the other part of https://github.com/dtolnay/cxx/issues/592.

    If this is approved, next steps/questions I can think of:

    • [ ] Can we use the rust's char::from_u32 to validate the unicode value? (currently it's a copy of it)
    • [ ] Can cpp's rust::Char be made a POD?
    • [ ] What should be the scope of the API of cpp rust::Char? Currently intentionally minimal
    • [ ] More tests (at least for each supported type in do_typecheck)
    • [ ] Documentation
    opened by kraktus 0
  • Adding helper methods to `cxx_gen` for higher level code generators

    Adding helper methods to `cxx_gen` for higher level code generators

    I couldn't see this discussed before (?), sorry if it has been.

    Would it be accepted to add some helper methods to cxx_gen (or elsewhere?) for higher level code generators ? (If such methods would be accepted I would be happy to help contribute code to do this.)

    In CXX-Qt we have a few places where it'd be useful for reuse some of the code from CXX itself rather than our fragile reimplementation of things, and other code generators using CXX may find this useful (eg maybe autocxx?). Furthermore this prevents breakage if CXX changes what it generates or adds support for more types.

    Some of the possible scenarios we have come across so far that would be useful (note that API are just examples and could be different).

    Retrieving the C++ name for a Rust type

    This is useful when we are generating extra C++ code for Rust CXX bridges and need to match the type names for parameters or return types.

    For a given syn::Type or syn::ReturnType it would be useful if there was a cxx_gen method to retrieve the corresponding C++ type name.

    Note that this would also have to consider any namespaces and cxx_name attributes from the bridge.

    For example with the following extern C++ block

    #[namespace = "my_namespace"]
    unsafe extern "C++" {
      #[cxx_name = "B"]
      type A;
    }
    

    If A is used as a type within a method, we need to have generation code to go from A to ::my_namespace::B. (and any other conversions need to occur like for UniquePtr or function pointers etc).

    Would something like the following in cxx_gen be accepted?

    pub fn syn_type_to_cxx_type(ty: &syn::Type, cxx_name_map: &BTreeMap<String, String>, namespace_map: &BTreeMap<String, String>) -> String {
        // calculates ::my_namespace::B from
        //  - reads syn::Type A
        //  - cxx_name_map with A -> B
        //  - namespace_map of A -> my_namespace
    }
    

    There would also likely need to be a similar method for syn::ReturnType as Result<T> can be used just in returns from my understanding (?).

    Determining if the type is unsafe for CXX bridges

    If certain types are used in CXX bridge functions the method needs to be marked as unsafe, eg if you use *mut T. Being able to determine by asking CXX which of it's supported types are unsafe would be much better than having to chase any new types.

    Would something like the following in cxx_gen be accepted?

    pub fn syn_type_is_cxx_bridge_unsafe(ty: &syn::Type) -> bool {
       // determine if syn::Type is unsafe
    }
    

    Retrieving the C++ bridge method name for a Rust method

    In more advanced cases we need to friend the CXX bridge method (this is so that we can call protected methods from a C++ base class from Rust) it would be good if there was a helper to provide us the method name.

    For example with the following CXX block

    #[namespace = "my_namespace"]
    unsafe extern "C++" {
        #[cxx_name = "B"]
        type A;
        fn method(self: &A);
    }
    

    CXX generates internal method names such as my_namespace$cxxbridge1$B$method.

    Would something like the following in cxx_gen be accepted?

    pub fn method_to_cxx_bridge_function_name(method: &syn::Ident, self_ty: Option<&syn::Type>, cxx_name_map: &BTreeMap<String, String>, namespace_map: &BTreeMap<String, String>) -> String {
        // calculates my_namespace$cxxbridge1$B$method from
        //  - reads the method ident "method"
        //  - reads the syn::Type Some(&A)
        //  - cxx_name_map with A -> B
        //  - namespace_map of method -> my_namespace
    }
    
    opened by ahayzen-kdab 2
  • cxxbridget has err

    cxxbridget has err "th name xxx is defined multiple times"

    image When I add another mod to the code in the demo, and reusing existing bingding types. I use the cxxbrdge command to generate the header file, the following error will be reported image

    opened by eric642 0
  • C++ constructor

    C++ constructor

    Hi

    I have a question, how can I use constructor C++ class with this library ?

    #[cxx::bridge(namespace = "svglib")]
    mod ffi {
        struct Fill {
            fill: String
        }
    
        struct Stroke {
            stroke: String,
            stroke_width: f32
        }
    
        //struct Circle {
        //    properties: SvgProperties
        //}
    
        unsafe extern "C++" {
            include!("../../../Sources/svglib/include/svglib.h");
            type Circle;
            pub fn Circle(fill: Fill, stroke: Stroke) -> Circle;
            pub fn generate(x: f32, y: f32, r: f32) -> String;
        }
    }
    

    With this code I have:

    error: needs a cxx::ExternType impl in order to be used as a return value of `Circle`
    

    When I add:

        struct Circle {
            properties: SvgProperties
        }
    
    error: linking with `cc` failed: exit status: 1
       = note: Undefined symbols for architecture x86_64:
                "svglib::Circle::generate(double, double, double)", referenced from:
                    _theme_astral_svg in libsweinterfacelib.a(SweInterface.o)
                "svglib::Circle::Circle(svglib::Fill, svglib::Stroke)", referenced from:
                    _theme_astral_svg in libsweinterfacelib.a(SweInterface.o)
              ld: symbol(s) not found for architecture x86_64
              clang: error: linker command failed with exit code 1 (use -v to see invocation)
    
    opened by stephaneworkspace 0
  • Attempting to replicate the PImpl style found in demo, but method not found in UniquePtr<T>

    Attempting to replicate the PImpl style found in demo, but method not found in UniquePtr

    I am quite close to the finish line.. of wrapping a 3rd party C++ library with CXX so I can stop coding C++ and join the Rust hype train.. I am seeing the following error.. it feels like this is just my ignorance of C++ .. that my function signature is not quite matching .. any advice is appreciated

    Main.RS

    #[cxx::bridge(namespace = "com::enserio")]
    mod ffi {
        unsafe extern "C++" {
            include!("twsapi_grpc_server/include/twsapi-client.h");
            include!("twsapi_grpc_server/include/AvailableAlgoParams.h");
            include!("twsapi_grpc_server/include/AccountSummaryTags.h");
            include!("twsapi_grpc_server/include/Utils.h");
    
            type TWSApiClient;
    
            fn new_twsapi_client() -> UniquePtr<TWSApiClient>;
            fn connect(self: Pin<&mut TWSApiClient>, port: i32, client_id: i32) -> bool;
        }
    }
    
    fn main() {
        let client = ffi::new_twsapi_client();
        client.connect(4002, 333);
    }
    

    The Error

    error[E0599]: no method named `connect` found for struct `UniquePtr<TWSApiClient>` in the current scope
      --> src/main.rs:21:12
       |
    21 |     client.connect(4002, 333);
       |            ^^^^^^^ method not found in `UniquePtr<TWSApiClient>`
    
    For more information about this error, try `rustc --explain E0599`.
    error: could not compile `twsapi_grpc_server` due to previous error
    

    TWSAPIClient.cc

    ...
    
    class TWSApiClient::impl {
        friend TWSApiClient;
    };
    
    TWSApiClient::TWSApiClient() : impl(new class TWSApiClient::impl)
            , m_osSignal(2000)//2-seconds timeout
            , m_pClient(new EClientSocket(this, &m_osSignal))
            , m_state(ST_CONNECT) // starts at m_state = 0
            , m_sleepDeadline(0)
            , m_orderId(0)
            , m_extraAuth(false) {}
    
    TWSApiClient::~TWSApiClient()
    {
        if( m_pReader ){
            m_pReader.reset();
        }
        delete m_pClient;
    }
    
    /**
    *  Connect - This part of the client deals with connection to IB Gateway
    *
    *  See: https://interactivebrokers.github.io/tws-api/classIBApi_1_1EClientSocket.html
    */
        bool TWSApiClient::connect(int port, int clientId) {...}{
        ...
    
      std::unique_ptr<TWSApiClient> new_twsapi_client() {
        return std::make_unique<TWSApiClient>();
      }
    

    TWSAPIClien.h

    class TWSApiClient : public EWrapper {
    
    public:
        #include "EWrapper_prototypes.h"
    
        TWSApiClient();
        ~TWSApiClient();
    
        bool connect(int port, int client_id);
        <and many other functions, but first want to just test connecting>
    
    private:
         class impl;
        std::shared_ptr<impl> impl;
        EReaderOSSignal m_osSignal;
        EClientSocket * const m_pClient;
        State m_state;
        time_t m_sleepDeadline;
        OrderId m_orderId;
        std::unique_ptr<EReader> m_pReader;
        bool m_extraAuth;
        std::string m_bboExchange;
        int client_id;
    };
    
    std::unique_ptr<TWSApiClient> new_twsapi_client();
    
    opened by EMCP 2
  • cxx: implement slice support for nostd

    cxx: implement slice support for nostd

    OVERVIEW:

    This patch adds experimental support for us to use slices in a nostd/freestanding environment, aim is to run c++ <=> cxx-rs <=> rust on a baremental target environment and use slices, with the intention of supporting more features later.

    CFG

    In the application Cargo.toml file, the following feature cfgs are required:

    [dependencies]
    cxx = { ... , default-features = false }
    
    [build-dependencies]
    cxx-build = { ... , default-features = false }
    

    Then build with:

    RUSTFLAGS='--cfg cxx_experimental_no_alloc' cargo build
    

    Build Notes

    and in the particular .cpp file you may need to declare the following

    void __assert_func (const char *__a, int, const char *__b, const char *__c) {
    	while (true) {}
    }
    
    void *__gxx_personality_v0;
    

    FUNCTIONALITY:

    Currently, this only supports slices (outside of trivial features).

    TESTING:

    Tested by compiling:

    • cargo test (run existing tests)

    • cxx/demo/ running it.

    • compiling with a arm toolchain setup with cmake/corrosion and running the binary on QEMU arm with basic logic assertions [1].

    Current testing has been done in the direction of C++ -> Rust with a simple callback test to C++. A simple test setup can be seen here [2].

    TODO:

    • Get features such as Results<Ok, Err> working.

    • When we build for the none std case (no default-features), instead of creating a symlink to the original cxx.h file, we copy it over and define the macro to disable stdlib dependencies. Perhaps there's a better way to do this?

    NOTES:

    By default, all the standard features are enabled gaurded by the #ifndef CXXBRIDGE1_RUST_STD, so this shoudn't break anything.

    [1] https://github.com/twilfredo/qemu_misc/tree/master/bm_arm [2] https://github.com/twilfredo/qemu_misc/blob/master/bm_arm/main.cpp

    Signed-off-by: Wilfred Mallawa [email protected]

    opened by twilfredo 2
Releases(1.0.85)
  • 1.0.85(Dec 19, 2022)

  • 1.0.84(Dec 17, 2022)

  • 1.0.83(Dec 3, 2022)

  • 1.0.82(Nov 18, 2022)

    • Add an opt-in to propagate Rust docs from the cxx::bridge module as Doxygen-style comments in the generated C++ header (https://docs.rs/cxx-build/1.0.82/cxx_build/static.CFG.html#cfgdoxygen)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.81(Nov 8, 2022)

  • 1.0.80(Oct 21, 2022)

    • Fix "cannot find type Box in this scope" build error when using Box, String, Vec in default-features = false, features = ["alloc"] mode (#1065)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.79(Oct 15, 2022)

  • 1.0.78(Sep 28, 2022)

  • 1.0.77(Sep 28, 2022)

  • 1.0.76(Sep 19, 2022)

  • 1.0.75(Sep 2, 2022)

  • 1.0.74(Aug 30, 2022)

    • Fix "filename, directory name, or volume label syntax is incorrect" build error on Windows when the target dir in which cxx-build is running contains broken symlinks (#1085)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.73(Aug 2, 2022)

  • 1.0.72(Jul 17, 2022)

  • 1.0.71(Jul 6, 2022)

  • 1.0.70(Jul 4, 2022)

  • 1.0.69(Jun 18, 2022)

  • 1.0.68(May 13, 2022)

  • 1.0.67(Apr 26, 2022)

    • Improvements to the Bazel build rules:
      • Use the default linker on macOS C++ toolchains from Apple (#1029, thanks @keith)
      • Support Arm target triples on Bazel 5.1+ (#1038, thanks @snowp)
      • Ensure that cxx and its third-party dependencies are built with the correct edition even if the downstream repo uses a different default one (#1034, #1035, #1040, https://github.com/bazelbuild/rules_rust/pull/1256)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.66(Mar 8, 2022)

  • 1.0.65(Mar 8, 2022)

  • 1.0.64(Mar 8, 2022)

  • 1.0.63(Jan 19, 2022)

    • Add support for conditional compilation using #[cfg(...)] attributes inside the bridge module (#989)
        #[cfg(target_os = "android")]
        type CallInvokerHolder;
    
        #[cfg(target_os = "android")]
        fn getCallInvoker(self: Pin<&mut CallInvokerHolder>) -> SharedPtr<CallInvoker>;
    
    Source code(tar.gz)
    Source code(zip)
  • 1.0.62(Jan 3, 2022)

  • 1.0.61(Dec 31, 2021)

    • Add String::lossy constructors to C++ API, corresponding to from_utf8_lossy and from_utf16_lossy (#984, thanks @benesch)
    • Add Vec<T>::truncate to C++ API (#988, thanks @benesch)
    • Assert sufficient alignment of const char16_t* passed to a rust::String constructor (#992)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.60(Dec 10, 2021)

    • Optimize the Debug and Display impl of CxxString to eliminate memory allocation (#979)
    • Prevent handwritten panicking Drop, PartialEq, PartialOrd, or Hash trait impls from causing UB when called from C++ (#980)
    • Add support for codebases that choose to opt in to elided_lifetimes_in_paths lint (#907, #981)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.59(Dec 9, 2021)

  • 1.0.58(Dec 8, 2021)

    • no_std mode (#969, #970, #971, #972, #973, #974, #975)

      [dependencies]
      cxx = { version = "1.0", default-features = false, features = ["alloc"] }
      

      A no_alloc mode is also implemented but is not stable yet in this release.

      [dependencies]
      cxx = { version = "1.0", default-features = false }
      
    Source code(tar.gz)
    Source code(zip)
  • 1.0.57(Dec 1, 2021)

  • 1.0.56(Oct 5, 2021)

Owner
David Tolnay
David Tolnay
“The Tie Between Ruby and Rust.”

Rutie Rutie — /ro͞oˈˌtī/rOOˈˌtI/rüˈˌtaI/ Integrate Ruby with your Rust application. Or integrate Rust with your Ruby application. This project allows

Daniel P. Clark 726 Jan 2, 2023
Facilitating high-level interactions between Wasm modules and JavaScript

wasm-bindgen Facilitating high-level interactions between Wasm modules and JavaScript. Guide | API Docs | Contributing | Chat Built with ?? ?? by The

Rust and WebAssembly 5.9k Jan 8, 2023
Rust bindings for writing safe and fast native Node.js modules.

Rust bindings for writing safe and fast native Node.js modules. Getting started Once you have the platform dependencies installed, getting started is

The Neon Project 7k Jan 4, 2023
A minimalist and safe ECS library for rust!

The full ECS (Entity-Component-System) library. Support an Open Source Developer! ♥️ Composed of two smaller libraries: world_dispatcher: the System p

Joël Lupien 124 Dec 19, 2022
Safe Rust bridge for creating Erlang NIF functions

Rustler Documentation | Getting Started | Example Rustler is a library for writing Erlang NIFs in safe Rust code. That means there should be no ways t

Rusterlium 3.5k Jan 7, 2023
Safe Rust bindings to Lua 5.1

rust-lua Copyright 2014 Lily Ballard Description This is a set of Rust bindings to Lua 5.1. The goal is to provide a (relatively) safe interface to Lu

Lily Ballard 124 Jan 5, 2023
mruby safe bindings for Rust

mrusty. mruby safe bindings for Rust mrusty lets you: run Ruby 1.9 files with a very restricted API (without having to install Ruby) reflect Rust stru

Anima 200 Oct 12, 2022
WebAssembly implementation from scratch in Safe Rust with zero dependencies

wain wain is a WebAssembly INterpreter written in Rust from scratch with zero dependencies. An implementation of WebAssembly. Features: No unsafe code

Linda_pp 328 Jan 2, 2023
Safe Rust <---> GraalVM Polyglot bindings using procedural macros

The class macro is the primary way to generate bindings to Java types; it will generate a struct (with generics if specified) that implements Pass and Receive and has all the methods you give stubs for. The methods generated can be used like normal rust methods, however mutability is not enforced. The fully-qualified type name should precede a block containing method and constructor stubs. Java primitives like char, int, and byte are aliased to corresponding Rust types.

Alec Petridis 33 Dec 28, 2022
A safe Rust FFI binding for the NVIDIA® Tools Extension SDK (NVTX).

NVIDIA® Tools Extension SDK (NVTX) is a C-based Application Programming Interface (API) for annotating events, code ranges, and resources in your applications. Official documentation for NVIDIA®'s NVTX can be found here.

Spencer Imbleau 78 Jan 2, 2023
High-level memory-safe binding generator for Flutter/Dart <-> Rust

flutter_rust_bridge: High-level memory-safe binding generator for Flutter/Dart <-> Rust Want to combine the best between Flutter, a cross-platform hot

fzyzcjy 2.1k Dec 31, 2022
A collection of unsound rust functions using entirly *safe* code

A collection of unsound rust functions using entirly *safe* code

null 2 Sep 6, 2022
A memory safe Lua interpreter

Hematita Da Lua Hematita Da Lua is an interpreter for the scripting language Lua, written entirely in 100% safe Rust. Hematita is the portugese word f

Daniel 149 Dec 29, 2022
Robust and Fast tokenizations alignment library for Rust and Python

Robust and Fast tokenizations alignment library for Rust and Python Demo: demo Rust document: docs.rs Blog post: How to calculate the alignment betwee

Explosion 157 Dec 28, 2022
Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# library.

Rabe-ffi Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# libra

Aya0wind 2 Oct 10, 2022
Slitter is a C- and Rust-callable slab allocator implemented primarily in Rust, with some C for performance or to avoid unstable Rust features.

Slitter is a less footgunny slab allocator Slitter is a classically structured thread-caching slab allocator that's meant to help write reliable long-

Backtrace Labs 133 Dec 5, 2022
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
Objective-C Runtime bindings and wrapper for Rust.

Objective-C Runtime bindings and wrapper for Rust. Documentation: http://ssheldon.github.io/rust-objc/objc/ Crate: https://crates.io/crates/objc Messa

Steven Sheldon 336 Jan 2, 2023
A notebook app integrated with todo lists utility. Developed with Rust, WebAssembly, Yew and Trunk.

Flow.er A notebook app integrated with todo-list utility. Project flow.er is a Rust WASM app running in browser. Taking advantage of Yew and Trunk, it

null 45 Dec 31, 2022