假如我們要用C語言實現下面的python腳本bird.py
import os
def fly(name):
print(name + " is flying.\n")
調用腳本main.py
import bird
bird.fly("fwd")
執行效果如下
> python main.py
fwd is flying.
實現相同邏輯的原始C代碼bird.c
#include <stdio.h>
void fly(const char *name)
{
printf("%s is flying.\n", name);
}
下面我們要將原始C代碼改造成可以被main.py的python模塊:
- 包含頭文件Python.h
- 添加C函數fly的Python調用版本bird_fly
- 添加向Python呈現C函數的方法表bird_methods
- 添加模塊初始化函數initbird(當動態庫被python解釋器搜索到時調用的函數)
#include <Python.h>
#include <stdio.h>
void fly(const char *name)
{
printf("%s is flying.\n", name);
}
static PyObject *bird_fly(PyObject *self, PyObject *args)
{
const char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
fly(name);
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef bird_methods[] = {
{ "fly", bird_fly, METH_VARARGS, "Bird fly" },
{ NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC initbird(void)
{
PyImport_AddModule("bird");
Py_InitModule("bird", bird_methods);
}
Linux下編譯
# yum install -y python-devel
# gcc -o bird.so `python-config --cflags` `python-config --libs` -shared bird.c
### 將main.py和bird.so放置在同一目錄下
# python main.py
fwd is flying.
Windows下編譯
VS2017(只需安裝python2.7的64位版本即可,本地開發工具可不裝)下創建空項目bird,然后添加源文件bird.cpp(內容同bird.c),項目配置如下:
Tab | 屬性 | 值 |
---|---|---|
常規 | 常規 > 目標名稱 | 將此字段設置為與 Python 看到的模塊名稱完全匹配。 |
常規 | 常規 > 目標擴展名 | .pyd |
常規 | 項目默認值 > 配置類型 | 動態庫(.dll) |
C/C++ > 常規 | 附加包含目錄 | 根據相應的安裝添加 Python include 文件夾,例如 C:\Python27amd64\include |
C/C++ > 預處理器 | 預處理器定義 | 在字符串的開頭添加 Py_LIMITED_API; ,可限制可從 Python 調用的某些函數,並使代碼在 Python 不同版本之間更易於移植。 |
C/C++ > 代碼生成 | 運行庫 | 多線程 DLL (/MD)(請參閱下面的“警告”) |
鏈接器 > 常規 | 附加庫目錄 | 根據相應的安裝添加包含 .lib 文件的 Python libs 文件夾,例如 C:\Python27amd64\libs 。 (務必指向包含 .lib 文件的 libs 文件夾,而非包含 .py 文件的 Lib 文件夾。) |
### 記住選擇release + x64編譯模式,否則編譯dll會報錯,然后將main.py和bird.pyd放置在同一目錄下
bird\x64\Release> python main.py
fwd is flying.