5

I'm trying to build a cpp cmake project and link to my Rust project.

cmake_minimum_required(VERSION 3.0)
set (CMAKE_CXX_STANDARD 17)
project(ZLMediaKit_LIB CXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")

set(ENABLE_TESTS OFF FORCE)
option(ENABLE_TESTS OFF)

set(ENABLE_OPENSSL FALSE FORCE)
option(ENABLE_OPENSSL OFF)

add_subdirectory(ZLMediaKit)

add_library(libzlmediakit_cpp_interface STATIC interface.cpp)
target_include_directories(libzlmediakit_cpp_interface PUBLIC 
. 
${CMAKE_CURRENT_SOURCE_DIR}/ZLMediaKit/src 
${CMAKE_CURRENT_SOURCE_DIR}/ZLMediaKit/3rdpart/ZLToolKit/src)
target_link_libraries(libzlmediakit_cpp_interface zlmediakit zltoolkit mpeg mov flv libstdc++)
install(TARGETS libzlmediakit_cpp_interface DESTINATION .)

Here's my build.rs:

extern crate cmake;
use cmake::Config;

fn main()
{
    let dst = Config::new("zlmediakit_lib").build();       

    println!("cargo:rustc-link-search=native={}", dst.display());
    println!("cargo:rustc-link-lib=static=libzlmediakit_cpp_interface");    
}

But I'm getting undefined reference errors:

ong)':
          /usr/include/c++/9/ext/new_allocator.h:128: undefined reference to `operator delete(void*)'
          /usr/bin/ld: /home/dev/orwell/liborwell_rust/zlmediakit_rust/target/debug/build/zlmediakit_rust-499cc82f14515635/out/liblibzlmediakit_cpp_interface.a(interface.cpp.o): in function `ZLRTSPClient::~ZLRTSPClient()':
          /home/dev/orwell/liborwell_rust/zlmediakit_rust/zlmediakit_lib/ZLRTSPClient.h:14: undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
          /usr/bin/ld: /home/dev/orwell/liborwell_rust/zlmediakit_rust/target/debug/build/zlmediakit_rust-499cc82f14515635/out/liblibzlmediakit_cpp_interface.a(interface.cpp.o): in function `std::default_delete<ZLRTSPClient>::operator()(ZLRTSPClient*) const':
          /usr/include/c++/9/bits/unique_ptr.h:81: undefined reference to `operator delete(void*, unsigned long)'
          /usr/bin/ld: /home/dev/orwell/liborwell_rust/zlmediakit_rust/target/debug/build/zlmediakit_rust-499cc82f14515635/out/liblibzlmediakit_cpp_interface.a(interface.cpp.o): in function `__static_initialization_and_destruction_0(int, int)':
          /usr/include/c++/9/iostream:74: undefined reference to `std::ios_base::Init::Init()'
          /usr/bin/ld: /usr/include/c++/9/iostream:74: undefined reference to `std::ios_base::Init::~Init()'
          /usr/bin/ld: /home/dev/orwell/liborwell_rust/zlmediakit_rust/target/debug/build/zlmediakit_rust-499cc82f14515635/out/liblibzlmediakit_cpp_interface.a(interface.cpp.o):(.data.rel.local.DW.ref.__gxx_personality_v0[DW.ref.__gxx_personality_v0]+0x0): undefined reference to `__gxx_personality_v0'
          collect2: error: ld returned 1 exit status

I've researched and found some answers (Link error "undefined reference to `__gxx_personality_v0'" and g++) that old me to link against libstdc++. As you see, I'm already doing that.

If I try to compile the CMake project alone, it links sucessfully. However then I compile everything from the Rust side, it gives this error.

Complete output of rust compilation

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Paprika
  • 402
  • 5
  • 18

1 Answers1

0

In case anyone is still interested in this, it seems that you can fix it by doing to following:

  1. You can add this to Cargo.toml:
[lib]
crate-type = ["staticlib"]

However, if you do this, your library is basically unusable as a normal rust dependency, as this only produces a static C library (you can still run tests though :O). However, you shouldn't need to do this for bin crates (probably?).

If you actually want this to be a library, you have to somehow find the path to libstdc++.a and link it in the build.rs file by using println!("cargo:rustc-link-search=native=PATH_TO_LIB");.

You can get the path by running g++ --print-file-name=libstdc++.a, but of course you can't hard-code it into build.rs since it will be different on different systems.

  1. Then, you have two options:
  • Add println!("cargo:rustc-link-lib=static=stdc++"); to build.rs (ideally before the other print statements).
  • Run the build command as RUSTFLAGS="-C link-args=-lstdc++" cargo build.

Long story short, the statically linked library produced by cmake does not actually contain the stdc++ code, so we have to explicitly tell Rust where to go look for it.

If anyone has more insight into cmake and cargo, feel free to chime in and explain why this is necessary. As for me, I'm just glad it works.

daemontus
  • 1,047
  • 10
  • 17