Reputation: 1275
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
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
Reputation: 11074
Do this:
set_target_properties(CPPclass PROPERTIES
IMPORTED_LOCATION ./libCPPclass.a
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
)
Upvotes: 3
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