为什么 Rust 找不到 wl_display_get_registry?
Why is Rust unable to find wl_display_get_registry?
在编写代码以使用 Wayland Client API 时,Rust 似乎无法找到 wl_display_get_registry
符号。该文件的 objdump 也无法找到该符号。但是,用 GCC 编译的 C 程序能够找到该符号。
为什么C程序能找到符号,而Rust却不能?如何修复 Rust 程序以找到符号?
OS:Ubuntu 18.04 LTS
生锈
建造
rustc -o wayland main.rs
输出
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
代码
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.");
}
}
C
建造
gcc -o wayland -lwayland-client main.c
输出
Connected to Wayland display server.
Retrieving the registry from the Wayland display.
Registry retrieved.
Disconnected from Wayland display server.
代码
#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;
}
objdump
命令
objdump -TC /usr/lib/x86_64-linux-gnu/libwayland-client.so | grep "wl_display*"
输出
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
wl_display_get_registry
函数和其他几个函数在头文件 wayland-client-protocols.h
中标记为 static inline
。 Functions marked static inline
will not have their symbols exported。这解释了 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.");
}
}
在编写代码以使用 Wayland Client API 时,Rust 似乎无法找到 wl_display_get_registry
符号。该文件的 objdump 也无法找到该符号。但是,用 GCC 编译的 C 程序能够找到该符号。
为什么C程序能找到符号,而Rust却不能?如何修复 Rust 程序以找到符号?
OS:Ubuntu 18.04 LTS
生锈
建造
rustc -o wayland main.rs
输出
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
代码
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.");
}
}
C
建造
gcc -o wayland -lwayland-client main.c
输出
Connected to Wayland display server.
Retrieving the registry from the Wayland display.
Registry retrieved.
Disconnected from Wayland display server.
代码
#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;
}
objdump
命令
objdump -TC /usr/lib/x86_64-linux-gnu/libwayland-client.so | grep "wl_display*"
输出
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
wl_display_get_registry
函数和其他几个函数在头文件 wayland-client-protocols.h
中标记为 static inline
。 Functions marked static inline
will not have their symbols exported。这解释了 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.");
}
}