为什么Rust无法找到wl_display_get_registry?

Jas*_*ith 3 rust wayland

在编写代码以使用Wayland Client API时,Rust似乎无法找到该wl_display_get_registry符号.该文件的objdump也无法找到该符号.但是,使用GCC编译的C程序能够找到该符号.

为什么C程序可以找到符号,但Rust不能?如何修复Rust程序以找到符号?

操作系统:Ubuntu 18.04 LTS

建立

rustc -o wayland main.rs
Run Code Online (Sandbox Code Playgroud)

产量

error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "wayland.main0.rcgu.o" "wayland.main1.rcgu.o" "wayland.main2.rcgu.o" "wayland.main3.rcgu.o" "wayland.main4.rcgu.o" "-o" "wayland" "wayland.crate.allocator.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "-L" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-l" "wayland-client" "-Wl,--start-group" "-Wl,-Bstatic" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-2da986ecbb2c5327.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-57f46841c9a9f4ee.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc_jemalloc-23263fe5893322f6.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-6ed5262c9a0a3e5a.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc_system-99c162b689d43349.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-cd415b85dd267875.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-3876ac10aa96a1e3.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_unicode-598b0e9aca382e9a.rlib" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-4eabb2b1c31071b8.rlib" "-Wl,--end-group" "/home/myrddin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-d7a656735ceeae9e.rlib" "-Wl,-Bdynamic" "-l" "dl" "-l" "rt" "-l" "pthread" "-l" "pthread" "-l" "gcc_s" "-l" "c" "-l" "m" "-l" "rt" "-l" "pthread" "-l" "util" "-l" "util"
  = note: wayland.main3.rcgu.o: In function `main::main':
          main3-317d481089b8c8fe83113de504472633.rs:(.text._ZN4main4main17h52709beaa06fe157E+0x109): undefined reference to `wl_display_get_registry'
          collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

pub enum WLDisplay {}
pub enum WLRegistry {}

#[link(name = "wayland-client")]
extern "C" {
    pub fn wl_display_connect(name: *const ::std::os::raw::c_char) -> *mut WLDisplay;
    pub fn wl_display_disconnect(display: *mut WLDisplay) -> ();

    pub fn wl_display_get_registry(display: *mut WLDisplay) -> *mut WLRegistry;
}

fn main() {
    let display: *mut WLDisplay;
    let registry: *mut WLRegistry;

    unsafe {
        display = wl_display_connect(::std::ptr::null());
        if display.is_null() == true {
            eprintln!("Unable to connect to the Wayland display server.");
            return;
        }
        println!("Connected to Wayland display server.");

        println!("Retrieving the registry from the Wayland display.");
        registry = wl_display_get_registry(display);
        if registry.is_null() == true {
            eprintln!("Unable to retrieve registry.");
        } else {
            println!("Registry retrieved.");
        }

        wl_display_disconnect(display);
        println!("Disconnected from Wayland display server.");
    }
}
Run Code Online (Sandbox Code Playgroud)

C

建立

gcc -o wayland -lwayland-client main.c
Run Code Online (Sandbox Code Playgroud)

产量

Connected to Wayland display server.
Retrieving the registry from the Wayland display.
Registry retrieved.
Disconnected from Wayland display server.
Run Code Online (Sandbox Code Playgroud)

#include <stdio.h>
#include <wayland-client.h>


