Distutils 显然在使用(工作中的) SWIG 扩展时失败了。

8

我正在通过SWIG将一个C库封装到一个Python模块中,这里称为"myExample"。如果我进行编译:

$swig -python myExample.i
$gcc -c myExample_wrap.c -I /usr/lib/python2.7 -fPIC -std=c99
$ld -shared myExample_wrap.so -llapacke -o _myExample.so

我获得了一个完整的工作模块(某些函数需要liblapacke)。现在,我想通过“pip install”来安装这个模块。
根据distutils部分(https://docs.python.org/2.7/distutils/setupscript.html),我编写了我的setup.py文件:
from distutils.core import setup, Extension
setup(name='myExample',
version='0.1',
ext_modules=[Extension('_myExample',['myExample.i'], libraries= ['lapacke'])] )

我编辑了MANIFEST.in以保留源代码并避免类似网站上的问题(即只包含myExample.h和myExample.c)。然后我运行:

$python setup.py sdist

通过“pip install”获得可安装的软件包。看起来已经完成(没有错误,没有警告),但是...它起作用。在这个可安装模块(“_myExample.so” - 注意下划线,似乎distutils需要它[也许它隐藏了一个答案?])中,一些方法是不同的,一些缺失了,等等...因此,我决定一步一步地进行。只编译:
$python setup.py build_ext

我已经遇到了同样的问题:最终模块与开头解释中所述的传统编译得到的模块不同。
总结一下:给定一个SWIG接口,通过传统方式编译它或通过distutils编译都会产生不同的结果。这可能怎么可能?我的setup.py有问题吗?难道有其他方法可以获得一个可pip安装的模块,而不依赖于distutils或setuptools(它们产生相同的问题)?
附注:包装代码非常长,所以我不能详细列出,但如果需要,我完全可以添加更多信息。例如,手动编译的接口成功包含“AdaptiveInterpolation”(运行良好),而distutil生成的接口具有“AdaptiveInterpolation_set”、“AdaptiveInterpolation_get”,或者有很多以“new_”开头的方法(原始代码中不存在)。

我认为值得添加示例源代码,这样就可以在本地重现问题。 - Oleg Kuralenko
1个回答

3
实际上,分发这种软件包有两个选择: bdist_wheelsdist
让我们以 SWIG 的例子为例,来自 distutils文档

example.h

int fact(int n);

example.c

#include "example.h"

int fact(int n) {
    if (n == 0) {
        return 1;
    }
    else {
        return n * fact(n - 1);
    }
}

example.i

%module example

%{
#define SWIG_FILE_WITH_INIT
#include "example.h"
%}

int fact(int n);

让我们构建一个SWIG接口,默认情况下会生成example_wrap.c

swig -python example.i 

Wheel

Python Wheels 是一种现代的分发格式,简化了预构建软件包的分发(即软件包的用户不需要编译器、开发头文件等就可以安装它)。为了使用它,我们需要 setuptoolswheel(可以通过 pip 或从操作系统存储库安装,sudo apt-get install python-wheel python-setuptools)。

setup.py

from setuptools import setup, Extension


setup(
  name = 'example',
  version = '0.1',
  author = 'SWIG Docs',
  description = 'Simple swig example from docs',
  ext_modules = [
    Extension('_example', sources = ['example_wrap.c', 'example.c'])],
  py_modules = ['example'],
  package_data = {'': ['example.h']}  # needed for sdist
)

您可以使用以下代码构建轮子:
python setup.py bdist_wheel

在我的机器上,它生成了example-0.1-cp27-cp27mu-linux_x86_64.whl,我可以用pip安装并像这样测试:python -c 'import example; print(example.fact(5))'。注意文件名。它编码了兼容的Python版本,ABI和平台。以下是内容列表(unzip -l ...)。
Archive:  example-0.1-cp27-cp27mu-linux_x86_64.whl
  Length      Date    Time    Name
---------  ---------- -----   ----
     2609  2018-02-24 11:06   example.py
    70968  2018-02-24 13:31   _example.so
       10  2018-02-24 14:58   example-0.1.dist-info/DESCRIPTION.rst
      290  2018-02-24 14:58   example-0.1.dist-info/metadata.json
       17  2018-02-24 14:58   example-0.1.dist-info/top_level.txt
      105  2018-02-24 14:58   example-0.1.dist-info/WHEEL
      193  2018-02-24 14:58   example-0.1.dist-info/METADATA
      617  2018-02-24 14:58   example-0.1.dist-info/RECORD
---------                     -------
    74809                     8 files

为了构建更好兼容性的 wheels,您可以查看 manylinux 等内容。

来源

sdist 代表源代码分发,这意味着用户需要具备编译器和相关的开发依赖。源代码分发是通过以下方式构建的:

python setup.py sdist

生成的 example-0.1.tar.gz 包含以下内容 (tar -tf ...):

example-0.1/
example-0.1/example.c
example-0.1/PKG-INFO
example-0.1/example.egg-info/
example-0.1/example.egg-info/PKG-INFO
example-0.1/example.egg-info/dependency_links.txt
example-0.1/example.egg-info/top_level.txt
example-0.1/example.egg-info/SOURCES.txt
example-0.1/setup.cfg
example-0.1/example.py
example-0.1/setup.py
example-0.1/example_wrap.c
example-0.1/example.h

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