使用 SWIG 为 python2 和 python3 创建一个模块

Posted

技术标签:

【中文标题】使用 SWIG 为 python2 和 python3 创建一个模块【英文标题】:Creating a module for python2 and python3 with SWIG 【发布时间】:2017-05-10 11:30:05 【问题描述】:

我有一个任务,我必须为现有的 C++ 库编写 Python 绑定。由于 SWIG 不仅支持 Python,还支持 Java 和 Perl 等语言,所以我使用的是 SWIG。我在 SWIG 中相对较新,所以我有疑问。我希望我的 python 库在 Python 2.7 和 Python 3.x 下是可支持的。但我不知道如何做到这一点。所以如果有人可以建议我。任何帮助,将不胜感激。如果您愿意,可以向我询问更多详细信息。

到目前为止我已经尝试过什么。

这是我的代码文件。

/* example.c file */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int my_mod(int n, int m) 
      return n % m;


int sieve(int number) 
    int* arr = malloc(sizeof (int) * (number + 10));
    int* prime = malloc(sizeof (int) * (number + 10));
    /* printf("Size of arr: %lu", sizeof(arr));
      printf("Size of int: %lu", sizeof(int)); */
    memset(arr, 0, sizeof(int) * (number + 10));
    int counter = 0;
    prime[counter++] = 2;
    arr[0] = arr[1] = 0;
    for (int i = 3; i * i <= number; i += 2) 
        if (!arr[i]) 
            for (int j = i + i; j < number; j += i) 
            arr[j] = 1;
        
    
  
  for (int i = 3; i < number; i += 2)
      if (!arr[i])
  prime[counter++] = i;
  // free(arr);
  // free(prime);
  return counter;

而我的接口文件是

/* example.i */
%module example
%
      #include "stdio.h"
      #include "stdlib.h"
      #include "string.h"
      extern int my_mod(int n, int m);
      extern int sieve(int number);
%

extern int my_mod(int n, int m);
extern int sieve(int number);

我的编译步骤

swig -python example.i
gcc -fpic -c example.c example_wrap.c $(pkg-config --cflags --libs python3)
gcc  -shared  example.o example_wrap.o -o _example.so

在上述编译格式中,模块在 python3 中工作正常,但在 python2 中失败,错误日志为

ImportError: ./_example.so: undefined symbol: PyUnicode_FromFormat

如果我使用下面的编译命令

swig -python example.i
gcc -fpic -c example.c example_wrap.c $(pkg-config --cflags --libs python2)
gcc  -shared  example.o example_wrap.o -o _example.so

模块正在使用 python2,但是当我尝试在 python3 中导入时,错误消息是

ImportError: /home/deepanshu/env/swig/env/src/deep/_example.so: undefined symbol: PyInstance_Type

我确定错误是因为$(pkg-config --cflags --libs pythonX) 我在 X 的位置指定版本,但我如何确保我的模块适用于两个 Python 版本?

我尝试了 swig 的 -py3 标志,但我无法使模块适用于具有上述指定标志的两个 Python 版本。

【问题讨论】:

您不能同时链接到 Python 2.7 和 Python 3.x。如果要同时支持这两个版本,则需要在生成的 Python 文件中执行并在 Python 版本上引入分支。 【参考方案1】:

C 扩展在 python3 和 python2 中的工作方式不同。此链接可以帮助您确定在 C 级别上需要做什么才能使库同时适用于 python 2 和 3(不使用 swig)。 http://python3porting.com/cextensions.html

使用 Swig,我要做的是使用 pip ***命名约定: https://packaging.python.org/tutorials/distributing-packages/#packaging-your-project

这样做,我会为 python3 打包库并使包遵循轮命名标准(“https://www.python.org/dev/peps/pep-0425/#id1”“py3-none-any”),然后为 Python2 制作库并使用相同的策略打包它(“py2-none-any”)。然后你可以将它上传到 Pypi,pip 就会知道它需要将 py2 用于 python2,将 py3 用于 python3。

【讨论】:

以上是关于使用 SWIG 为 python2 和 python3 创建一个模块的主要内容,如果未能解决你的问题,请参考以下文章

python和swig版本兼容性问题

在 Mac 上的 Python 2.7.3 中导入 .pyd(使用 SWIG 创建)

在 C++ 中使用 SWIG

使用 SWIG 将 C++ 文件包装为 Python 文件

通过 SWIG 将 Python 3 个字节输入到 C char*

pip 无法安装软件包,因为它找不到 swig2.0 二进制文件