一、 环境准备:
WSL2 +Bindgen + CTP C++ 接口 for linux Bindgen: https://github.com/rust-lang/rust-bindgenCTP 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
ctp-sdk文件这个可以找指定的地方copy进来,这部分省略。
总体效果如下:
二、构建wrapper.hpp 文件
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这样,binding.rs就自动生成了。 如下图: 文件很大,有几万行,这里就只显示一部分了。