简体   繁体   English

使用CMake的可移植Python C-API构建

[英]Portable Python C-API build with CMake

Let's consider the following trivial code for connecting C to python as follows 让我们考虑以下将C连接到python简单代码

// main.cpp

#include <Python.h>

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

The following CMake code works fine for 以下CMake代码适用于

CMakeLists.txt 的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})

The problem is when I move the code to another computer, the linking fails as I have python 3.6 there instead of 3.5 . 问题是当我将代码移到另一台计算机时,链接失败,因为我在那里有python 3.6而不是3.5 Thus I should replace every 3.5 with 3.6 . 因此,我应该将每3.53.6替换。 Is there any portable solution for linking python? 是否有用于链接python的任何便携式解决方案?

I have tried this instead of the lengthy line but it does not work: 我尝试了此方法,而不是冗长的代码,但它不起作用:

target_link_libraries(myapp ${PYTHON_LIBRARIES})

With the following message: 带有以下消息:

/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

Distributing standalone application dynamically linked against python 分发与python动态链接的独立应用程序

Generally speaking, since the API and ABI between minor version of python change, you would have to distribute one version of your executable for each python version you would like to support. 一般来说,由于python的次要版本之间的API和ABI发生了变化,因此您必须为要支持的每个python版本分发一个可执行文件版本。

For example, your different application could be named myapp-cpython-34m-linux_x86_64 , myapp-cpython-35m-linux_x86_64 , ... or myapp-py34m, ... 例如,您的其他应用程序可以命名为myapp-cpython-34m-linux_x86_64myapp-cpython-35m-linux_x86_64 ,...或myapp-py34m,...

The Stable Application Binary Interface 稳定的应用程序二进制接口

As described in Stable Application Binary Interface document, you could compile your program with Py_LIMITED_API definition (meaning only a subset of the API is used), that would allow you create a binary compatible with any version of python start with python 3.2. 稳定应用程序二进制接口文档中所述,您可以使用Py_LIMITED_API定义编译程序(意味着仅使用API​​的一个子集),这将允许您创建与从python 3.2开始的任何版本的python兼容的二进制文件。

That said, this only work well for cpython binary extension that are imported in the cpython interpreter. 也就是说,这仅适用于在cpython解释器中导入的cpython二进制扩展名。 Indeed, in that case the python symbols are already available. 确实,在那种情况下,python符号已经可用。

In your care, myapp would have to find any of the shared python 3.x library and I believe that is not supported by the operating system library loader. 在您的照料下, myapp必须找到任何共享的python 3.x库,并且我相信操作系统库加载程序不支持该库。

Possible solutions 可能的解决方案

  • Redistribute your own python shared library 重新分发自己的python共享库

  • Statically link against CPython library 静态链接到CPython库

Note that if your project uses a compiler different from the one officially associated with a given version of CPython, you could easily compile CPython itself using https://github.com/python-cmake-buildsystem/python-cmake-buildsystem 请注意,如果您的项目使用的编译器不同于与给定版本的CPython 正式关联的编译器,则可以使用https://github.com/python-cmake-buildsystem/python-cmake-buildsystem轻松地编译CPython本身。

Tweak and improvement to your project 调整和改进您的项目

Here is an improved version of your project specifying Usage requirements for the target. 这是项目的改进版本,指定了目标的使用要求

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
  )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM