Expand description
This crate cpp
provides macros that allow embedding arbitrary C++ code.
Usage
This crate must be used in tandem with the cpp_build
crate. A basic Cargo
project which uses these projects would have a structure like the following:
crate
|-- Cargo.toml
|-- src
|-- main.rs
|-- build.rs
Where the files look like the following:
Cargo.toml
[package]
build = "build.rs"
[dependencies]
cpp = "0.5"
[build-dependencies]
cpp_build = "0.5"
build.rs
extern crate cpp_build;
fn main() {
cpp_build::build("src/main.rs");
}
main.rs
use cpp::cpp;
cpp!{{
#include <iostream>
}}
fn main() {
let name = std::ffi::CString::new("World").unwrap();
let name_ptr = name.as_ptr();
let r = unsafe {
cpp!([name_ptr as "const char *"] -> u32 as "int32_t" {
std::cout << "Hello, " << name_ptr << std::endl;
return 42;
})
};
assert_eq!(r, 42)
}
Build script
Use the cpp_build
crates from your build.rs
script.
The same version of cpp_build
and cpp
crates should be used.
You can simply use the cpp_build::build
function, or the cpp_build::Config
struct if you want more option.
Behind the scene, it uses the cc
crate.
Using external libraries
Most likely you will want to link against external libraries. You need to tell cpp_build
about the include path and other flags via cpp_build::Config
and you need to let cargo
know about the link. More info in the cargo docs.
Your build.rs
could look like this:
fn main() {
let include_path = "/usr/include/myexternallib";
let lib_path = "/usr/lib/myexternallib";
cpp_build::Config::new().include(include_path).build("src/lib.rs");
println!("cargo:rustc-link-search={}", lib_path);
println!("cargo:rustc-link-lib=myexternallib");
}
(But you probably want to allow to configure the path via environment variables or
find them using some external tool such as the pkg-config
crate, instead of hardcoding
them in the source)
Limitations
As with all procedure macro crates we also need to parse Rust source files to
extract C++ code. That leads to the fact that some of the language features
might not be supported in full. One example is the attributes. Only a limited
number of attributes is supported, namely: #[path = "..."]
for mod
declarations to specify an alternative path to the module file and
#[cfg(feature = "...")]
for mod
declarations to conditionally include the
module into the parsing process. Please note that the latter is only supported
in its simplest form: straight-forward feature = "..."
without any
additional conditions, cfg!
macros are also not supported at the moment.
Since the C++ code is included within a rust file, the C++ code must obey both
the Rust and the C++ lexing rules. For example, Rust supports nested block comments
(/* ... /* ... */ ... */
) while C++ does not, so nested comments not be used in the
cpp!
macro. Also the Rust lexer will not understand the C++ raw literal, nor all
the C++ escape sequences within literal, so only string literals that are both valid
in Rust and in C++ should be used. The same applies for group separators in numbers.
Be careful to properly use #if
/ #else
/ #endif
, and not have unbalanced delimiters.
Macros
- This macro is used to embed arbitrary C++ code.
- This macro allows wrapping a relocatable C++ struct or class that might have a destructor or copy constructor, implementing the
Drop
andClone
trait appropriately.