简体   繁体   English

从 cmake 创建 python package (deb/rpm)

[英]Creating a python package (deb/rpm) from cmake

I am trying to create a python package (deb & rpm) from cmake , ideally using cpack .我正在尝试从cmake创建一个 python package (deb & rpm),最好使用cpack I did read我确实读过

The installation works just fine (using component install) for my shared library.对于我的共享库,安装工作正常(使用组件安装)。 However I cannot make sense of the documentation to install the python binding (glue) code.但是,我无法理解安装 python 绑定(胶水)代码的文档。 Using the standard cmake install mechanism, I tried:使用标准的 cmake 安装机制,我试过:

install(
  FILES __init__.py library.py
  DESTINATION ${ACME_PYTHON_PACKAGE_DIR}/project_name
  COMPONENT python)

And then using brute-force approach ended-up with:然后使用蛮力方法最终得到:

# debian based package (relative path)
set(ACME_PYTHON_PACKAGE_DIR lib/python3/dist-packages)

and

# rpm based package (full path required)
set(ACME_PYTHON_PACKAGE_DIR /var/lang/lib/python3.8/site-packages)

The above is derived from:以上来源于:

debian % python -c 'import site; print(site.getsitepackages())'
['/usr/local/lib/python3.9/dist-packages', '/usr/lib/python3/dist-packages', '/usr/lib/python3.9/dist-packages']

while:尽管:

rpm % python -c 'import site; print(site.getsitepackages())'
['/var/lang/lib/python3.8/site-packages']

It is pretty clear that the brute-force approach will not be portable, and is doomed to fail on the next release of python.很明显,蛮力方法将无法移植,并且在 python 的下一个版本中注定会失败。 The only possible solution that I can think of is generating a temporary setup.py python script (using setuptools ), that will do the install.我能想到的唯一可能的解决方案是生成一个临时setup.py python 脚本(使用setuptools ),它将进行安装。 Typically cmake would call the following process :通常cmake会调用以下过程

% python setup.py install --root ${ACME_PYTHON_INSTALL_ROOT}

My questions are:我的问题是:

  • Did I understand the cmake/cpack documentation correctly for python package?我是否正确理解了 python package 的 cmake/cpack 文档? If so this means I need to generate an intermediate setup.py script.如果是这样,这意味着我需要生成一个中间setup.py脚本。
  • I have been searching through the cmake/cpack codebase ( git grep setuptools ) but did not find helper functions to handle generation of setup.py and passing the result files back to cpack .我一直在搜索 cmake/cpack 代码库( git grep setuptools )但没有找到帮助函数来处理setup.py的生成并将结果文件传回cpack Is there an existing cmake module which I could re-use?是否有可以重复使用的现有cmake模块?

I did read, some alternative solution, such as:我确实阅读了一些替代解决方案,例如:

Which seems overly complex, and geared toward Debian-only based system.这似乎过于复杂,并且面向仅基于 Debian 的系统。 I need to handle RPM in my case.在我的情况下,我需要处理 RPM。

I am going to post the temporary solution I am using at the moment, until someone provide something more robust.我将发布我目前正在使用的临时解决方案,直到有人提供更强大的东西。

So I eventually manage to stumble upon:所以我最终设法偶然发现:

Re-using the above to do an install step instead of a build step can be done as follow:重新使用上述内容来执行install步骤而不是build步骤可以如下完成:

find_package(PythonInterp REQUIRED)

set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
set(SETUP_DEPS "${CMAKE_CURRENT_SOURCE_DIR}/project_name/__init__.py")
set(SETUP_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build-python")

configure_file(${SETUP_PY_IN} ${SETUP_PY})

add_custom_command(
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/setup_timestamp
  COMMAND ${PYTHON_EXECUTABLE} ARGS ${SETUP_PY} install --root ${SETUP_OUTPUT}
  COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/setup_timestamp
  DEPENDS ${SETUP_DEPS})

add_custom_target(target ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/setup_timestamp)

And then the ugly part is:然后丑陋的部分是:

install(
  # trailing slash is important:
  DIRECTORY ${SETUP_OUTPUT}/
  DESTINATION "/" # FIXME may cause issues with other cpack generators
  COMPONENT python)

Turns out that the documentation for install() is pretty clear about absolute paths :事实证明install()的文档对绝对路径非常清楚:

 DESTINATION [...] As absolute paths are not supported by cpack installer generators, it is preferable to use relative paths throughout.

For reference, here is my setup.py.in :作为参考,这是我的setup.py.in

from setuptools import setup

if __name__ == '__main__':
    setup(name='project_name_python',
          version='${PROJECT_VERSION}',
          package_dir={'': '${CMAKE_CURRENT_SOURCE_DIR}'},
          packages=['project_name'])

As mentionned in my other solution , the ugly part is dealing with absolute path in cmake install() commands.正如我在其他解决方案中提到的,丑陋的部分是在 cmake install()命令中处理绝对路径。 I was able to refactor the code to avoid usage of absolute path in install() .我能够重构代码以避免在install()中使用绝对路径。 I simply changed the installation into:我只是将安装更改为:

install(
  # trailing slash is important:
  DIRECTORY ${SETUP_OUTPUT}/
  # "." syntax is a reliable mechanism, see:
  # https://gitlab.kitware.com/cmake/cmake/-/issues/22616
  DESTINATION "."
  COMPONENT python)

And then one simply needs to:然后只需要:

set(CMAKE_INSTALL_PREFIX "/")
set(CPACK_PACKAGING_INSTALL_PREFIX "/")
include(CPack)

At this point all install path now need to include explicitely /usr since we've cleared the value for CMAKE_INSTALL_PREFIX .此时,所有安装路径现在都需要明确包含/usr ,因为我们已经清除了CMAKE_INSTALL_PREFIX的值。

The above has been tested for deb and rpm packages.以上已针对 deb 和 rpm 包进行了测试。 CPACK_BINARY_TGZ does properly run with the above solution: CPACK_BINARY_TGZ确实可以使用上述解决方案正常运行:

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

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