如何正确地满足以下pybind11项目中的所有链接器依赖项

How to properly satisfy all linker dependencies in following pybind11 project?

本文关键字:链接 依赖 项目 正确地 满足 pybind11      更新时间:2024-09-28

我正在为python接口将一个大型库移植到pybind11。然而,我一直在链接器阶段获取multiple declaration error,或者在python导入过程中获取symbol not found错误。简化的项目结构如下所示

CMake文件

cmake_minimum_required(VERSION 3.5)
# set the project name
project(tmp VERSION 1.0)
find_package(EnvModules REQUIRED)
env_module(load python39)

find_package(PythonInterp REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
include_directories(pybind11/include)
add_subdirectory(pybind11)
pybind11_add_module(TMP py_modules.cpp
SubConfiguration.cpp)
# pybind11_add_module(TMP py_modules.cpp)

源文件:py_modules.cpp

#include "pybind11/pybind11.h"
#include "calculateStress.h"
namespace py = pybind11;
PYBIND11_MODULE(TMP, m){
py::class_<Stencil>(m, "Stencil")
.def(py::init<double &>());
py::class_<SubConfiguration>(m, "SubConfiguration")
.def(py::init<Stencil &>());
}
  1. calculateStress.h
#ifndef CALCULATESTRESS_H_
#define CALCULATESTRESS_H_
#include "SubConfiguration.h"
#endif /* CALCULATESTRESS_H_ */
  1. SubConfiguration.h
#ifndef SRC_SUBCONFIGURATION_H_
#define SRC_SUBCONFIGURATION_H_
#include "Stencil.h"
class SubConfiguration
{
public:
double& parent;
SubConfiguration(Stencil& stencil);
};
#endif /* SRC_SUBCONFIGURATION_H_ */
  1. SubConfiguration.cpp
#include "SubConfiguration.h"
SubConfiguration::SubConfiguration(Stencil& stencil) :
parent(stencil.parent)
{}
  1. Stencil.h
#ifndef SRC_STENCIL_H_
#define SRC_STENCIL_H_
class Stencil {
public:
double parent;
Stencil(double&);
};
Stencil::Stencil(double& parent) : parent(parent) { }
#endif /* SRC_STENCIL_H_ */

我认为所有的进口保护措施都设置得当。

现在,当我给pybind11_add_module(TMP py_modules.cpp)编译选项时,我得到了TMP模块,但在导入时,我收到了错误undefined symbol: _ZN16SubConfigurationC1ER7Stencil

而使用pybind11_add_module(TMP py_modules.cpp SubConfiguration.cpp),我得到以下错误

/usr/bin/ld: CMakeFiles/TMP.dir/SubConfiguration.cpp.o (symbol from plugin): in function `Stencil::Stencil(double&)':
(.text+0x0): multiple definition of `Stencil::Stencil(double&)'; CMakeFiles/TMP.dir/py_modules.cpp.o (symbol from plugin):(.text+0x0): first defined here
/usr/bin/ld: CMakeFiles/TMP.dir/SubConfiguration.cpp.o (symbol from plugin): in function `Stencil::Stencil(double&)':
(.text+0x0): multiple definition of `Stencil::Stencil(double&)'; CMakeFiles/TMP.dir/py_modules.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/TMP.dir/build.make:99: TMP.cpython-39-x86_64-linux-gnu.so] Error 1
make[1]: *** [CMakeFiles/Makefile2:96: CMakeFiles/TMP.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

如何正确设置?

问题是Stencil.h同时包含在py_modules.cpp和SubConfiguration.cpp中。include保护只能防止来自单个编译单元(cpp文件(的双重包含。

Stencil.h中删除Stencil构造函数的实现,并将其作为移动到新文件Stencil.cpp

#include "Stencil.h"
Stencil::Stencil(double& parent) : parent(parent) { }

然后将新文件添加到您的模块

...
add_subdirectory(pybind11)
pybind11_add_module(TMP py_modules.cpp SubConfiguration.cpp Stencil.cpp )

更新(反映意见(

如果您有一个模板化的类,则不一定需要在头中包含实现。您可以使用显式模板实例化,如下例所示:

在标题doit.h

template< typename T >
T addsome( T t );

体内doit.cpp

#include "doit.h"
// Add explicit template instantiations for the types you care
// #include <doit.h>
template<> 
int addsome<int>( int t ) {
return t+1;
}
template<> 
double addsome<double>( double t ) {
return t+2;
}

在main.cpp或您使用它的地方

int main() {
int res = addsome<int>( 1 ); // This will link against the compiled body doit.cpp
}