1. 程式人生 > >C++編寫Python模組----相關設定

C++編寫Python模組----相關設定

 

參考:

建立適用於 Python 的 C++ 擴充套件

https://docs.microsoft.com/zh-cn/visualstudio/python/working-with-c-cpp-python-in-visual-studio?view=vs-2017

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匯入模組會失敗;

*/