Я только что пришел к Linux программированию на c ++ с Windows. Попытка сделать общую библиотеку libso.so , которая использует std::thread
. Общая библиотека будет загружена другими людьми и вызовет функцию экспорта. Тестовый код:
// so.cpp, the .so library
#include <iostream>
#include <thread>
using namespace std;
extern "C"
void run() {
cout << "run() begin" << endl;
std::thread t([] {
});
t.join();
cout << "run() end" << endl;
}
// test.cpp, the test loader
#include <dlfcn.h>
int main() {
typedef void (*run_t)();
auto dll = dlopen("libso.so", RTLD_LAZY);
run_t run = (run_t) dlsym(dll, "run");
run();
}
// The CMakeLists.txt file
cmake_minimum_required(VERSION 3.0)
PROJECT (test)
Include_Directories(${PROJECT_SOURCE_DIR})
Link_Directories(${PROJECT_BINARY_DIR})
add_library(so SHARED so.cpp )
target_link_libraries(so pthread)
add_executable( test test.cpp )
target_link_libraries(test pthread dl)
Сбой в функции run()
, вывод:
run() begin
“./test” terminated by signal SIGSEGV (Address boundary error)
Кажется, что std::thread
отлично работает в исполняемом файле , но не в общей библиотеке. Что мне не хватает?
Среда: g ++ 9.3.0, cmake 3.16.3
Отредактировано:
Попробуйте ldd.
ldd ./test
показывает нет pthread
, но ldd ./libso.so
имеет libpthread.so.0
. Разница в связывании параметров с SET(CMAKE_VERBOSE_MAKEFILE TRUE)
// linking executable 'test'
/usr/bin/c++ -rdynamic CMakeFiles/test.dir/test.cpp.o -o test -L/e/c/1/kali -Wl,-rpath,/e/c/1/kali -ldl -lpthread
// linking library 'libso.so'
/usr/bin/c++ -fPIC -shared -Wl,-soname,libso.so -o libso.so CMakeFiles/so.dir/so.cpp.o -L/e/c/2/kali -Wl,-rpath,/e/c/1/kali -lpthread
Единственная разница - -fPIC
, я погуглил и добавил set_property(TARGET test PROPERTY POSITION_INDEPENDENT_CODE ON)
к исполняемому файлу, но ничего не изменилось.
Обходной путь 1
Так как .so имеет libpthread.so.0
, я попытался добавить код в .so к исполняемому файлу:
int main() {
std::thread t([]{}); // to make executable linking to `pthread`
t.join();
// ... load dll and call run function
}
И это работает, теперь ldd ./test
показывает libpthread.so.0
, а не cra * sh. Это означает: если разделяемая библиотека использует std::thread
и исполняемый файл хочет ее загрузить, сам исполняемый файл также должен использовать std::thread
.
Обходной путь 2 :
std::thread
отлично работает в исполняемом файле, но вылетает в разделяемой библиотеке. Найдены некоторые связанные обсуждения , обход использует boost::thread
вместо std::thread
и связывается с библиотекой boost_thread
, без cra * sh.