使用 cmake 的局限性
.lib 合并问题
cmake 不会将多个 .lib 合并, 因此可能需要使用 add_custom_command
命令手动使用 MSVC 工具 lib.exe
来创建最终具有 C ABI 的 .lib 静态库文件供Rust调用.
set(Target "output")
add_library("${Target}" STATIC lib.cpp)
target_include_directories("${App}" PUBLIC "${CMAKE_HOME_DIRECTORY}/src")
target_link_libraries("${App}" Win32Helper)
很遗憾, output.lib 中对另一个静态库Win32Helper的调用是未寻址的! 可以使用cygwin工具 nm
来查看符号:
U表示“未定义”——对象有对符号的引用但没有定义
T表示在文本段中全局定义——对象定义并导出符号
nm output.lib | grep win32_init
U win32_init
其它的解决办法:
- 合并代码, 不拆分成多个库的形式
- 尝试在Rust中将多个.lib都进行链接 (繁琐, 实验后未成功)
set(Target "output")
file(GLOB_RECURSE files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" ../Win32Helper/*.c)
add_library("${Target}" STATIC lib.cpp ${files})
Win32 API 符号链接问题
由于 cmake 导出 .lib 时忽略静态库和动态库依赖, 造成 API 调用在 Rust 中形成 fatal error LNK1120
链接错误, 意味着找不到符号.
解决办法:
- 在C++代码中使用内联编译注释指定导入库, 微软 API 文档有说明每个 API 所在的头文件和Library等信息.
#pragma comment(lib, "User32.lib") // MessageBoxW
#pragma comment(lib, "Shell32.lib") // Shell_NotifyIconW
- 在Rust中进行链接
#[link(name = "User32", kind = "dylib")]
#[link(name = "Shell32", kind = "dylib")]
#[link(name = "Z:\Github\Win32Helper\build\src\Rust-ffi\Debug\output", kind = "static")]
extern "C" {
pub fn test() -> c_int;
}
动态调用符号
#[link(name = "User32", kind = "dylib")]
extern "C" {
fn GetModuleHandleA(lpModuleName: *const u8) -> *mut u8;
fn GetProcAddress(hModule: *mut u8, lpProcName: *const u8) -> *mut u8;
}
#[no_mangle]
extern "C" fn DllMain(_: *mut u8, reason: u32, _: *mut u8) -> u32 {
match reason {
1 => {
println!("连接到进程!");
intro();
}
0 => {
println!("检测到进程退出");
}
_ => ()
}
return 1;
}
fn intro() {
unsafe {
let module = GetModuleHandleA("Kernel32 ".as_ptr());
println!("得到模块 -> {:?}.", module);
let symbol = GetProcAddress(module, b"ExitProcess ".as_ptr());
println!("得到符号 -> {:?}.", symbol);
type ExitProcess = unsafe extern "C" fn(u32);
let exit_process: ExitProcess = std::mem::transmute(symbol);
exit_process(0);
}
}
将Rust动态库注入到node进程,提示node版本
use std::ptr::null_mut;
#[link(name = "User32", kind = "dylib")]
extern "C" {
fn GetModuleHandleA(lpModuleName: *const u8) -> *mut u8;
fn GetProcAddress(hModule: *mut u8, lpProcName: *const u8) -> *mut u8;
fn MessageBoxA(hWnd: *mut u8, lpText: *const u8, lpCaption: *const u8, uType: u32) -> u32;
}
#[no_mangle]
extern "C" fn DllMain(_: *mut u8, reason: u32, _: *mut u8) -> u32 {
match reason {
1 => {
println!("连接到进程!");
intro();
}
0 => {
println!("检测到进程退出");
}
_ => ()
}
return 1;
}
fn intro() {
unsafe {
let module = GetModuleHandleA(" ".as_ptr());
println!("得到模块 -> {:?}.", module);
let symbol = GetProcAddress(module, b"uv_version_string ".as_ptr());
println!("得到符号 -> {:?}.", symbol);
type Func = extern "C" fn() -> *const u8;
let uv_version: Func = std::mem::transmute(symbol);
let version = uv_version();
println!("得到版本 -> {:?}.", version);
MessageBoxA(null_mut(), version, "Got version!".as_ptr(), 0);
}
}
node将打印以下输出并弹出消息框
连接到进程!
得到模块 -> 0x0.
得到符号 -> 0x7ff6d72a1440.
得到版本 -> 0x7ff6d83a5674.
exiting...
检测到进程退出
END
原文链接: https://www.cnblogs.com/develon/p/15978530.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/188143
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!