使用CMake查找Python的site-packages目录

19

我使用CMake来构建我的应用程序。如何找到Python site-packages目录的位置?我需要该路径以便编译Python扩展。

由于我计划在Linux、Mac和Windows上部署我的应用程序,因此CMake必须能够在这三个主要操作系统中找到该路径。

我尝试了以下方法:

include(FindPythonLibs)
find_path( PYTHON_SITE_PACKAGES site-packages ${PYTHON_INCLUDE_PATH}/.. )

不过那样并没有用。

我也可以通过运行以下命令获取路径

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

我知道如何在 shell 中执行这个命令,但是我该如何从 CMake 中调用它呢?

解决方法:

谢谢,Alex。 所以可以给出给我 site-package 目录的命令是:

execute_process ( COMMAND python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)

使用OUTPUT_STRIP_TRAILING_WHITESPACE命令可以去除末尾的换行符。


2
仅供参考:我发现了这个很棒的包:https://github.com/lyricat/Hotot/tree/master/cmake/modules - dashesy
2
对于使用Python 3.x的用户,print语句应该写成:print(get_python_lib()) - wesanyer
4个回答

10

我用于 lcm 的稍微更新的版本:

execute_process(
  COMMAND "${PYTHON_EXECUTABLE}" -c "if True:
    from distutils import sysconfig as sc
    print(sc.get_python_lib(prefix='', plat_specific=True))"
  OUTPUT_VARIABLE PYTHON_SITE
  OUTPUT_STRIP_TRAILING_WHITESPACE)

这将设置PYTHON_SITE为适当的前缀相对路径,可用于以下情况:

install(
  FILES ${mypackage_python_files}
  DESTINATION ${PYTHON_SITE}/mypackage)

(请不要安装到绝对路径!这样会绕过 CMAKE_INSTALL_PREFIX。)


1
if True: 的意义是什么?只是为了让你缩进剩下的两行代码吗? - kynan
1
确切地说:这样内联脚本就不会打破周围 CMake 代码的缩进。 - Matthew

8

自 CMake 3.12 版本起,您可以使用 FindPython 模块,该模块为无架构和特定库分别填充 Python_SITELIBPython_SITEARCH 变量。

示例:

find_package(Python ${PYTHON_VERSION} REQUIRED COMPONENTS Development)
Python_add_library(foo MODULE
    src/foo.cc src/python_interface.cc
)
install(TARGETS foo DESTINATION ${Python_SITEARCH}/foo)

2
问题在于,Python_SITEARCH / Python_SITELIB 等似乎是绝对路径,这使得它们无法用于 install(),因为它会破坏 CMAKE_INSTALL_PATH 的处理。 - FeRD
@FeRD 它只会半断,CMAKE_INSTALL_PATH 仍然被尊重,但整个“绝对”路径将被附加到它上面,例如 /builds/python-foo/debian/python3-foo/usr/lib/python3/dist-packages/foo/foo.so 理想的解决方案是根本不使用 CMake 进行安装,但这个解决方案对于 Debian 打包来说很好用。 - Erbureth
有趣。debhelper 是否可以使用 DESTDIR 而不是 CMAKE_INSTALL_PREFIXDESTDIR(作为 make 参数,例如 make install DESTDIR=/some/install/path将会添加前缀,即使是绝对路径。 - FeRD
@FeRD 我不确定,看起来它直接使用了 cmake。如果您能在此处找到一些内容,请查看匿名的构建日志:https://pastebin.com/TazFVxMZ - Erbureth
没错,代码的第168行就是:"dh_auto_install --buildsystem=cmake --builddirectory="/builds/python_foo/.pybuild/pythonX.Y_2.7/build" --destdir="/builds/python_foo/debian/python-foo""实际上,CMake设置从未使用CMAKE_INSTALL_PREFIX - FeRD
显示剩余2条评论

8

您可以使用execute_process在cmake中执行外部进程(如果需要,可以将输出获取到一个变量中,就像这里一样)。


4
这看起来像是一个黑客攻击。现在(六年后)还是这样做的方式吗? - Torsten Bronger
2
@TorstenBronger 为什么这是一个hack?CMake需要从某个地方获取信息,那为什么不直接询问谁最懂呢,比如Python? - kynan
就我而言,我使用CMake的意图是为了将这些东西抽象出来。 - Torsten Bronger
1
可能这是一个黑客行为,但现在它已经被正式地集成到CMake中了:“Python_SITELIB / 第三方平台无关的安装目录。/ 由distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)返回的信息。” - FeRD

1
我建议如果你将这个扩展作为动态库使用,可以使用get_python_lib(True)。第一个参数应该是true,如果你需要平台特定的位置(在64位Linux机器上,可能是/usr/lib64而不是/usr/lib)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接