Я создал новую пустую библиотеку Rust. Я установил crate-type
на cdylib
, чтобы генерировались файлы .wasm
. Это мой lib.rs
:
#[no_mangle]
pub extern fn fibonacci(n: usize) -> usize {
if n < 2 {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
Если я удалю #[no_mangle]
, Cargo создаст двоичный файл WASM, который даже не содержит никакого кода:
$ wasm-objdump -h -x target/wasm32-unknown-unknown/release/fibonacci.wasm
fibonacci.wasm: file format wasm 0x1
Sections:
Table start=0x0000000a end=0x0000000f (size=0x00000005) count: 1
Memory start=0x00000011 end=0x00000014 (size=0x00000003) count: 1
Global start=0x00000016 end=0x0000002f (size=0x00000019) count: 3
Export start=0x00000031 end=0x00000056 (size=0x00000025) count: 3
Custom start=0x00000059 end=0x00000f5a (size=0x00000f01) ".debug_abbrev"
Custom start=0x00000f5e end=0x0005c6df (size=0x0005b781) ".debug_info"
Custom start=0x0005c6e3 end=0x00084461 (size=0x00027d7e) ".debug_ranges"
Custom start=0x00084465 end=0x00118f6a (size=0x00094b05) ".debug_str"
Custom start=0x00118f6e end=0x00152a48 (size=0x00039ada) ".debug_line"
Custom start=0x00152a4a end=0x00152a63 (size=0x00000019) "name"
Custom start=0x00152a65 end=0x00152ab2 (size=0x0000004d) "producers"
Custom start=0x00152ab4 end=0x00152ae0 (size=0x0000002c) "target_features"
Section Details:
Table[1]:
- table[0] type=funcref initial=1 max=1
Memory[1]:
- memory[0] pages: initial=16
Global[3]:
- global[0] i32 mutable=1 <__stack_pointer> - init i32=1048576
- global[1] i32 mutable=0 <__data_end> - init i32=1048576
- global[2] i32 mutable=0 <__heap_base> - init i32=1048576
Export[3]:
- memory[0] -> "memory"
- global[1] -> "__data_end"
- global[2] -> "__heap_base"
Custom:
- name: ".debug_abbrev"
Custom:
- name: ".debug_info"
Custom:
- name: ".debug_ranges"
Custom:
- name: ".debug_str"
Custom:
- name: ".debug_line"
Custom:
- name: "name"
- global[0] <__stack_pointer>
Custom:
- name: "producers"
Custom:
- name: "target_features"
- [+] mutable-globals
- [+] sign-ext
Есть ли способ принудительно включить функцию в двоичный файл без использования #[no_mangle]
? Использование extern
само по себе не работает.
extern
просто влияет на ЛПИ. Фактически, отсутствие указания ABI просто означает ABI по умолчанию, а это означает, что он не имеет никаких эффектов.
По теме: Почему ржавчина выдаёт совершенно разные сборки с пабом и без него и #[no_mangle]?
Означает ли это, что вы можете просто заменить его на used
, и это может/должно работать?
@TachyonicBytes У него будет другое (искаженное) имя, но да, оно будет экспортировано.
@ChayimFriedman Я так не думаю; Я попробовал, но он отклонен (см. ответ ниже).
@prog-fh Ах да.
extern
эквивалентно extern "C"
, что означает, что ABI этой функции будет использовать общий ABI платформы (да, я отказываюсь называть его C ABI).
no_mangle
преследует две цели: сначала отключить mangle, то есть преобразовать имя функции. И он пометит эту функцию как «экспортировать». Да, возможно, это сбивает с толку. Но no_mangle
можно прочитать как export
.
Узнать больше:
Точнее, публичные функции всегда экспортируются, но #[no_mangle]
помечает функцию как «используемую», поэтому компилятор не удалит ее только потому, что на нее нет ссылки в коде.
В ссылке говорится о no_mangle , что он явно отключает искажение имен, но, кроме того, он аналогичен атрибуту Used.
Однако used
применяется только к статическим элементам, а не к функциям, как показано в примере ниже.
Тогда единственный способ экспортировать вашу функцию — отключить искажение имен (что, на мой взгляд, разумно).
fn this_is_invisible(n: i32) -> i32 {
n * 2 + 1
}
pub fn this_is_also_invisible(n: i32) -> i32 {
n * 2 + 1
}
#[no_mangle]
fn this_is_accepted(n: i32) -> i32 {
n * 2 + 1
}
/*
// ERROR: attribute must be applied to a `static` variable
#[used]
fn this_is_rejected(n: i32) -> i32 {
n * 2 + 1
}
*/
$ nm target/debug/libmy_project.so | grep this_is
0000000000006e00 T this_is_accepted
Вам, вероятно, все равно понадобится
#[no_mangle]
, чтобы иметь возможность назвать функцию, но странно, что без нее она полностью опускается.