C++編寫Python模組----相關設定
參考:
建立適用於 Python 的 C++ 擴充套件
Extending Python with C or C++
https://docs.python.org/2.7/extending/extending.html
專案屬性配置:
1.選擇release + x64編譯模式,否則編譯dll會報錯,(python 是64位)
2.如下表所述設定專案屬性
Tab | 屬性 | “值” |
---|---|---|
常規 | 常規 > 目標名稱 | 指定想要在 from...import 語句中從 Python 引用的模組的名稱。 定義 Python 的模組時,在 C++ 中使用相同的名稱。 如果想要將專案的名稱用作模組名稱,請保留預設值 $(ProjectName)。 |
常規 > 目標副檔名 | .pyd | |
專案預設值> 配置型別 | 動態庫(.dll) | |
C/C++> 常規 | 附加包含目錄 | 根據相應的安裝新增 Python“include” 資料夾,例如 c:\Python36\include 。 |
C/C++> 前處理器 | 前處理器定義 | 將 Py_LIMITED_API; 新增到字串(包括分號)的開頭。 此定義會限制可從 Python 呼叫的某些函式,並使程式碼在 Python 不同版本之間更易於移植。 |
C/C++> 程式碼生成 | 執行時庫 | 多執行緒 DLL (/MD)(請參閱下面的“警告”) |
連結器 > 常規 | 附加庫目錄 | 根據相應的安裝新增包含 .lib 檔案的 Python“libs”資料夾,例如 c:\Python36\libs 。 (務必指向包含 .lib 檔案的“libs”資料夾,而非包含 .py 檔案的 Lib 資料夾。) |
提示
如果在專案屬性中未看到 C/C++ 選項卡,這是因為專案不包含標識為 C/C++ 原始檔的任何檔案。 如果建立的原始檔不含 .c 或 .cpp 副檔名,則可能出現這種情況。 例如,如果之前在“新建項”對話方塊中不小心輸入了 module.coo
(而不是 module.cpp
),則 Visual Studio 會建立檔案,但不會將檔案型別設定為“C/C+ 程式碼”,而正是它啟用 C/C++ 屬性選項卡。即使將檔案重新命名為帶 .cpp
,此類識別錯誤仍會存在。 為了正確設定檔案型別,請在“解決方案資源管理器”中右鍵單擊檔案,選擇“屬性”,然後將“檔案型別”設定為“C/C++ 程式碼”。
警告
即使對於除錯配置,也始終將“C/C++” > “程式碼生成” > “執行時庫”選項設定為“多執行緒 DLL (/MD)”,因為此設定是生成非除錯 Python 二進位制檔案時使用的設定。 如果碰巧設定了“多執行緒除錯 DLL (/MDd)”選項,則生成除錯配置會產生錯誤“C1189: Py_LIMITED_API 與 Py_DEBUG、Py_TRACE_REFS 和 Py_REF_DEBUG 不相容”。 此外,如果刪除 Py_LIMITED_API
來避免出現生成錯誤,則在嘗試匯入模組時,Python 會崩潰。 (如下所述,崩潰將發生在 DLL 對 PyModule_Create
的呼叫中,並出現輸出訊息“嚴重 Python 錯誤: PyThreadState_Get: 無當前執行緒”。)
/MDd 選項用於生成 Python 除錯二進位制檔案(例如 python_d.exe),但對擴充套件 DLL 選擇此選項仍會導致 Py_LIMITED_API
的生成錯誤。
測試程式碼:
#include <Python.h>
//C++函式
int Add(int x, int y)
{
return x + y;
}
int Del(int x, int y)
{
return x - y;
}
//***********************************************************介面函式,以接受和返回 Python 型別
static PyObject* WrappAdd(PyObject* self, PyObject* args)
{
int x, y;
if (!PyArg_ParseTuple(args, "ii", &x, &y))
{
return NULL;
}
return Py_BuildValue("i", Add(x, y));
}
static PyObject* WrappDel(PyObject* self, PyObject* args)
{
int x, y;
if (!PyArg_ParseTuple(args, "ii", &x, &y))
{
return NULL;
}
return Py_BuildValue("i", Del(x, y));
}
//*************************************************************模組方法表,向 Python 呈現 C++ 中方法、函式的結構
static PyMethodDef py_module_methods[] = {
{ "Add", WrappAdd, METH_VARARGS, "Execute a shell command." },
{ "Del", WrappDel, METH_VARARGS, "Execute a shell command." },
{ NULL, NULL, 0, NULL } /* Sentinel */
};
//**************************************************************模組的初始化函式
//--- #define PyMODINIT_FUNC extern "C" __declspec(dllexport) void
// PyMODINIT_FUNC 為巨集定義,本身包含extern "C"
//extern "C"
PyMODINIT_FUNC initpy_module(void)
{
PyObject *m;
m = Py_InitModule("py_module", py_module_methods);
if (m == NULL)
return;
PyImport_AddModule("py_module");
}
/*
初始化函式的名稱必須是init+模組名。這個函式必須是non-static的。
如動態庫名字為py_module.pyd,則模組的初始化函式名必須是initpy_module,
且Py_InitModule()函式的第一個引數必須是“py_module”,否則Python匯入模組會失敗;
*/