一、 环境准备:
WSL2 +Bindgen + CTP C++ 接口 for linux
Bindgen: https://github.com/rust-lang/rust-bindgen
CTP for linux
说明一下,我在windows环境下,同样的方法,一直报libclang没有找到(如下,问题是我明明设置这个环境变量,为什么睁眼看不见),至今也没有解决,看了github bindgen issues上提的问题,类似的问题不少。试了不少方法,终于放弃,转WSL2.
windows下bug:
thread ‘main’ panicked at ‘Unable to find libclang: “couldn’t find any valid shared libraries matching: [‘clang.dll’, ‘libclang.dll’], set the
LIBCLANG_PATH
environment variable to a path where one of these files can be found (invalid: [])”’, C:\Users\songroom.cargo\registry\src\github.com-1ecc6299db9ec823\bindgen-0.55.1\src/lib.rs:1896:31
在WSL下:这个下面安装clang来解决:
sudo apt-get install llvm
sudo apt install clang
ctp-sdk文件这个可以找指定的地方copy进来,这部分省略。
总体效果如下:
wrapper.hpp是告诉bindgen,我这些都需要帮我翻译一下。东西在这呢。这个文件可以放在src目录下。
注意:加上“…/”; 或者用绝对路径。
#include "../ctp_sdk/ThostFtdcMdApi.h"
#include "../ctp_sdk/ThostFtdcTraderApi.h"
#include "../ctp_sdk/ThostFtdcUserApiStruct.h"
#include "../ctp_sdk/ThostFtdcUserApiDataType.h"
三、倒腾build.rs文件
build.rs文件,放在工程目录的根目录下,我这儿的工程名是“rust_new_test”,build.rs放在和Cargo.toml同一目录级下,并列就好。
use std::env;
use std::path::PathBuf;
fn main() {
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("src/wrapper.hpp")
/* // Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks)) */
.ignore_methods()
.rustified_enum(".*")
.blacklist_item("CTP_SIDE_TYPE")
.blacklist_function("TraderSpiStub_Rust.*")
.blacklist_function("QuoteSpiStub_Rust.*")
.generate_comments(false)// 不需形成doc ,默认true
.layout_tests(false) //不需要test,默认true
.generate_comments(false)//不需注释,默认true
.derive_copy(false)
.derive_hash(false) //不要实现hash
/* .default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: true,
}) */
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// 注意,这些属性尽量要有所控制,否则会在类型转换时造成影响
/* derive_copy: true,
derive_debug: true,
derive_default: false,
derive_hash: false,
derive_partialord: false,
derive_ord: false,
derive_partialeq: false,
derive_eq: false, */
//OUT_DIR: D:\rust_test\
// Write the bindings to the $OUT_DIR/bindings.rs file.
//let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
//r"C:\windows\system32.dll"
let out_path = PathBuf::from("/home/songroom/rust_new_test");
println!("out_path: {:?}",out_path);
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
blacklist_item、blacklist_function是指哪些不需要进行翻译的项。
需要注意的是,我特地把里面的注释、测试、文档等关闭了(设置了false).具体的设置可以在文档中找到。主要原因是,文档太长了,看了根本吃不消。关闭了大约7000+行,不关闭这些近70000行,你说,能吃得消么?
https://github.com/rust-lang/rust-bindgen/blob/0996486f0977e12f1a64f7730b3eca81659aa839/src/lib.rs
impl Default for BindgenOptions {
fn default() -> BindgenOptions {
let rust_target = RustTarget::default();
BindgenOptions {
rust_target,
rust_features: rust_target.into(),
blacklisted_types: Default::default(),
blacklisted_functions: Default::default(),
blacklisted_items: Default::default(),
opaque_types: Default::default(),
rustfmt_path: Default::default(),
whitelisted_types: Default::default(),
whitelisted_functions: Default::default(),
whitelisted_vars: Default::default(),
default_enum_style: Default::default(),
bitfield_enums: Default::default(),
newtype_enums: Default::default(),
rustified_enums: Default::default(),
rustified_non_exhaustive_enums: Default::default(),
constified_enums: Default::default(),
constified_enum_modules: Default::default(),
default_macro_constant_type: Default::default(),
default_alias_style: Default::default(),
type_alias: Default::default(),
new_type_alias: Default::default(),
new_type_alias_deref: Default::default(),
builtins: false,
emit_ast: false,
emit_ir: false,
emit_ir_graphviz: None,
layout_tests: true,
impl_debug: false,
impl_partialeq: false,
derive_copy: true,
derive_debug: true,
derive_default: false,
derive_hash: false,
derive_partialord: false,
derive_ord: false,
derive_partialeq: false,
derive_eq: false,
enable_cxx_namespaces: false,
enable_function_attribute_detection: false,
disable_name_namespacing: false,
disable_nested_struct_naming: false,
disable_header_comment: false,
use_core: false,
ctypes_prefix: None,
anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(),
namespaced_constants: true,
msvc_mangling: false,
convert_floats: true,
raw_lines: vec![],
module_lines: HashMap::default(),
clang_args: vec![],
input_header: None,
input_unsaved_files: vec![],
parse_callbacks: None,
codegen_config: CodegenConfig::all(),
conservative_inline_namespaces: false,
generate_comments: true,
generate_inline_functions: false,
whitelist_recursively: true,
generate_block: false,
objc_extern_crate: false,
block_extern_crate: false,
enable_mangling: true,
detect_include_paths: true,
prepend_enum_name: true,
time_phases: false,
record_matches: true,
rustfmt_bindings: true,
size_t_is_usize: false,
rustfmt_configuration_file: None,
no_partialeq_types: Default::default(),
no_copy_types: Default::default(),
no_debug_types: Default::default(),
no_hash_types: Default::default(),
array_pointers_in_arguments: false,
wasm_import_module_name: None,
}
}
}
四、Cargo.toml
[package]
name = "rust_new_test"
version = "0.1.0"
authors = ["sg"]
edition = "2018"
[dependencies]
lazy_static ="1.4"
libc = "0.2"
[build-dependencies]
bindgen = "0.55.1"
cc = "1.0"
五、lib.rs :视情况
如果Cargo.toml文件中没有lib设置(如下,类似),则lib.rs可以忽略。
[lib]
name ="ctp"
path ="src\lib.rs"
如果有lib设置,lib.rs路径可以设“src\lib.rs”,即放在src目录下,设一个空文件即可。
六、cargo build
输入:
cargo build --release