int main()
{
   struct wl_display *display;
   struct wl_registry *registry;

   display = wl_display_connect(NULL);
   if (display == NULL)
   {
      fprintf(stderr, "Unable to connect to the Wayland display server.\n");
      return 1;
   }
   fprintf(stdout, "Connected to Wayland display server.\n");

   fprintf(stdout, "Retrieving the registry from the Wayland display.\n");
   registry = wl_display_get_registry(display);
   if (registry == NULL)
   {
      fprintf(stderr, "Unable to retrieve registry.\n");
   }
   else
   {
      fprintf(stdout, "Registry retrieved.\n");
   }

   wl_display_disconnect(display);
   fprintf(stdout, "Disconnected from Wayland display server.\n");

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

objdump

命令

objdump -TC /usr/lib/x86_64-linux-gnu/libwayland-client.so | grep "wl_display*"
Run Code Online (Sandbox Code Playgroud)

产量

0000000000005f60 g DF .text 0000000000000275  Base wl_display_connect
0000000000006960 g DF .text 0000000000000078  Base wl_display_flush
0000000000006a90 g DF .text 000000000000000c  Base wl_display_dispatch
00000000000067b0 g DF .text 0000000000000042  Base wl_display_cancel_read
00000000000068c0 g DF .text 000000000000000c  Base wl_display_dispatch_pending
0000000000006800 g DF .text 00000000000000bf  Base wl_display_dispatch_queue_pending
00000000000061e0 g DF .text 0000000000000057  Base wl_display_disconnect
0000000000006be0 g DF .text 00000000000000fc  Base wl_display_roundtrip_queue
00000000000068d0 g DF .text 000000000000002c  Base wl_display_get_error
0000000000005610 g DF .text 0000000000000031  Base wl_display_create_queue
0000000000006740 g DF .text 0000000000000052  Base wl_display_prepare_read_queue
0000000000006900 g DF .text 0000000000000051  Base wl_display_get_protocol_error
0000000000005dc0 g DF .text 0000000000000194  Base wl_display_connect_to_fd
00000000000069e0 g DF .text 00000000000000ac  Base wl_display_dispatch_queue
0000000000006ce0 g DF .text 000000000000000c  Base wl_display_roundtrip
0000000000006250 g DF .text 00000000000004f0  Base wl_display_read_events
0000000000006240 g DF .text 0000000000000004  Base wl_display_get_fd
000000000020dce0 g DO .data.rel.ro 0000000000000028 Base wl_display_interface
00000000000067a0 g DF .text 000000000000000c  Base wl_display_prepare_read
Run Code Online (Sandbox Code Playgroud)

Jas*_*ith 5

wl_display_get_registry函数和其他几个函数标记static inline在头文件中wayland-client-protocols.h.标记的功能static inline不会导出其符号.这解释了C如何能够看到和使用该功能,但Rust无法做到.

我们必须重新实现C宏和静态内联函数作为Rust函数:

pub enum WLDisplay {}
pub enum WLProxy {}
pub enum WLRegistry {}

const WL_DISPLAY_GET_REGISTRY: ::std::os::raw::c_uint = 1;

#[link(name = "wayland-client")]
extern "C" {
    #[no_mangle]
    static wl_registry_interface: WLInterface;

    pub fn wl_display_connect(name: *const ::std::os::raw::c_char) -> *mut WLDisplay;
    pub fn wl_display_disconnect(display: *mut WLDisplay) -> ();

    pub fn wl_proxy_marshal_constructor(
        proxy: *mut WLProxy,
        opcode: ::std::os::raw::c_uint,
        interface: *const WLInterface,
    ) -> *mut WLProxy;
}

#[repr(C)]
pub struct WLMessage {
    pub name: *const ::std::os::raw::c_char,
    pub signature: *const ::std::os::raw::c_char,
    pub types: *const *const WLInterface,
}

#[repr(C)]
pub struct WLInterface {
    pub name: *const ::std::os::raw::c_char,
    pub version: ::std::os::raw::c_int,
    pub request_count: ::std::os::raw::c_int,
    pub requests: *const WLMessage,
    pub event_count: ::std::os::raw::c_int,
    pub events: *const WLMessage,
}

fn wl_display_get_registry(display: *mut WLDisplay) -> *mut WLRegistry {
    let proxy: *mut WLProxy;

    unsafe {
        proxy = wl_proxy_marshal_constructor(
            display as *mut _ as *mut WLProxy,
            WL_DISPLAY_GET_REGISTRY,
            &wl_registry_interface,
        );
        proxy as *mut _ as *mut WLRegistry
    }
}

fn main() {
    let display: *mut WLDisplay;
    let registry: *mut WLRegistry;

    unsafe {
        display = wl_display_connect(::std::ptr::null());
        if display.is_null() == true {
            eprintln!("Unable to connect to the Wayland display server.");
            return;
        }
        println!("Connected to Wayland display server.");

        println!("Retrieving the registry from the Wayland display.");
        registry = wl_display_get_registry(display);
        if registry.is_null() == true {
            eprintln!("Unable to retrieve registry.");
        } else {
            println!("Registry retrieved.");
        }

        wl_display_disconnect(display);
        println!("Disconnected from Wayland display server.");
    }
}
Run Code Online (Sandbox Code Playgroud)