Reputation: 113
I'm integrating a static library based on c/c++ into a shared library based on c (using cmake on linux).
I have errors like this: libmylib.so: undefined reference to `std::ios_base::Init::Init()'
The problem is strongly related with the use of c++ and its linking to the shared library. If I avoid the shared library (even another static library) no error occurs. Because of my project I can not avoid that shared library which uses the static library.
How to generate a properly shared library from an c/c++ static library and new c source code?
PD: I'm sorry for the long question, I'm posting the code in order to give you some context of my problem.
cppexample.hpp
typedef struct cpp_api
{
int (*func_ptr)(const char *, int);
} cpp_api;
#ifdef __cplusplus
extern "C" {
#endif
const cpp_api* getApi();
#ifdef __cplusplus
}
#endif
cppexample.cpp
int apiFunc(const char *strc, int value)
{
std::string str(strc);
std::cout << "Api call: " << str << std::endl;
return value;
}
static const cpp_api libapi =
{
&apiFunc,
};
extern "C"
{
const cpp_api* getApi()
{
return &libapi;
}
}
example.h
void doSomething();
example.c
#include "example.h"
#include "cpp_lib/cppexample.hpp"
void doSomething()
{
const cpp_api *api = getApi();
int result = api->func_ptr("hello!", 12);
}
mainApi.h
void callDoSomething();
mainApi.c
#include "mainApi.h"
#include "mix_lib/example.h"
void callDoSomething()
{
doSomething();
}
main.c
#include "mainApi.h"
int main(int argc, const char* argv[])
{
callDoSomething();
return 0;
}
Libary gene
cmake_minimum_required(VERSION 3.5)
set(CMAKE_BUILD_TYPE "Release") #Not debug
set(THIS MAINLIB) #project name
project(${THIS} C CXX) #For c and c++
set(CMAKE_C_STANDARD 99) #c99
set(CMAKE_CXX_STANDARD 11) #c++11
set(CMAKE_POSITION_INDEPENDENT_CODE ON) #fPIC
set(MAIN_LIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
###### MAIN LIB ######
include_directories(${MAIN_LIB_ROOT} ${MAIN_LIB_ROOT}/main)
list(APPEND MAIN_LIB_SOURCES
"${MAIN_LIB_ROOT}/main/mainApi.h"
"${MAIN_LIB_ROOT}/main/mainApi.c")
set(MAIN_LIB_NAME mainlib)
add_library(${MAIN_LIB_NAME} STATIC ${MAIN_LIB_SOURCES})
include("${MAIN_LIB_ROOT}/cpp_lib/cpp_lib.cmake")
include("${MAIN_LIB_ROOT}/mix_lib/mix_lib.cmake")
setup_cpp_lib()
setup_mix_lib()
###### MAIN EXECUTABLE ######
add_executable(${THIS} "${MAIN_LIB_ROOT}/main.c")
target_link_libraries(${THIS} PUBLIC ${MAIN_LIB_NAME})
list(APPEND MAIN_INSTALL_BINS
${THIS})
setup_cpp_lib()
list(APPEND CPP_LIB_SOURCES
"${MAIN_LIB_ROOT}/cpp_lib/cppexample.hpp"
"${MAIN_LIB_ROOT}/cpp_lib/cppexample.cpp")
function(setup_cpp_lib)
add_library(cpplib OBJECT ${CPP_LIB_SOURCES})
target_sources(${MAIN_LIB_NAME} PRIVATE $<TARGET_OBJECTS:cpplib>)
endfunction()
setup_mix_lib()
list(APPEND MIX_LIB_SOURCES
"${MAIN_LIB_ROOT}/mix_lib/example.h"
"${MAIN_LIB_ROOT}/mix_lib/example.c")
function(setup_mix_lib)
add_library(mixlib OBJECT ${MIX_LIB_SOURCES})
target_sources(${MAIN_LIB_NAME} PRIVATE $<TARGET_OBJECTS:mixlib>)
endfunction()
Until here the libmainlib.a
is created. I copied that library and the mainApi.h
and main.c
to another project and the error occurs
cmake_minimum_required(VERSION 3.5)
set(CMAKE_BUILD_TYPE "Release") #Not debug
set(THIS MYPROJECT) #project name
project(${THIS} C CXX) #For c only
set(CMAKE_C_STANDARD 99) #c99
set(CMAKE_CXX_STANDARD 11) #c++11
set(MAIN_LIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") #current cmakelists path
include_directories(${MAIN_LIB_ROOT}/includes) #includes for library headers
add_library(mylib SHARED "${MAIN_LIB_ROOT}/main.c")
add_library(mainlib STATIC IMPORTED)
set_property(TARGET mainlib PROPERTY IMPORTED_LOCATION ${MAIN_LIB_ROOT}/lib/libmainlib.a)
target_link_libraries(mylib mainlib)
add_executable(${THIS} "${MAIN_LIB_ROOT}/main.c")
target_link_libraries(${THIS} mylib)
list(APPEND MAIN_INSTALL_BINS ${THIS})
install(TARGETS ${MAIN_INSTALL_BINS} DESTINATION "${CMAKE_INSTALL_PREFIX}")
libmylib.so: undefined reference to `std::ios_base::Init::Init()'
libmylib.so: undefined reference to `std::string::_Rep::_M_destroy(std::allocator<char> const&)'
libmylib.so: undefined reference to `std::string::_Rep::_S_empty_rep_storage'
libmylib.so: undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)'
collect2: error: ld returned 1 exit status
make[2]: *** [MYPROJECT] Error 1
make[1]: *** [CMakeFiles/MYPROJECT.dir/all] Error 2
make: *** [all] Error 2
===Edit===
I have a static library called
libmainlib.a
(simulates a complex library that was modified injecting c++ code). That library is used to generate a shared library calledlibmylib.so
(simulates another complex library that I didn't modify but uses the static library).
Upvotes: 3
Views: 327
Reputation: 66061
You got that undefined references because mylib
library is linked as C object. But since the static library libmainlib.a
is a C++ one, it requires C++ linking. For more info about origin of such undefined references that question: undefined reference to `std::ios_base::Init::Init()'.
Such incorrect linking is because the library mainlib
in your second code is STATIC
IMPORTED
(both keywords are important) and CMake isn't aware of the actual language of that library.
You need to hint CMake that given library is actually a C++ one and requires C++ linking:
set_property(TARGET mainlib PROPERTY IMPORTED_LINK_INTERFACE_LANGUAGES CXX)
Your first code works correctly, because its mainlib
library, while it is STATIC, is not IMPORTED
one and CMake knows its sources. As a source cppexample.cpp
is definitely a C++ one, CMake treats mainlib
library as C++.
Upvotes: 5