linker - 导入到 python 时使用 Boost.python 包装 C++ 模块时的未定义符号
问题描述
我正在尝试使用 Boost.Python为 C++ 库fbow创建一个 Python 包装器。我的代码灵感来自另一个包装器pyDBoW3到一个非常相似的库DBoW3。到目前为止,我能做的是: pyBoW3 包装器在我的系统上工作——我可以将它导入 Python 并让它做它的事情。我试图创建的pyfbow包装器在准系统中工作,但是一旦我尝试链接一个使用底层 fbow 库中的某些东西的函数,它就会抛出:
$ python -c "import pyfbow.so"
ImportError: dlopen(/Users/vik748/pyfbow/build/pyfbow.so, 2): Symbol not found: __ZN4fbow10Vocabulary10saveToFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
Referenced from: /Users/vik748/pyfbow/build/pyfbow.so
Expected in: flat namespace
in /Users/vik748/pyfbow/build/pyfbow.so
$ nm pyfbow.dylib | grep __ZN4fbow10Vocabulary10saveToFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
U __ZN4fbow10Vocabulary10saveToFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
$ c++filt -n __ZN4fbow10Vocabulary10saveToFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE
fbow::Vocabulary::saveToFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
包装器代码的主要片段是:
class Vocabulary
{
public:
Vocabulary(int k = 10, int L = 6, int nthreads = 1, int maxIters = 0, bool verbose = true){
voc_creator_params.k = k;
voc_creator_params.L = L;
voc_creator_params.nthreads = nthreads;
voc_creator_params.maxIters = maxIters;
voc_creator_params.verbose = verbose;
}
~Vocabulary() {
//delete voc;
//delete voc_creator;
}
void create(const std::vector<cv::Mat> &training_features ) {
std::cout << "Creating a " << voc_creator_params.k << "^" << voc_creator_params.L << " vocabulary..." << std::endl;
voc_creator->create(*voc, training_features, std::string("NA"), voc_creator_params);
}
fbow::Vocabulary * voc;
fbow::VocabularyCreator * voc_creator;
fbow::VocabularyCreator::Params voc_creator_params;
};
namespace fs {
namespace python {
BOOST_PYTHON_MODULE(pyfbow)
{
// Main types export
fs::python::init_and_export_converters();
py::scope scope = py::scope();
// Class
py::class_<Vocabulary>("Vocabulary")
.def(py::init< py::optional<int, int, int, int, bool> >(
(py::arg("k") = 10, py::arg("L") = 5, py::arg("nthreads") = 1,
py::arg("maxIters") = 0, py::arg("verbose") = true )))
.def("create", &Vocabulary::create);
}
} // namespace fs
} // namespace python
如果您想在您的系统上进行测试,唯一的依赖项是 boost-python 和 opencv。在https://github.com/vik748/pyfbow的 repo 上有一个构建脚本,它可以让它很快运行。
现在,如果我注释掉voc_creator->create(*voc, training_features, std::string("NA"), voc_creator_params);
一切正常,代码编译,链接,我就可以将包导入 Python。但是,如果该行未注释,则代码会编译并链接,但导入 python 会引发上述错误。
这是我尝试过的所有事情:
- 如此处所述,我尝试添加
boost::noncopyable
- 如此处所述,我已将代码添加到底层 fbow 库正在使用的几个空虚函数中。
- 我认为这表明不同的编译器可能会导致问题,但由于代码编译时带有注释行,我认为这不是问题所在。
- 按照这里的建议,我还尝试将 pyfbow 和 fbow 合并到同一个包和 CMakeLists.txt 中,但这也没有帮助。
- 此外,根据其他几个不同的 SO 帖子,我尝试了一堆链接器标志
-Wl -export_dynamic -flat_namespace -export-dynamic
等。
我想尽办法解决这个问题,我欢迎任何调试想法。干杯!
根据@ead 的建议,我正在添加来自ld --trace-symbol
ld pyfbow.so --trace-symbol=_ZN4fbow17VocabularyCreator6createERNS_10VocabularyERKSt6vectorIN2cv3MatESaIS5_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS0_6ParamsE
pyfbow.so: reference to _ZN4fbow17VocabularyCreator6createERNS_10VocabularyERKSt6vectorIN2cv3MatESaIS5_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS0_6ParamsE
ld: warning: cannot find entry symbol _start; not setting start address
pyfbow.so: undefined reference to `fbow::VocabularyCreator::create(fbow::Vocabulary&, std::vector<cv::Mat, std::allocator<cv::Mat> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, fbow::VocabularyCreator::Params)'
解决方案
TLDR:fbow 库 findcmake 正在设置 fbar_LIBS 变量,而我的包装器正在读取 fbar_LIBRARIES 变量。
如何调试:根据@ead 的建议和提供的链接,我在运行 make 时添加了set( CMAKE_VERBOSE_MAKEFILE on)
参数,CMakeLists.txt
我能够查看 cmake_link_script。我将它与 pyDBoW3 包中的那个进行了比较,发现 -L 参数更少。在进一步调查中,我发现那fbow_LIBRARIES
是空的。在检查包的 fbowConfig.cmake 时,它正在设置 fbow_LIBS 变量。切换名称解决了所有问题。
感谢@ead 的帮助。
推荐阅读
- firefox - SVG 文本路径渲染在 Firefox 中出现反转
- c# - 如何在不等待内部方法完成的情况下立即返回“ok”
- java - RecyclerView 搜索过滤器在过滤结果后位置错误
- vscode-remote - 如何在 Windows 中通过 git bash 连接 vscode-remote-ssh 扩展?
- python - 在linux上安装pandas,只用一个python文件
- python - 如何使用文件名(如果提供)或标准输入(如果未提供 argparse)
- ios - UISearchBar 不会更改 iOS 12.1 的搜索图标和占位符颜色
- c++ - 如何重载流运算符以使用位于不同文件中的函数?
- python - 比较两个字符(在字符串内)如何在 Python 中工作
- flutter - 在 DropdownButton 中选择项目时出现断言错误