【问题标题】:Portable Python C-API build with CMake使用 CMake 构建可移植 Python C-API
【发布时间】:2018-08-12 01:35:44
【问题描述】:

让我们考虑以下将 C 连接到 python 的简单代码,如下所示

// main.cpp

#include <Python.h>

int main()
{
    Py_Initialize();
    return 0;
}

以下 CMake 代码适用于

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.9)

project (myapp)

find_package(Threads)

set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(Python_ADDITIONAL_VERSIONS 3.5)
find_package(Threads REQUIRED)
find_package(PythonLibs REQUIRED)

include_directories(${PYTHON_INCLUDE_DIRS})

add_executable(myapp
    main.cpp
)

target_link_libraries(myapp rt)
target_link_libraries(myapp ${CMAKE_DL_LIBS})
target_link_libraries(myapp "-L/usr/lib/python3.5/config-3.6m-x86_64-linux-gnu -L/usr/lib -lpython3.5m -Bsymbolic-functions")
#target_link_libraries(myapp ${PYTHON_LIBRARIES})
target_link_libraries(myapp ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(myapp ${PYTHON_LIBRARIES})

问题是当我将代码移动到另一台计算机时,链接失败,因为我在那里有 python 3.6 而不是 3.5。因此,我应该用3.6 替换每个3.5。有没有链接python的便携解决方案?

我已经尝试过这个而不是冗长的行,但它不起作用:

target_link_libraries(myapp ${PYTHON_LIBRARIES})

带有以下信息:

/usr/local/lib/libpython3.5m.a(posixmodule.o): In function `os_forkpty_impl':
/usr/src/Python-3.5.2/./Modules/posixmodule.c:5972: undefined reference to `forkpty'
/usr/local/lib/libpython3.5m.a(posixmodule.o): In function `os_openpty_impl':
/usr/src/Python-3.5.2/./Modules/posixmodule.c:5878: undefined reference to `openpty'
/usr/local/lib/libpython3.5m.a(dynload_shlib.o): In function `_PyImport_FindSharedFuncptr':
/usr/src/Python-3.5.2/./Python/dynload_shlib.c:82: undefined reference to `dlsym'
/usr/src/Python-3.5.2/./Python/dynload_shlib.c:95: undefined reference to `dlopen'
/usr/src/Python-3.5.2/./Python/dynload_shlib.c:126: undefined reference to `dlsym'
/usr/src/Python-3.5.2/./Python/dynload_shlib.c:95: undefined reference to `dlopen'
/usr/src/Python-3.5.2/./Python/dynload_shlib.c:101: undefined reference to `dlerror'
collect2: error: ld returned 1 exit status
CMakeFiles/myapp.dir/build.make:96: recipe for target 'myapp' failed
make[2]: *** [myapp] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/myapp.dir/all' failed
make[1]: *** [CMakeFiles/myapp.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

【问题讨论】:

  • 变量Python_ADDITIONAL_VERSIONS 主要用于指定您使用的CMake 未知 版本的Python 版本。如果要指定最低版本,请将其设置为find_package() 的第二个参数:find_package(PythonLibs 3.5 REQUIRED)。至于您显示的错误消息,它们与非 python 符号有关:这些符号来自 dl 库和 utils 一个,它可能链接到 rtthreads。请注意,您应该在 python 之后链接这些库。
  • @Tsyvarev,我也通过target_link_libraries(myapp "-ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions") 明确地这样做了,但错误消息完全相同。
  • 有趣的是target_link_libraries(myapp "-lpython3.5m -Wl,-Bsymbolic-functions") 就足够了。

标签: c++ c cmake linker python-c-api


【解决方案1】:

分发独立应用程序动态链接到 python

一般来说,由于 Python 的次要版本之间的 API 和 ABI 发生了变化,因此您必须为每个想要支持的 Python 版本分发一个可执行版本。

例如,您的不同应用程序可以命名为myapp-cpython-34m-linux_x86_64myapp-cpython-35m-linux_x86_64、...或myapp-py34m、...

稳定的应用二进制接口

Stable Application Binary Interface 文档中所述,您可以使用Py_LIMITED_API 定义编译您的程序(意味着仅使用API​​ 的一个子集),这将允许您创建一个与python 3.2 开头的任何python 版本兼容的二进制文件.

也就是说,这只适用于在 cpython 解释器中导入的 cpython 二进制扩展。实际上,在这种情况下,python 符号已经可用。

在您的照顾下,myapp 必须找到任何共享的 python 3.x 库,我相信操作系统库加载器不支持。

可能的解决方案

  • 重新分发你自己的python共享库

  • 静态链接到 CPython 库

请注意,如果您的项目使用不同于officially associated 的编译器和给定版本的CPython,您可以使用https://github.com/python-cmake-buildsystem/python-cmake-buildsystem 轻松编译CPython 本身

调整和改进您的项目

这是您项目的改进版本,为目标指定了Usage requirements

cmake_minimum_required(VERSION 3.12)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(myapp)

# dependencies
set(Python_ADDITIONAL_VERSIONS 3.5)
find_package(PythonLibs REQUIRED)
find_package(Threads REQUIRED)

# executable
add_executable(myapp
  main.cpp
  )
target_compile_definitions(myapp
  PRIVATE
    Py_LIMITED_API
  )
target_include_directories(myapp
  PRIVATE
    ${PYTHON_INCLUDE_DIRS}
  )
target_link_libraries(myapp
  PRIVATE
    ${CMAKE_DL_LIBS}
    Threads::Threads
    ${PYTHON_LIBRARIES}
    rt
  )

【讨论】:

    猜你喜欢
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多