I am trying to create a small example to show how to call C/C++ code in Rust.
Now I'm aware that you cannot call C++ code directly but you can wrap the C++ code in C. Then use that wrapper in Rust.
My issue is when any of my C/C++ code contains std::cout
, std::vector<type>
I get an error when compiling Rust.
Here is my Rust program
//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();
}
}
Here is my C++ program
//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();
}
}
I compile my c++ file with the command g++ -c another.cpp -o another.o
in the /src
directory of the cargo project.
But when I hit cargo run
I get this big error message
~/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
Now If I remove the following lines
std::vector<int> test;
std::cout << "Hello world again" << std::endl;
And recompile the c++ code with g++ -c another.cpp -o another.o
and hit cargo run
boom it works! I believe that Rust maybe is not able to find where std::vector
and std::cout
are located for whatever reason.
Now at first I figured that it might be impossible to do what I want to do. But then I found this post in which they are able to execute the following code which gets called in 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);
}
}
}
I think that the reason im not able to call std::cout
is related to the reason im not able to call std::vector<type>
. I am not sure why this is happening.
I did not originally choose something like cc
to compile my code because I have a big C++ library which depends on one library which is an extremely big C++ library. I want to be able to call this C++ library in Rust. I figured if somehow I could just link the object file it would be the easiest since my C++ library generates an object file with CMake.
I was compiling with g++
since if I knew if I could use an object file generated with with g++
from the CLI then I could also do that with the object file generated from CMake for my library.
I was not sure if I could use cc
to compile my C++ library. I would look into it more. Another user replied with suggestion of cxx
I will look into this.
Make a build script with the following content:
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++")
}
}
This will tell Cargo to link the standard library of C++. The code is pretty much taken from the code of cc
responsible for the same task.