如何从 Python 中获取 Python 库的路径

How to get the path of the Python library from within Python

初始情况:

我有一个 C/C++ 库并为不同的目标语言提供绑定。其中一种语言是 Python。我决定使用 Swig,因为它为多种语言提供了良好的支持,并且它与 CMake 的集成非常简单。

为了提高 Python 绑定及其安装的可用性,我想提供一个 setup.py。这个想法是从 setup.py 文件中 运行 CMake,因为 CMake 包含如何正确创建绑定的所有逻辑。

我目前得到的:

我能够 运行 从 setup.py.

CMake 和构建 Python 绑定的目标

根据 Swig 的设计,CMake 文件需要区分 Python 2 和 Python 3。而 运行ning CMake 会检测 Python 安装的位置并配置环境。如果用户同时安装了 Python 2 和 Python 3(以及他们的开发包)CMake 总是需要 Python 3.

根据:https://cmake.org/cmake/help/v3.0/module/FindPythonLibs.html实际使用的Python版本可以通过设置PYTHON_LIBRARY和PYTHON_INCLUDE_DIR来指定。例如我必须 运行:

cmake -DPYTHON_INCLUDE_DIR=/usr/include/python2.7 -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so

问题是什么:

如果用户执行:

python setup.py build

可执行文件 'python' 的 Python 版本可能是 2,但 CMake 使用版本 3 构建绑定(见上文)。

根据Find python header path from within python?,我可以使用以下方法获取头文件的位置:

from distutils.sysconfig import get_python_inc
get_python_inc()

不幸的是,我不知道如何获取Python库的路径。 Distribution independent libpython path 提供的解决方案对我不起作用,因为它总是 returns '/usr/lib' 而不是 '/usr/lib/x86_64-linux-gnu/libpython2.7.so'

问题:

如何从 Python.

中获取 Python 库的位置(完整路径)

问题:

如何从 Python.

中获取 Python 库的位置(完整路径)

答案:

在 python 的 Makefile 中寻找 INSTALL_SHARED: https://github.com/python/cpython/blob/3.5/Makefile.pre.in

我们可以发现:

$(INSTALL_SHARED) libpython$(VERSION)$(SO) $(DESTDIR)$(LIBDIR)/$(INSTSONAME); \

我们可以看到查询信息没有单一变量。您需要从其他两个构建它:

from distutils.sysconfig import get_config_var
libpython = "%s/%s" % (get_config_var("LIBDIR"), get_config_var("INSTSONAME"))

在 python 2.7 中测试:

Python 2.7.13 (default, Nov 20 2017, 02:33:01)
[GCC 4.7.2 20121109 (Red Hat 4.7.2-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from distutils.sysconfig import get_config_var
>>> "%s/%s" % (get_config_var("LIBDIR"), get_config_var("INSTSONAME"))
'/usr/lib64/libpython2.7.so.1.0'

在 python 3.3 中测试:

Python 3.3.0 (default, Nov 11 2013, 09:56:47)
[GCC 4.7.2 20121109 (Red Hat 4.7.2-8)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from distutils.sysconfig import get_config_var
>>> "%s/%s" % (get_config_var("LIBDIR"), get_config_var("INSTSONAME"))
'/usr/lib64/libpython3.3m.so.1.0'

因此,正如您在 python Makefile 中看到的那样,它仅适用于 linux 中的 CPython (>=2.3),并且不能保证它会适用于未来,无论如何,自 2003 年 5 月 11 日以来,这在过去 14 年中没有改变。

您可以为 Windows 使用 BINDIR 和 DLLLIBRARY 变量,正如您从 Makefile 中看到的那样:

$(INSTALL_SHARED) libpython$(VERSION)$(SO) $(DESTDIR)$(BINDIR); \

但是,我无法在 Windows 中进行测试。

我通过变通方法自行解决了问题。也许它可以帮助其他面临相同或至少类似问题的人。

首先,我引入了环境变量PYTHON_INCLUDE_DIR和PYTHON_LIBRARY,它们与CMake中用于配置python路径的参数同名:-DPYTHON_INCLUDE_DIR 和 -DPYTHON_LIBRARY。此外,我将以下代码添加到我的 CMake 文件

if(DEFINED ENV{PYTHON_LIBRARY} AND DEFINED ENV{PYTHON_INCLUDE_DIR})
    message(STATUS "Using environment variables PYTHON_LIBRARY and PYTHON_INCLUDE_DIR")
    set(PYTHON_LIBRARY $ENV{PYTHON_LIBRARY})
    set(PYTHON_INCLUDE_DIR $ENV{PYTHON_INCLUDE_DIR})
endif()

这只是将环境变量包装到 CMake 参数中。现在用户可以定义这些变量而不是之前的参数 运行 CMake.

PYTHON_INCLUDE_DIR=/usr/include/python2.7 PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so cmake

由于我的setup.py只是调用CMake,CMake现在可以抓取环境变量并分别包装到参数中,用户也可以在运行之前配置变量setup.py(或 pip 等)。

PYTHON_INCLUDE_DIR=/usr/include/python2.7 PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so pip install tinyspline

老实说,用户还需要配置一些路径,但总算he/she可以了。

我对 Python 了解不多,而且我没能找到解决 Python 库的完整路径和名称的问题的好答案。所以我试图通过使用以下方法进行测试来提出解决方案:

  • CentOS 7 (Python 3.6)
  • Ubuntu 19.10 (Python 3.7)
  • Windows 10(Python 来自 Chocolatey 的 3.8)

我使用 CMake 的 find_package(Python3) 作为参考,这些是它在每个平台上找到的库:

  • CentOS:/usr/lib64/libpython3.6m.so
  • Ubuntu: /usr/lib/python3.7/config-3.7m-x86_64-linux-gnu/libpython3.7m.so
  • Windows: C:/Python38/libs/python38.lib

从那以后,我试图找出是否有配置变量的任何组合(如 distutils.sysconfig.get_config_vars() 所报告)可以给我找到 CMake 的那些路径和库名称。在我看来,不幸的是,没有一种方法可以在所有这些平台上移植地工作以获得完整的库路径。 我能得到的是这些组合似乎适用于每个平台:

  • CentOS: LIBDIR + LDLIBRARY
  • Ubuntu: LIBPL + LDLIBRARY
  • Windows: BINDIR + 硬编码 libs\python3.lib