毫无疑问,C 比 Python 更快,那么像 Numpy 这样的 Python 库是如何如此快速、高效地执行海量数据运算的呢?实际上,像 Numpy 这样的库并不是完全用 Python 编写的,相反,库的某些部分是用 C 编写的,这提供了性能上的提升。在用 C 编写代码后,我们将它们封装在 Python 代码中,这些代码充当了那些 C 代码的接口。然后我们可以使用 Python 语法调用 C 函数,实际的处理过程在后台由 C 完成,结果作为 Python 对象返回。在本文中,我们将看看如何在 Linux 系统上使用名为 SWIG 的软件为我们的 C 程序创建 Python 封装器。
什么是 SWIG
简而言之,SWIG 是一个编译器,它接收 C/C++ 声明并创建所需的包装器,以便从 Python、Tcl、Ruby 等其他语言访问这些声明。
它通常不需要更改现有代码,并能在极短的时间内创建一个接口。
创建封装器的原因
在许多情况下,我们需要封装器,以下是其中几种情况 –
- 为现有的 C 程序构建解释型接口。
- 为脚本语言构建高性能的 C 模块。
- 测试大型 C 程序是一件非常痛苦的事情,所以我们用 Python 等脚本语言编写封装器,因为在这些语言中编写测试非常容易。等等。
安装 SWIG
要直接从 apt 仓库下载 SWIG,请输入以下命令 –
sudo apt-get update
sudo apt-get install swig
使用 SWIG 编写封装器
让我们看看这段 C 代码,它包含两个函数和一个全局变量 –
C
CODEBLOCK_5ce6153d
这是我们的头文件 example.h –
C
CODEBLOCK_a3be7398
首先,我们必须创建一个 SWIG 接口文件。该文件包含 ANSI C 函数原型和变量声明。在这里 –
- %module 指令指定了我们将在 Python 中使用的模块名称。
- %{ .. %} 块提供了一个位置来插入额外的代码,例如 C 头文件或额外的 C 声明,到生成的包装代码中。
- %include 指令允许我们包含额外的文件,如头文件。
C
CODEBLOCK_efdbc370
现在我们将使用类似于 $ swig -targetlanguage interfacefile.i 的命令来创建包装代码
$ swig -python example.i
执行此命令后,将创建一个名为 “example_wrap.c” 的包装代码。此文件包含我们原始 C 代码的臃肿版本,其中包含各种错误处理代码等。还会生成另一个文件 “example.py”,这是我们将在 python 脚本中导入的模块。
在此之后,我们必须生成位置无关代码,这些代码将在共享库中使用,方法是使用以下命令编译 “example_wrap.c” 和 “example.c” –
$ gcc -c -fpic example_wrap.c example.c -I/use/include/python2.7
将 python2.7 替换为你的 Python 版本。这将生成两个目标文件
“example_wrap.o” 和 “example.o”。在上面的命令中 –
- -fpic 生成适合在共享库中使用的位置无关代码 (PIC),如果目标机器支持的话。此类代码通过全局偏移表 (GOT) 访问所有常量地址。
注意: 如果你遇到类似 "… ‘Python.h‘ file not found" 的错误,那么可能有以下原因 –
- 你可能没有 ‘Python.h‘ 文件,或者
- 你向编译器提供了 ‘Python.h‘ 文件的错误路径
要获取 ‘Python.h‘,你必须使用以下命令安装 Python-dev –
$ sudo apt-get install python-dev
要找到 ‘Python.h‘ 的正确路径,请执行以下命令 –
$ python-config --cflags
这将输出类似这样的内容 –
现在将编译命令中的路径替换为这个针对 python2.7 的路径,或者针对 Python 3.5 将版本更改为 python3.5。
现在,最后,我们必须将生成的目标文件链接在一起以创建一个共享对象,它类似于 Windows 中的 dll 文件。