如何构建和分发依赖于第三方libFoo.s的Python/Cython包

2024-10-02 10:25:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经编写了一个依赖于一些C扩展的Python模块。这些C扩展又依赖于几个已编译的C库。我希望能够将这个模块与所有依赖项捆绑在一起。在

我已经给出了一个最小的例子(it can be found on GitHub in its entirety)。在

目录结构为:

$ tree .
.
├── README.md
├── poc
│   ├── __init__.py
│   ├── cython_extensions
│   │   ├── __init__.py
│   │   ├── cvRoberts_dns.c
│   │   ├── cvRoberts_dns.h
│   │   ├── helloworld.c
│   │   ├── helloworld.pxd
│   │   ├── helloworld.pyx
│   │   ├── test.c
│   │   └── test.h
│   ├── do_stuff.c
│   └── do_stuff.pyx
└── setup.py

在设置.py根据必要的库生成扩展和链接(在本例中为libsundials_cvodelibsundials_nvectorserial):

^{pr2}$

这一切都很好,但它确实要求最终用户首先安装sundanials(在实际情况中,还需要其他几个非常挑剔的库来启动和运行)。在

理想情况下,我希望能够只在开发机器上设置它,创建包含适当的共享库的发行版,并发布某种捆绑包。在

给出了各种各样的教程,例子和我到目前为止找到的帖子。我被引导相信我在正确的轨道上。不过,还有一些最后的步骤我并不是在摸索。在

感谢任何帮助:-)。在


Tags: 模块pytestinitdns情况itdo
3条回答

