• Rust 静态调用 C++


    使用 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
    

    其它的解决办法:

    1. 合并代码, 不拆分成多个库的形式
    2. 尝试在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 链接错误, 意味着找不到符号.

    解决办法:

    1. 在C++代码中使用内联编译注释指定导入库, 微软 API 文档有说明每个 API 所在的头文件和Library等信息.
    #pragma comment(lib, "User32.lib") // MessageBoxW
    #pragma comment(lib, "Shell32.lib") // Shell_NotifyIconW 
    
    1. 在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\0".as_ptr());
            println!("得到模块 -> {:?}.", module);
            let symbol = GetProcAddress(module, b"ExitProcess\0".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("\0".as_ptr());
            println!("得到模块 -> {:?}.", module);
            let symbol = GetProcAddress(module, b"uv_version_string\0".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

  • 相关阅读:
    第02组 Beta冲刺(4/5)
    第02组 Beta冲刺(3/5)
    第02组 Beta冲刺(2/5)
    第02组 Beta冲刺(1/5)
    第02组 Alpha事后诸葛亮
    第02组 Alpha冲刺(6/6)
    第02组 Alpha冲刺(5/6)
    第02组 Alpha冲刺(4/6)
    第02组 Alpha冲刺(3/6)
    2020系统综合实践1 微服务与Docker 基本入门
  • 原文地址:https://www.cnblogs.com/develon/p/15978530.html
Copyright © 2020-2023  润新知