user3288829
user3288829

Reputation: 1275

force target_link_libraries to use c++ linker

TL;DR

Is there a way to force cmake to use the c++ linker when linking a static c++ library to a c executable?


I have a static library that consists of 2 objects, a C++ file and a C wrapper to the functions in that file (Constructor, Destructor, and Print function), similar to this SO answer. The last paragraph states:

The fun part is now ensuring that you get all the required C++ libraries linked into you larger library correctly. For gcc (or clang) that means just doing the final link stage using g++.

I can verify this with my MCVE. Replacing gcc with g++ fixes the problem and everything works

$ gcc -static main.c -L. -lCPPclass -o main
./libCPPclass.a(CInt.o): In function `newCINT':
CInt.cpp:(.text+0xd): undefined reference to `operator new(unsigned long)'
CInt.cpp:(.text+0x28): undefined reference to `operator delete(void*)'
./libCPPclass.a(CInt.o): In function `delCINT':
CInt.cpp:(.text+0x5e): undefined reference to `operator delete(void*)'
./libCPPclass.a(CInt.o):(.eh_frame+0x13): undefined reference to `__gxx_personality_v0'
./libCPPclass.a(CPPclass.o): In function `CPPclass::print_success()':
CPPclass.cpp:(.text+0x26): undefined reference to `std::cout'
CPPclass.cpp:(.text+0x2b): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
./libCPPclass.a(CPPclass.o): In function `__static_initialization_and_destruction_0(int, int)':
CPPclass.cpp:(.text+0x54): undefined reference to `std::ios_base::Init::Init()'
CPPclass.cpp:(.text+0x63): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
$
$#REPLACE gcc with g++
$
$ g++ -static main.c -L. -lCPPclass -o main
$ ./main
Success!

My real code, however, is built using CMake, so I'm trying to get this MCVE built with CMake, which takes me back to my original question. My CMakeLists.txt file is as follows:

cmake_minimum_required(VERSION 2.8)
project(Cmain C CXX)

add_library(CPPclass STATIC IMPORTED)
set_property(TARGET CPPclass PROPERTY IMPORTED_LOCATION ./libCPPclass.a)
add_executable(main main.c)
target_link_libraries(main CPPclass)

However, when I run cmake . and then make I get the same errors as above

$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/me/temp
$ make
Linking C executable main
./libCPPclass.a(CInt.o): In function `newCINT':
CInt.cpp:(.text+0xd): undefined reference to `operator new(unsigned long)'
CInt.cpp:(.text+0x28): undefined reference to `operator delete(void*)'

etc. Of course if I renamed main.c to main.cpp, CMake would compile the executable with g++ and target_link_libraries would execute without error, but it kind of defeats the purpose of the c wrapper and doesn't work in my real use case.

Upvotes: 4

Views: 6154

Answers (3)

user7610
user7610

Reputation: 28751

Set linker language to CXX on your target

set_target_properties(my_target PROPERTIES LINKER_LANGUAGE CXX)

I think this is better than the stdc++ answer because it is general (I am currently dealing with clang's libc++). It is maybe not better than the IMPORTED_LINK_INTERFACE_LANGUAGES answer, but it is certainly more direct.

Upvotes: 5

steveire
steveire

Reputation: 11074

Do this:

set_target_properties(CPPclass PROPERTIES
  IMPORTED_LOCATION ./libCPPclass.a
  IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
)

Upvotes: 3

user3288829
user3288829

Reputation: 1275

As @BillyONeal mentioned in the comments above, I don't need a different linker to get the additional libraries needed, I just had to add libstdc++ to the list of libraries to be linked.

cmake_minimum_required(VERSION 2.8)
project(Cmain C CXX)

add_library(CPPclass STATIC IMPORTED)
set_property(TARGET CPPclass PROPERTY IMPORTED_LOCATION ./libCPPclass.a)
add_executable(main main.c)
target_link_libraries(main CPPclass stdc++)

Upvotes: 0

Related Questions