为了增强mhsmith的优秀answer,下面是使用delocate在MacOS上执行的步骤:

  1. 安装sundials,例如使用自制程序:

    $ brew install sundials
    
  2. 生成包:

    $ python setup.py bdist_wheel
    
  3. auditwheel show/auditwheel repair的挂件是delocate-listdeps/delocate-wheel,因此首先分析生成的wheel文件:

    ^{3美元
  4. 固定车轮锉刀:

    $ delocate-wheel -v -w dist_fixed dist/poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl 
    Fixing: dist/poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl
    Copied to package .dylibs directory:
      /usr/local/Cellar/sundials/2.7.0_3/lib/libsundials_cvodes.2.9.0.dylib
      /usr/local/Cellar/sundials/2.7.0_3/lib/libsundials_nvecserial.2.7.0.dylib
    

dist_fixed目录中,您将拥有捆绑的轮子。您会注意到尺寸差异:

$ ls -l dist/ dist_fixed/
dist/:
total 72
-rw-r r   1 hoefling  wheel  36030 10 Nov 20:25 poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl

dist_fixed/:
total 240
-rw-r r   1 hoefling  wheel  120101 10 Nov 20:34 poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl

如果您列出了捆绑式控制盘的dep,您将注意到所需的库现在已绑定(由前缀@loader_path表示):

$ delocate-listdeps  all dist_fixed/poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl 
/usr/lib/libSystem.B.dylib
@loader_path/../.dylibs/libsundials_cvodes.2.9.0.dylib
@loader_path/../.dylibs/libsundials_nvecserial.2.7.0.dylib

安装捆绑式控制盘(请注意,捆绑式lib已正确安装):

$ pip install dist_fixed/poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl 
Processing ./dist_fixed/poc-0.0.0-cp27-cp27m-macosx_10_13_intel.whl
Installing collected packages: poc
Successfully installed poc-0.0.0
$ pip show -f poc
Name: poc
Version: 0.0.0
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: UNKNOWN
Location: /Users/hoefling/.virtualenvs/stackoverflow-py27/lib/python2.7/site-packages
Requires: 
Files:
  poc-0.0.0.dist-info/DESCRIPTION.rst
  poc-0.0.0.dist-info/INSTALLER
  poc-0.0.0.dist-info/METADATA
  poc-0.0.0.dist-info/RECORD
  poc-0.0.0.dist-info/WHEEL
  poc-0.0.0.dist-info/metadata.json
  poc-0.0.0.dist-info/top_level.txt
  poc/.dylibs/libsundials_cvodes.2.9.0.dylib
  poc/.dylibs/libsundials_nvecserial.2.7.0.dylib
  poc/__init__.py
  poc/__init__.pyc
  poc/cython_extensions/__init__.py
  poc/cython_extensions/__init__.pyc
  poc/cython_extensions/helloworld.so
  poc/do_stuff.so

我建议采取完全不同的方法。设置Linux包管理基础设施。在Ubuntu/Debian上,这可以用reprepro完成。https://wiki.ubuntuusers.de/reprepro/可能是一个开始,但还有更多的教程可用。然后,您可以构建自己的Linux包,将库和所有必需的文件与Python应用程序一起分发。在

这将是一个非常干净和方便的方法为您的客户。尤其是关于更新。(您甚至可以根据需要同时处理不同的操作系统版本。)

一如往常,干净的方法是有代价的。这种干净的方法需要您付出相当大的努力才能实现。你不仅需要设置一个服务器-这是比较容易的部分-而且要学习如何构建包-这并不困难,但你需要阅读一点如何做到这一点,并做大量的实验,最终得到完全符合你想要的包。不过,一切都会是你想要的。将来的更新对你和你的客户机来说都很容易。在

如果您希望在将来简化更新,希望了解Linux,并且将来可能需要自己的软件包,我建议您使用这种方法。或者大量的客户。在


这是一个非常“高层次”的方法。相比之下,非常“低水平”的方法是:

  • 启动程序时检查库是否存在
  • 如果不存在:终止应用程序。打印一个文本,该文本引用如何安装必需的库的脚本。这甚至可以是下载脚本的网址,例如:

bash <(curl -s http://mywebsite.com/myscript.txt)

如您所知,使用编译组件分发Python模块的推荐方法是使用wheel format。似乎没有任何标准的跨平台方式将第三方本机库捆绑到一个轮子中。但是,有一些特定于平台的工具可用于此目的。在

在Linux上,使用auditwheel

^{}修改现有的LinuxWheel文件,以添加基本“manylinux”标准中未包含的任何第三方库。下面是如何在Ubuntu 17.10干净安装的项目中使用它的演练:

首先,安装基本的Python开发工具和第三方库及其头:

root@ubuntu-17:~# apt-get install cython python-pip unzip
root@ubuntu-17:~# apt-get install libsundials-serial-dev

然后将项目构建到控制盘文件中:

^{pr2}$

现在可以在本地安装和测试wheel文件:

root@ubuntu-17:~/cython-example/dist# pip install poc-0.0.0-cp27-cp27mu-linux_x86_64.whl
[...]
root@ubuntu-17:~/cython-example/dist# python -c "from poc.do_stuff import hello; hello()"
hello cython
0.841470984808
trying to load the sundials program

3-species kinetics problem

At t = 2.6391e-01      y =  9.899653e-01    3.470564e-05    1.000000e-02
    rootsfound[] =   0   1
At t = 4.0000e-01      y =  9.851641e-01    3.386242e-05    1.480205e-02
[...]

现在我们安装auditwheel工具。它需要Python3,但它能够处理Python2或3的轮子。在

root@ubuntu-17:~/cython-example/dist# apt-get install python3-pip
root@ubuntu-17:~/cython-example/dist# pip3 install auditwheel

auditwheel使用另一个名为patchelf的工具来完成它的工作。不幸的是,ubuntu17.10中包含的patchelf版本丢失了a bugfix,没有了{a5}。所以我们必须从源代码构建它(脚本取自the manylinux Docker image):

root@ubuntu-17:~# apt-get install autoconf
root@ubuntu-17:~# PATCHELF_VERSION=6bfcafbba8d89e44f9ac9582493b4f27d9d8c369
root@ubuntu-17:~# curl -sL -o patchelf.tar.gz https://github.com/NixOS/patchelf/archive/$PATCHELF_VERSION.tar.gz
root@ubuntu-17:~# tar -xzf patchelf.tar.gz
root@ubuntu-17:~# (cd patchelf-$PATCHELF_VERSION && ./bootstrap.sh && ./configure && make && make install)

现在,我们可以检查wheel需要哪些第三方库:

root@ubuntu-17:~/cython-example/dist# auditwheel show poc-0.0.0-cp27-cp27mu-linux_x86_64.whl

poc-0.0.0-cp27-cp27mu-linux_x86_64.whl is consistent with the
following platform tag: "linux_x86_64".

The wheel references external versioned symbols in these system-
provided shared libraries: libc.so.6 with versions {'GLIBC_2.4',
'GLIBC_2.2.5', 'GLIBC_2.3.4'}

The following external shared libraries are required by the wheel:
{
    "libblas.so.3": "/usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1",
    "libc.so.6": "/lib/x86_64-linux-gnu/libc-2.26.so",
    "libgcc_s.so.1": "/lib/x86_64-linux-gnu/libgcc_s.so.1",
    "libgfortran.so.4": "/usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0",
    "liblapack.so.3": "/usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1",
    "libm.so.6": "/lib/x86_64-linux-gnu/libm-2.26.so",
    "libpthread.so.0": "/lib/x86_64-linux-gnu/libpthread-2.26.so",
    "libquadmath.so.0": "/usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0",
    "libsundials_cvodes.so.2": "/usr/lib/libsundials_cvodes.so.2.0.0",
    "libsundials_nvecserial.so.0": "/usr/lib/libsundials_nvecserial.so.0.0.2"
}

In order to achieve the tag platform tag "manylinux1_x86_64" the
following shared library dependencies will need to be eliminated:

libblas.so.3, libgfortran.so.4, liblapack.so.3, libquadmath.so.0,
libsundials_cvodes.so.2, libsundials_nvecserial.so.0

并创建一个新的轮子来捆绑它们:

root@ubuntu-17:~/cython-example/dist# auditwheel repair poc-0.0.0-cp27-cp27mu-linux_x86_64.whl
Repairing poc-0.0.0-cp27-cp27mu-linux_x86_64.whl
Grafting: /usr/lib/libsundials_nvecserial.so.0.0.2 -> poc/.libs/libsundials_nvecserial-42b4120e.so.0.0.2
Grafting: /usr/lib/libsundials_cvodes.so.2.0.0 -> poc/.libs/libsundials_cvodes-50fde5ee.so.2.0.0
Grafting: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1 -> poc/.libs/liblapack-549933c4.so.3.7.1
Grafting: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1 -> poc/.libs/libblas-52fa99c8.so.3.7.1
Grafting: /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0 -> poc/.libs/libgfortran-2df4b07d.so.4.0.0
Grafting: /usr/lib/x86_64-linux-gnu/libquadmath.so.0.0.0 -> poc/.libs/libquadmath-0d7c3070.so.0.0.0
Setting RPATH: poc/cython_extensions/helloworld.so to "$ORIGIN/../.libs"
Previous filename tags: linux_x86_64
New filename tags: manylinux1_x86_64
Previous WHEEL info tags: cp27-cp27mu-linux_x86_64
New WHEEL info tags: cp27-cp27mu-manylinux1_x86_64

Fixed-up wheel written to /root/cython-example/dist/wheelhouse/poc-0.0.0-cp27-cp27mu-manylinux1_x86_64.whl
root@ubuntu-17:~/cython-example/dist# unzip -l wheelhouse/poc-0.0.0-cp27-cp27mu-manylinux1_x86_64.whl
Archive:  wheelhouse/poc-0.0.0-cp27-cp27mu-manylinux1_x86_64.whl
  Length      Date    Time    Name
    -          -     
      167  2017-11-08 11:28   poc-0.0.0.dist-info/METADATA
        4  2017-11-08 11:28   poc-0.0.0.dist-info/top_level.txt
       10  2017-11-08 11:28   poc-0.0.0.dist-info/DESCRIPTION.rst
      211  2017-11-08 11:28   poc-0.0.0.dist-info/metadata.json
     1400  2017-11-08 12:08   poc-0.0.0.dist-info/RECORD
      110  2017-11-08 12:08   poc-0.0.0.dist-info/WHEEL
    62440  2017-11-08 11:28   poc/do_stuff.so
        2  2017-11-08 11:28   poc/__init__.py
   131712  2017-11-08 12:08   poc/cython_extensions/helloworld.so
        2  2017-11-08 11:28   poc/cython_extensions/__init__.py
   230744  2017-11-08 12:08   poc/.libs/libsundials_cvodes-50fde5ee.so.2.0.0
  7005072  2017-11-08 12:08   poc/.libs/liblapack-549933c4.so.3.7.1
   264024  2017-11-08 12:08   poc/.libs/libquadmath-0d7c3070.so.0.0.0
  2039960  2017-11-08 12:08   poc/.libs/libgfortran-2df4b07d.so.4.0.0
    17736  2017-11-08 12:08   poc/.libs/libsundials_nvecserial-42b4120e.so.0.0.2
   452432  2017-11-08 12:08   poc/.libs/libblas-52fa99c8.so.3.7.1
    -                        -
 10206026                     16 files

如果卸载第三方库,以前安装的控制盘将停止工作:

root@ubuntu-17:~/cython-example/dist# apt-get remove libsundials-serial-dev && apt-get autoremove
[...]
root@ubuntu-17:~/cython-example/dist# python -c "from poc.do_stuff import hello; hello()"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "poc/do_stuff.pyx", line 1, in init poc.do_stuff
ImportError: libsundials_cvodes.so.2: cannot open shared object file: No such file or directory

但是,带有捆绑库的轮子可以正常工作:

root@ubuntu-17:~/cython-example/dist# pip uninstall poc
[...]
root@ubuntu-17:~/cython-example/dist# pip install wheelhouse/poc-0.0.0-cp27-cp27mu-manylinux1_x86_64.whl
[...]
root@ubuntu-17:~/cython-example/dist# python -c "from poc.do_stuff import hello; hello()"
hello cython
0.841470984808
trying to load the sundials program

3-species kinetics problem

At t = 2.6391e-01      y =  9.899653e-01    3.470564e-05    1.000000e-02
    rootsfound[] =   0   1
At t = 4.0000e-01      y =  9.851641e-01    3.386242e-05    1.480205e-02
[...]

在OSX上,使用delocate

OSX的^{}显然与auditwheel非常相似。不幸的是,我没有一台OSX机器来提供演练。在

组合示例:

一个同时使用这两种工具的项目是SciPy。This repository,尽管它的名字,包含了所有平台的官方SciPy构建过程,而不仅仅是Mac。具体来说,将Linux build script(使用auditwheel)与{a10}(使用delocate)进行比较。在

要查看此过程的结果,您可能需要下载并解压一些SciPy wheels from PyPI。例如,scipy-1.0.0-cp27-cp27m-manylinux1_x86_64.whl包含以下内容:

 38513408  2017-10-25 06:02   scipy/.libs/libopenblasp-r0-39a31c03.2.18.so
  1023960  2017-10-25 06:02   scipy/.libs/libgfortran-ed201abd.so.3.0.0

scipy-1.0.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl包含以下内容:

   273072  2017-10-25 07:03   scipy/.dylibs/libgcc_s.1.dylib
  1550456  2017-10-25 07:03   scipy/.dylibs/libgfortran.3.dylib
   279932  2017-10-25 07:03   scipy/.dylibs/libquadmath.0.dylib

相关问题 更多 >

    热门问题