cpptorust project is aimed to create Rust wrappers for C++ libraries automatically.
libclang-dev
. Mainly developed with version 3.5, but higher versions should be compatible as well.If you have multiple versions of Qt on your machine (for example, obtained via online installer) and you want to build against a specific version, modify PATH
environment variable so that qmake
command of the correct Qt version is available. cpp_to_rust
uses qmake
command to find library paths.
The converter parses C++ headers of the library and generates a wrapper library with C interface that provides access to all supported functions and methods of the library. Then it creates source of new Rust crate and compiles it.
The generator requires multiple files to run: Cargo.toml
file template for the library, spec.json
file with additional information, tests and extra source files. Exact specification of input files is not stabilized at the moment. Prepared input files are available for multiple libraries:
Clone cpp_to_rust
and the input folder. Execute in cpp_to_rust
's folder:
cargo run -- -s path/to/input -o path/to/output
Output path will contain source files of the crate. C wrapper library will be placed in a subdirectory of the output directory. The converter will run cargo test
and cargo doc
on the crate to build and test it.
To use generated library, include it in your project's Cargo.toml
by specifying relative or absolute path to its directory:
qt_core = { path = "../output/qt_core" }
When processing a library with dependencies on other C++ libraries (e.g. QtWidgets that depends on QtCore and QtGui), dependencies need to be processed first. Use -d <OUT_DIR1> <OUT_DIR2>...
argument to add dependencies to cpp_to_rust
. You may not need to include dependencies in your project's Cargo.toml
file because each generated crate re-exports all its dependencies. But if you decide to do it, make sure that you use the same crate directory that was used in -d
.
This option uses standard Cargo's build system. The input files folder itself is a full-featured crate with a build script that uses cpp_to_rust
to generate the sources. You can either clone the input folder and run cargo build
in it, or just include the input files folder directly in your project:
qt_widgets = { git = "https://github.com/rust-qt/qt_widgets.git" }
If the library is published on crates.io, you can also include it using its version:
qt_widgets = "0.0"
C++ dependencies are found and buily automatically when using this method.
Main downside of this method is that cargo
compiles a dependency crate from scratch for each of your projects and for each build configuration (e.g. debug and release) in a separate folder, so it's not possible to cache anything. cpp_to_rust
will be executed for each project and each build configuration, and it may significantly slow down the build process, especially for large libraries with multiple dependencies. When executing cpp_to_rust
from command line, it runs exactly once, and generated crate will not run cpp_to_rust
when included in a project.
If you use custom Qt version that is not available in library path, you need to set LIBRARYPATH and LDLIBRARY_PATH environment variables before executing Cagro commands. When running the converter directly from command line, this is done automatically, but it's not possible to do it from a build script.
Only Linux is currently supported. Windows support is a high priority. Mac OS support is not planned, but contributions are welcome.
cpp_to_rust
was tested on a limited set of libraries. See Input files section for a list of currently supported libraries.
The first priority is to support all of Qt5 libraries. However, most of its code is not Qt-dependent, so it is possible to support arbitrary libraries in the future.
Currently implemented features:
Not implemented yet but planned:
static_cast
, dynamic_cast
and qobject_cast
.Not planned to support:
Class1<T>::Class2
.The wrapper code is platform-dependent. The main problem is notion of sizes of structs, but they only matter if Rust-owned structs are used. Platform-dependency of types is generally mitigated by libc crate. However, the C++ library itself also may be platform-dependant. For example, it can use preprocessor directives to declare different types and methods for different platforms and environments. Different versions of the same library may also have different set of methods. Lack of methods will probably be reported by the linker, but type mismatch will not, and it can cause dangerous issues at runtime.
This project does not have a portability solution yet. It is theoretically possible to analyze header parsing result on all supported platforms and generate platform-independent and environment-independent code. The result would look like libc - any type or method always corresponds to the OS in use. However, it is hard to implement such analysis, and it is even harder to organize the process on all supported systems and all versions of all supported libraries.
So the project currently assumes that the user will use the generated wrapper only on the same system and with the same library that were used during its generation. It is possible that the generated crate will be usable when moved to machines with the same arch, OS, and library version but different directory layout. Beyond that, however, there are no plans to introduce portability at the moment.
Environment required to generate wrappers is somewhat heavy (see "Dependencies" section), so it may be troublesome to set it up on the target machine. Cross-compilation may be one solution to this problem, so supporting cross-compilation may become a goal in the future.
On the other side, requirement to perform header parsing on the target system will assure that the wrapper is correct, and any missing methods and mismatched types will be reported by the Rust compiler.
Contributions are always welcome! There are easy ways to contribute:
cpp_to_rust
itself or any of wrapped libraries and submit a pull request;