Я пытаюсь создать небольшой пример, показывающий, как вызывать код C/C++ в Rust.
Теперь я знаю, что вы не можете напрямую вызывать код C++, но можете обернуть код C++ в C. Затем использовать эту оболочку в Rust.
Моя проблема заключается в том, что когда какой-либо мой код C/C++ содержит std::cout
, std::vector<type>
, я получаю сообщение об ошибке при компиляции Rust.
Вот моя программа на Rust
//main.rs
#[link(name = "/Users/alfredo/repos/rust-playground/c-cpp/src/another.o")]
extern "C" {
pub fn my_super_function();
}
fn main() {
unsafe {
my_super_function();
}
}
Вот моя программа на C++
//another.cpp
#include <iostream>
#include <vector>
class test_class {
public:
int thing;
test_class(){
this->thing = 10;
}
void print_val() {
//Works fine
std::printf("Hello world %d +++\n", 1);
printf("Hello world\n");
//Rust Compiler does not like
std::vector<int> test;
//Also does not like
std::cout << "Hello world again" << std::endl;
}
};
extern "C" {
void my_super_function(){
test_class testing;
testing.print_val();
}
}
Я компилирую свой файл C++ с помощью команды g++ -c another.cpp -o another.o
в каталоге /src
проекта Cargo.
Но когда я нажимаю cargo run
, я получаю большое сообщение об ошибке
~/repos/rust-playground/c-cpp/src (master*) » cargo run
Compiling c-cpp v0.1.0 (/Users/alfredo/repos/rust-playground/c-cpp)
error: linking with `cc` failed: exit status: 1
|
= note: env -u IPHONEOS_DEPLOYMENT_TARGET -u TVOS_DEPLOYMENT_TARGET LC_ALL = "C" PATH = "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/bin:/Users/alfredo/.pyenv/shims:/Users/alfredo/.local/bin:/Users/alfredo/.local/bin:/Users/alfredo/builds/emsdk:/Users/alfredo/builds/emsdk/upstream/emscripten:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Users/alfredo/.pyenv/shims:/Users/alfredo/.local/bin:/Users/alfredo/.cargo/bin" VSLANG = "1033" ZERO_AR_DATE = "1" "cc" "-arch" "arm64" "/var/folders/j2/7mgrf3yx347gbplvscllcpy00000gn/T/rustc7nloQf/symbols.o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e.16fn91fgrrtumhsg.rcgu.o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e.3cu4p06zqfau76or.rcgu.o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e.56ambxxn67rf7q42.rcgu.o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e.5a21onrgi1kafdlk.rcgu.o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e.kxoqkwimezc782q.rcgu.o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e.34n6f4r7d6zv5d1o.rcgu.o" "-L" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps" "-L" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib" "-l/Users/alfredo/repos/rust-playground/c-cpp/src/another.o" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libstd-d7097f83793f285d.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libpanic_unwind-50e7fd4712e1104c.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libobject-9bf4c2305270bb3d.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libmemchr-b9180b0bd18086ab.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libaddr2line-09f75b2a7a30a183.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libgimli-72b430ce2d1ca406.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/librustc_demangle-8016ac6fb72599e3.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libstd_detect-13855c7195db552b.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libhashbrown-c4874185cc82a43a.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/librustc_std_workspace_alloc-6ef0176aaa60ff0c.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libminiz_oxide-1e9f0e423eed4f7c.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libadler-263f3ba6f4d2645b.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libunwind-85e43ed53a81d633.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libcfg_if-279824e18f4fd20b.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/liblibc-b7ead8c5aa11dde6.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/liballoc-37d126161ada8ba6.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/librustc_std_workspace_core-c7113231a51981ef.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libcore-0e8873809402687b.rlib" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib/libcompiler_builtins-c3f3955ff7203236.rlib" "-lSystem" "-lc" "-lm" "-L" "/Users/alfredo/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/aarch64-apple-darwin/lib" "-o" "/Users/alfredo/repos/rust-playground/c-cpp/target/debug/deps/c_cpp-fa1cdd46941c638e" "-Wl,-dead_strip" "-nodefaultlibs"
= note: Undefined symbols for architecture arm64:
"std::__1::locale::use_facet(std::__1::locale::id&) const", referenced from:
std::__1::ctype<char> const& std::__1::use_facet[abi:ue170006]<std::__1::ctype<char>>(std::__1::locale const&) in another.o
"std::__1::ios_base::getloc() const", referenced from:
std::__1::basic_ios<char, std::__1::char_traits<char>>::widen[abi:ue170006](char) const in another.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::__init(unsigned long, char)", referenced from:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::basic_string[abi:ue170006](unsigned long, char) in another.o
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::~basic_string()", referenced from:
std::__1::ostreambuf_iterator<char, std::__1::char_traits<char>> std::__1::__pad_and_output[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char>>, char const*, char const*, char const*, std::__1::ios_base&, char) in another.o
std::__1::ostreambuf_iterator<char, std::__1::char_traits<char>> std::__1::__pad_and_output[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::ostreambuf_iterator<char, std::__1::char_traits<char>>, char const*, char const*, char const*, std::__1::ios_base&, char) in another.o
"std::__1::basic_ostream<char, std::__1::char_traits<char>>::put(char)", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::endl[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&) in another.o
"std::__1::basic_ostream<char, std::__1::char_traits<char>>::flush()", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::endl[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&) in another.o
"std::__1::basic_ostream<char, std::__1::char_traits<char>>::sentry::sentry(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
"std::__1::basic_ostream<char, std::__1::char_traits<char>>::sentry::~sentry()", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
"std::__1::cout", referenced from:
test_class::print_val() in another.o
"std::__1::ctype<char>::id", referenced from:
std::__1::ctype<char> const& std::__1::use_facet[abi:ue170006]<std::__1::ctype<char>>(std::__1::locale const&) in another.o
"std::__1::locale::~locale()", referenced from:
std::__1::basic_ios<char, std::__1::char_traits<char>>::widen[abi:ue170006](char) const in another.o
std::__1::basic_ios<char, std::__1::char_traits<char>>::widen[abi:ue170006](char) const in another.o
"std::__1::ios_base::__set_badbit_and_consider_rethrow()", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
"std::__1::ios_base::clear(unsigned int)", referenced from:
std::__1::ios_base::setstate[abi:ue170006](unsigned int) in another.o
"std::terminate()", referenced from:
___clang_call_terminate in another.o
"operator delete(void*)", referenced from:
std::__1::allocator<int>::deallocate[abi:ue170006](int*, unsigned long) in another.o
void std::__1::__libcpp_operator_delete[abi:ue170006]<void*>(void*) in another.o
"___cxa_begin_catch", referenced from:
___clang_call_terminate in another.o
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
"___cxa_call_unexpected", referenced from:
std::__1::char_traits<char>::length[abi:ue170006](char const*) in another.o
std::__1::ostreambuf_iterator<char, std::__1::char_traits<char>>::ostreambuf_iterator[abi:ue170006](std::__1::basic_ostream<char, std::__1::char_traits<char>>&) in another.o
std::__1::vector<int, std::__1::allocator<int>>::__base_destruct_at_end[abi:ue170006](int*) in another.o
std::__1::allocator<int>::deallocate[abi:ue170006](int*, unsigned long) in another.o
"___cxa_end_catch", referenced from:
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
std::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:ue170006]<char, std::__1::char_traits<char>>(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, char const*, unsigned long) in another.o
"___gxx_personality_v0", referenced from:
/Users/alfredo/repos/rust-playground/c-cpp/src/another.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: could not compile `c-cpp` (bin "c-cpp") due to 1 previous error
Теперь, если я удалю следующие строки
std::vector<int> test;
std::cout << "Hello world again" << std::endl;
Перекомпилируйте код C++ с помощью g++ -c another.cpp -o another.o
и нажмите cargo run
— бум, все работает! Я считаю, что Rust по какой-то причине не может найти, где расположены std::vector
и std::cout
.
Сначала я подумал, что, возможно, невозможно сделать то, что я хочу. Но потом я нашел этот пост, в котором они могут выполнить следующий код, который вызывается в Rust.
#include <iostream>
#include <stdint.h>
#include <unistd.h>
extern "C" {
int print_it(int32_t num) {
while (1) {
std::cout << num << std::endl;
sleep(1);
}
}
}
Я думаю, что причина, по которой я не могу вызвать std::cout
, связана с причиной, по которой я не могу вызвать std::vector<type>
. Я не уверен, почему это происходит.
Изначально я не выбирал что-то вроде cc
для компиляции своего кода, потому что у меня есть большая библиотека C++, которая зависит от одной библиотеки, которая является чрезвычайно большой библиотекой C++. Я хочу иметь возможность вызывать эту библиотеку C++ в Rust. Я подумал, что если бы я мог просто связать объектный файл, это было бы проще всего, поскольку моя библиотека C++ генерирует объектный файл с помощью CMake.
Я компилировал с помощью g++
, поскольку если бы я знал, могу ли я использовать объектный файл, сгенерированный с помощью g++
из CLI, то я также мог бы сделать то же самое с объектным файлом, сгенерированным из CMake для моей библиотеки.
Я не был уверен, смогу ли я использовать cc
для компиляции своей библиотеки C++. Я бы присмотрелся к этому подробнее. Другой пользователь ответил, предложив cxx
Я рассмотрю это.
Не рекомендуется ли cxx для взаимодействия с C++?
@sweenish CXX - если вы хотите взаимодействовать с типами C++, если вы хотите взаимодействовать в стиле C (как это делает OP), вам нужно только правильно скомпилировать и связать, и это работа для cc
.
Создайте скрипт сборки следующего содержания:
fn main() {
let target = std::env::var("TARGET").unwrap();
if target.contains("msvc") {
// Do nothing.
} else if target.contains("apple")
| target.contains("freebsd")
| target.contains("openbsd")
| target.contains("aix")
| target.contains("linux-ohos")
{
println!("cargo:rustc-link-lib=c++")
} else if target.contains("android") {
println!("cargo:rustc-link-lib=c++_shared")
} else {
println!("cargo:rustc-link-lib=stdc++")
}
}
Это скажет Cargo связать стандартную библиотеку C++. Код практически взят из кода cc, отвечающего за ту же задачу.
libstdc++ не связывается. Самый простой способ — использовать крейт cc для компиляции кода C++.