将pybind11与调用外部函数的动态库链接时出现未定义符号错误
Undefined Symbol error when linking pybind11 with a dynamic library that calls an external function
我正在尝试 link 带有 .so
动态库的 pybind11 模块,而该库调用的函数未在 .so
文件中实现。它在普通的 c++ 可执行文件中工作正常,但在 python.
中导入时会引发 Undefined Symbol
错误
这里有一个简单的演示来重现我的问题。
函数 Student::print()
被编译为一个动态库,它调用了 .so
文件中未包含的函数 Student::setId()
。 (如果使用nm
命令,会显示U _ZN7Student5setIdEi
。)
它在 main.cpp
中调用 Student::print()
工作正常,但在 test.py
中它引发 ImportError: {mypath}/libstu_lib.so: undefined symbol: _ZN7Student5setIdEi
为了简化,我将外部函数设置为它自己的成员函数。当调用属于另一个 类 的函数时问题仍然重现,所以我认为这无关紧要。
pybind11 中有没有选项可以解决这个问题?因为很难修改动态库的源代码。谢谢。
Student.h
#include <iostream>
using namespace std;
class Student {
public:
Student(int id);
void setId(int id);
void print();
private:
int id;
};
Student.cpp
#include "Student.h"
Student::Student(int id) {
this->id = id;
}
void Student::setId(int id) {
this->id = id;
}
Student_lib.cpp
#include "Student.h"
void Student::print() {
cout << "id: " << this->id << endl;
this->setId(111);
cout << "id: " << this->id << endl;
}
Student_wrapper.cpp
#include <pybind11/pybind11.h>
#include "Student.h"
namespace py = pybind11;
PYBIND11_MODULE(stu, m){
py::class_<Student>(m, "Student")
.def(py::init<int>())
.def("setId", &Student::setId)
.def("print", &Student::print);
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(test)
link_directories(${PROJECT_SOURCE_DIR})
add_library(stu_lib SHARED Student_lib.cpp)
add_executable(main main.cpp Student.cpp)
target_link_libraries(main stu_lib)
find_package(pybind11 REQUIRED)
pybind11_add_module(stu Student_wrapper.cpp Student.cpp)
target_link_libraries(stu PUBLIC stu_lib)
main.cpp
#include "Student.h"
int main(int argc, char** argv) {
Student* s = new Student(1);
s->print();
return 0;
}
test.py
from stu import Student
s = Student(1)
s.print()
ldd libstu_core.so
的输出:
linux-vdso.so.1 (0x00007ffcffdac000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3def395000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3def1a3000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3def054000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3def593000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3def039000)
老实说:我不知道 pybind11 的内部工作原理如何足以告诉您为什么 会发生这种情况。但是,有一种解决方法可以使您的代码正常工作,即将 Student.cpp
编译到它自己的共享库中,并将其 link 编译到 pybind11 模块。您可以通过以下方式修改 CMakeLists.txt
以使其正常工作:
cmake_minimum_required(VERSION 3.15)
project(test)
link_directories(${PROJECT_SOURCE_DIR})
add_library(stu_lib SHARED Student_lib.cpp)
add_executable(main main.cpp Student.cpp)
target_link_libraries(main stu_lib)
find_package(pybind11 REQUIRED)
add_library(stu_class SHARED Student.cpp)
pybind11_add_module(stu Student_wrapper.cpp)
target_link_libraries(stu PUBLIC stu_lib stu_class)
我正在尝试 link 带有 .so
动态库的 pybind11 模块,而该库调用的函数未在 .so
文件中实现。它在普通的 c++ 可执行文件中工作正常,但在 python.
Undefined Symbol
错误
这里有一个简单的演示来重现我的问题。
函数 Student::print()
被编译为一个动态库,它调用了 .so
文件中未包含的函数 Student::setId()
。 (如果使用nm
命令,会显示U _ZN7Student5setIdEi
。)
它在 main.cpp
中调用 Student::print()
工作正常,但在 test.py
中它引发 ImportError: {mypath}/libstu_lib.so: undefined symbol: _ZN7Student5setIdEi
为了简化,我将外部函数设置为它自己的成员函数。当调用属于另一个 类 的函数时问题仍然重现,所以我认为这无关紧要。
pybind11 中有没有选项可以解决这个问题?因为很难修改动态库的源代码。谢谢。
Student.h
#include <iostream>
using namespace std;
class Student {
public:
Student(int id);
void setId(int id);
void print();
private:
int id;
};
Student.cpp
#include "Student.h"
Student::Student(int id) {
this->id = id;
}
void Student::setId(int id) {
this->id = id;
}
Student_lib.cpp
#include "Student.h"
void Student::print() {
cout << "id: " << this->id << endl;
this->setId(111);
cout << "id: " << this->id << endl;
}
Student_wrapper.cpp
#include <pybind11/pybind11.h>
#include "Student.h"
namespace py = pybind11;
PYBIND11_MODULE(stu, m){
py::class_<Student>(m, "Student")
.def(py::init<int>())
.def("setId", &Student::setId)
.def("print", &Student::print);
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(test)
link_directories(${PROJECT_SOURCE_DIR})
add_library(stu_lib SHARED Student_lib.cpp)
add_executable(main main.cpp Student.cpp)
target_link_libraries(main stu_lib)
find_package(pybind11 REQUIRED)
pybind11_add_module(stu Student_wrapper.cpp Student.cpp)
target_link_libraries(stu PUBLIC stu_lib)
main.cpp
#include "Student.h"
int main(int argc, char** argv) {
Student* s = new Student(1);
s->print();
return 0;
}
test.py
from stu import Student
s = Student(1)
s.print()
ldd libstu_core.so
的输出:
linux-vdso.so.1 (0x00007ffcffdac000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3def395000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3def1a3000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3def054000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3def593000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3def039000)
老实说:我不知道 pybind11 的内部工作原理如何足以告诉您为什么 会发生这种情况。但是,有一种解决方法可以使您的代码正常工作,即将 Student.cpp
编译到它自己的共享库中,并将其 link 编译到 pybind11 模块。您可以通过以下方式修改 CMakeLists.txt
以使其正常工作:
cmake_minimum_required(VERSION 3.15)
project(test)
link_directories(${PROJECT_SOURCE_DIR})
add_library(stu_lib SHARED Student_lib.cpp)
add_executable(main main.cpp Student.cpp)
target_link_libraries(main stu_lib)
find_package(pybind11 REQUIRED)
add_library(stu_class SHARED Student.cpp)
pybind11_add_module(stu Student_wrapper.cpp)
target_link_libraries(stu PUBLIC stu_lib stu_class)