如何创建可执行文件并跨目录链接自定义的pybind11模块
问题原因
pybind11_add_module 生成的目标默认是为Python导入场景优化的,会自动开启符号隐藏、添加Python模块特有的文件名前缀/后缀、限制导出符号范围,因此原生可执行文件直接链接该目标会找不到自定义函数。此外你尝试链接的pybind11::module只是pybind11提供的接口依赖库,本身不包含你在test_pybind11.cpp中实现的业务代码,因此也无法找到对应符号。
最优实现方案
使用CMake对象库作为中间层,仅编译一次test_pybind11.cpp,产物同时供pybind11模块、测试可执行文件、大型应用复用,不需要重复添加源文件,也不需要冗余编译:
- 定义公共对象库
# 定义对象库,仅编译test_pybind11.cpp一次,编译产物供所有下游目标复用 add_library(test_pybind11_obj OBJECT test_pybind11.cpp) # 为对象库添加pybind11头文件依赖 target_link_libraries(test_pybind11_obj PUBLIC pybind11::pybind11) # 配置符号可见性,确保large_app可以调用到cpp中定义的函数 set_target_properties(test_pybind11_obj PROPERTIES CXX_VISIBILITY_PRESET default VISIBILITY_INLINES_HIDDEN OFF )
- 复用对象库生成原有测试目标和pybind11模块
# 原有测试可执行文件 add_executable(test_pybind11) target_link_libraries(test_pybind11 PRIVATE test_pybind11_obj pybind11::embed) # 原有pybind11模块,无需重复编译源文件 pybind11_add_module(test_pybind11_module SHARED) target_link_libraries(test_pybind11_module PRIVATE test_pybind11_obj)
- 大型应用直接链接对象库即可
add_executable(large_app ${LARGE_APP_SOURCES}) target_link_libraries(large_app PRIVATE test_pybind11_obj pybind11::embed ${LARGE_APP_LIBS})
注意事项
test_pybind11.cpp中需要被large_app调用的函数不要声明为static,否则会被限制为编译单元内可见,外部无法链接- Windows平台如果出现符号找不到问题,可以在项目根CMakeLists开头添加
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON),或者给需要导出的函数手动添加__declspec(dllexport)声明 - 如果确实需要直接链接
test_pybind11_module共享库,可以在生成模块时添加NO_EXTRAS参数关闭pybind11的默认模块适配规则:pybind11_add_module(test_pybind11_module SHARED NO_EXTRAS test_pybind11.cpp),配置符号可见性后即可直接链接,但该方案会引入额外的共享库依赖,执行效率和部署便捷性不如对象库方案。
内容的提问来源于stack exchange,提问作者Binu
相关产品推荐
相关产品推荐

