My aim is to provide a new C++ shared library that will by called by Python using Pybind, to expose existing C++ functionality. The Python aspect is not super relevant here, but just for context.
The shared library essentially provides an interface, that then calls functionality in an existing project, called "core", provided by a static library (libcore.a). Core is NOT built with PIC.
For now, I am simply trying to get the basics working:
- test_app - this is a C++ stand in for the Python client - the problem I will get to is demonstrated here
- lib_interface - the .so I want to generate
- lib_core - the .a representing all the existing functionality
It is important to me NOT to use PIC, but instead relocation (https://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries/).
This is all with CMAKE, on Ubuntu 20, gcc 9.4.0.
\CmakeLists.txt
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-pthread -Wall -fopenmp -fuse-ld=lld")
project("test LANGUAGES CXX")
add_subdirectory(test_app)
add_subdirectory(lib_interface)
add_subdirectory(lib_core)
test_app\CmakeLists.txt
add_executable(test_app main.cpp)
target_link_libraries(test_app PUBLIC
${CMAKE_BINARY_DIR}/lib_interface/liblib_interface.so
)
test_app\main.cpp
#include <iostream>
#include "../lib_interface/lib_interface.h"
int main()
{
std::cout << "Test app start" << std::endl;
lib_interface::foo();
return 0;
}
lib_interface\CmakeLists.txt
add_library(lib_interface SHARED lib_interface.cpp)
set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") # in order to remove -fPIC
target_link_libraries(lib_interface PRIVATE
${CMAKE_BINARY_DIR}/lib_core/liblib_core.a
)
lib_interface\lib_interface.cpp
#include <iostream>
#include "lib_interface.h"
#include "../lib_core/lib_core.h"
void lib_interface::foo()
{
std::cout << "lib_interface - foo"<< std::endl;
std::cout << "calling lib_core"<< std::endl;
lib_core::bla();
}
lib_core\CmakeLists.txt
add_library(lib_core STATIC lib_core.cpp)
lib_core\lib_core.cpp
#include <iostream>
#include "lib_core.h"
void lib_core::bla()
{
std::cout << "lib_core - bla"<< std::endl;
}
Building as presented, I get this error
FAILED: lib_interface/liblib_interface.so
: && /usr/bin/c++ -pthread -Wall -fopenmp -fuse-ld=lld -g -shared -Wl,-soname,liblib_interface.so -o lib_interface/liblib_interface.so lib_interface/CMakeFiles/lib_interface.dir/lib_interface.cpp.o lib_core/liblib_core.a && :
ld.lld: error: relocation R_X86_64_PC32 cannot be used against symbol std::cout; recompile with -fPIC
Adding -fPIC is not acceptable - this is one of those cases where the performance impact is a problem, and up-front loading time is best.
Going off of Possible to build a shared library with static link used library? , it seems that -static is needed.
Adding
set_target_properties(lib_interface PROPERTIES LINK_FLAGS "-static")
to lib_interface\CMakeList.txt, I get:
FAILED: lib_interface/liblib_interface.so
: && /usr/bin/c++ -pthread -Wall -fopenmp -fuse-ld=lld -g -static -shared -Wl,-soname,liblib_interface.so -o lib_interface/liblib_interface.so lib_interface/CMakeFiles/lib_interface.dir/lib_interface.cpp.o lib_core/liblib_core.a && :
ld.lld: error: can't create dynamic relocation R_X86_64_32 against symbol: __TMC_END__ in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
which seems more promising.
Adding
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-z,notext")
to lib_interface\CMakeList.txt, the error is now:
FAILED: lib_interface/liblib_interface.so
: && /usr/bin/c++ -pthread -Wall -fopenmp -fuse-ld=lld -Wl,-z,notext -g -static -shared -Wl,-soname,liblib_interface.so -o lib_interface/liblib_interface.so lib_interface/CMakeFiles/lib_interface.dir/lib_interface.cpp.o lib_core/liblib_core.a && :
ld.lld: error: relocation R_X86_64_32 cannot be used against symbol __TMC_END__; recompile with -fPIC
Appreciate a pointer on where I'm going wrong.