Отсутствует объектный файл Rust при связывании с C с использованием clang - PullRequest
0 голосов
/ 06 января 2019

Я пытался проработать некоторые простые вещи FFI, чтобы выяснить, как заставить Rust работать с кодом C или C ++. Мой ближайший вопрос:

Кажется, что когда я компилирую код Rust в объектный файл, ему не хватает некоторых привязок для компоновщика clang для завершения исполняемого файла. Вот два очень простых файла, которые я использую.

clink.c

#include <stdio.h>
#include <stdbool.h>

int rust_int(int);
bool rust_bool(int, int);

/********************************/
/* void rust_char_star(char *); */
/********************************/

int main(void) {
    printf("%d\n", rust_int(5));
    if (rust_bool(5, 6)) {
        printf("True\n");
    }
    else { printf("False\n"); }

    /******************************/
    /* rust_char_star("Testing"); */
    /******************************/

    return 0;
}

rustlink.rs

use std::os::raw::{c_int, c_char};
// use std::ffi::{CStr, CString};

#[no_mangle]
pub extern "C" fn rust_int(i: c_int) -> c_int {
    i
}

#[no_mangle]
pub extern "C" fn rust_bool(x: c_int, y: c_int) -> bool {
    if x > y {
        true
    }
    else {
        false
    }
}

////////////////////////////////////////////////////////////////////////////
// #[no_mangle]                                                           //
// pub extern "C" fn rust_char_star(c: *const c_char) {                   //
//     let str_printable = unsafe {CString::from_raw(c as *mut c_char) }; //
//                                                                        //
//     println!("{:?}", str_printable);                                   //
// }                                                                      //
////////////////////////////////////////////////////////////////////////////

Когда я компилирую каждый из них без CString, все работает как положено. Не обращайте внимания на предупреждение.

~/dev/rust/learn/clink$ rustc --emit obj --crate-type staticlib rustlink.rs
warning: unused import: `c_char`
use std::os::raw::{c_int, c_char};
                          ^^^^^^
= note: #[warn(unused_imports)] on by default

~/dev/rust/learn/clink$ clang clink.c rustlink.o -o test
~/dev/rust/learn/clink$ ./test
5
False

Когда я раскомментирую весь код для использования типа CString, вот где-то я что-то упускаю. Я не собираюсь делать репост вышеупомянутого кода с удаленными комментариями. Вот что дает выходной сигнал.

~/dev/rust/learn/clink$ rustc --emit obj --crate-type staticlib rustlink.rs 
warning: unused import: `CStr`
 --> rustlink.rs:2:16
  |
2 | use std::ffi::{CStr, CString};
  |                ^^^^
  |
  = note: #[warn(unused_imports)] on by default

~/dev/rust/learn/clink$ clang clink.c rustlink.o -o test
rustlink.o: In function `alloc::alloc::dealloc':
rustlink.3a1fbbbh-cgu.0:(.text._ZN5alloc5alloc7dealloc17hca8aab9ecdf50cafE+0x43): undefined reference to `__rust_dealloc'
rustlink.o: In function `rust_char_star':
rustlink.3a1fbbbh-cgu.0:(.text.rust_char_star+0xa): undefined reference to `std::ffi::c_str::CString::from_raw'
rustlink.3a1fbbbh-cgu.0:(.text.rust_char_star+0x3a): undefined reference to `<std::ffi::c_str::CString as core::fmt::Debug>::fmt'
rustlink.3a1fbbbh-cgu.0:(.text.rust_char_star+0xa9): undefined reference to `std::io::stdio::_print'
rustlink.o:(.data.DW.ref.rust_eh_personality[DW.ref.rust_eh_personality]+0x0): undefined reference to `rust_eh_personality'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
~/dev/rust/learn/clink$ 

Идем немного дальше. Я попытался скомпилировать код Rust в статическую библиотеку для подачи в clang. Я не уверен, почему, но это результат.

~/dev/rust/learn/clink$ rustc --crate-type staticlib rustlink.rs 
warning: unused import: `CStr`
 --> rustlink.rs:2:16
  |
2 | use std::ffi::{CStr, CString};
  |                ^^^^
  |
  = note: #[warn(unused_imports)] on by default

~/dev/rust/learn/clink$ ls
clink.c  librustlink.a  rustlink.o  rustlink.rs
~/dev/rust/learn/clink$ clang clink.c -o test -lrustlink
/usr/bin/ld: cannot find -lrustlink
clang: error: linker command failed with exit code 1 (use -v to see invocation)
~/dev/rust/learn/clink$ clang clink.c -o test -L -lrustlink
/tmp/clink-357672.o: In function `main':
clink.c:(.text+0x15): undefined reference to `rust_int'
clink.c:(.text+0x3a): undefined reference to `rust_bool'
clink.c:(.text+0x83): undefined reference to `rust_char_star'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
~/dev/rust/learn/clink$

Здесь я немного растерялся. Я думал, когда вы говорите rustc, что тип ящика является статическим, что он включает в себя все зависимости, но я предполагаю, что это не так.

Очевидно, я пропускаю шаг. Я бы предпочел, чтобы rustc включал все привязки, чтобы я мог просто использовать простую команду, чтобы набрать исполняемый файл.

1 Ответ

0 голосов
/ 06 января 2019

Мне не хватало стандартных библиотечных привязок. После еще немного поиска в Google я нашел несколько полезных ссылок:

Оказывается, мне просто нужно было узнать, где находится стандартный объектный файл Rust. Выполнение следующего является решением:

~/dev/rust/learn/clink$ rustc --crate-type staticlib rustlink.rs
~/dev/rust/learn/clink$ clang clink.c -o test ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libstd-89cf9eb8d404bb7b.so -L . -lrustlink
nick@Void:~/dev/rust/learn/clink$ ./test
5
False
"Testing"
Did I get here?
~/dev/rust/learn/clink$ 

Я добавил строку «Я сюда попал», потому что, когда я был изначально успешен в компиляции, программа завершила работу с ошибкой до завершения. Я пытался выяснить, была ли это печать CString, которая вызывала это или нет. Оказывается, у меня было что-то вроде двойного свободного состояния. Я добавлю пересмотренный код Rust в самом низу для полноты.

В качестве второго решения, которое мне больше нравится, вы можете использовать объектный файл:

~/dev/rust/learn/clink$ rustc --emit obj --crate-type staticlib rustlink.rs --verbose
~/dev/rust/learn/clink$ clang clink.c -o test rustlink.o ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libstd-89cf9eb8d404bb7b.so 
~/dev/rust/learn/clink$ ./test
5
False
"Testing"
Did I get here?
~/dev/rust/learn/clink$ 

Они оба дают один и тот же результат, и я не могу точно сказать, лучше ли один путь, чем другой. Это зависит от того, какие ваши требования находятся в разработке.

Последний. Мой оригинальный код выше для rustlink.rs был неверным. Я узнал, что использование CString, которое связано с необработанным указателем, является в значительной степени плохой идеей. Я думаю, что в большинстве случаев необходимо выделять собственную память. Это связано с drop. Я изменил функцию rust_char_star с исходного поста на следующий.

#[no_mangle]
pub extern "C" fn rust_char_star(c: *const c_char) {
    let ch = unsafe { CStr::from_ptr(c) };
    let str_printable = CString::from(ch);

    println!("{:?}", str_printable);
    println!("Did I get here?");
}

Это предотвращает то, что фактически является двойным свободным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...