1. 程式人生 > >Windows C++中嵌入Python指令碼含import numpy等庫出現問題

Windows C++中嵌入Python指令碼含import numpy等庫出現問題

C++呼叫Python指令碼

問題

在C++中呼叫Python指令碼如果使用第三方庫,如import numpy/ PIL/ scipy/ opencv/ PIL/ matplotlib等這些庫檔案時可能就會出現如下圖所示錯誤:
import numpy

import numpy error

在VS中使用64位debug版,而且是debug版有問題,而release版沒有問題(後來發現的release版可以正常執行)如果release版也有類似問題,那麼我的方法估計不會奏效了。

現有方法

然後在國內的論壇和部落格中搜了很多,但是發現只有幾個提問,回答也不好,到國外的論壇網站搜尋,有很多這樣類似的問題,但是能正面回答的不是很多(有一些可能是我的水平低,沒有懂)。最終也沒有找到合適的解決方法,這個問題困擾了我大概一週的時間啊。

問題分析

最後,通過在不同環境嘗試,無意發現release可以執行,而debug版不可以,那麼可能的原因就是debug版的python直譯器會對python指令碼中包含的一些模組包解析,這個在嵌入python這個問題中是多此一舉的。所以debug版並不需要將指令碼解析,那麼就將C++專案中即使是debug版呼叫的python直譯器也使用release版的。

最終整體解決方案

1. 修改檔名

在Python的安裝目錄:\libs資料夾下,將python36.lib改為python36_d.lib,從而替換掉原有的debug版。我的Python版本是3.6.2,有些版本下好像沒有debug版lib檔案,我已經不記得是不是自帶的debug版lib檔案,具體版本號為 v3.6.2:5fd33b5,

但如果只是將檔名修改,也會在VS中產生–連結–錯誤:
修改python36_d.lib後產生的錯誤

2. 修改python/C API配置檔案

產生這個錯誤,主要是因為python/C API配置檔案中的Py_DEBUG/Py_TRACE_REFS引起, 修改目錄:\include下的pyconfig.h和object.h檔案:

  • 在pyconfig.h檔案中:
    原始碼:
#           if defined(_DEBUG)
#               pragma comment(lib,"python36_d.lib")
#           elif defined(Py_LIMITED_API)
# pragma comment(lib,"python3.lib") # else # pragma comment(lib,"python36.lib") # endif /* _DEBUG */
修改為:
#           if defined(_DEBUG)
#               pragma comment(lib,"python36.lib")
#           elif defined(Py_LIMITED_API)
#               pragma comment(lib,"python3.lib")
#           else
#               pragma comment(lib,"python36.lib")
#           endif /* _DEBUG */
  • 在pyconfig.h檔案中:
    原始碼:
#ifdef _DEBUG
#   define Py_DEBUG
#endif
修改為:
#ifdef _DEBUG
//# define Py_DEBUG
#endif
  • 在object.h檔案中:
    原始碼:
/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif
修改為:
/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
//#define Py_TRACE_REFS
#endif

後記:
去掉Py_DEBUG後可能會面臨一些檢查問題,比如去掉Py_Debug後就不會執行以下檢查:
* Extra checks are added to the object allocator.
* Extra checks are added to the parser and compiler.
* Downcasts from wide types to narrow types are checked for loss of information.
* A number of assertions are added to the dictionary and set implementations. In addition, the set object acquires a test_c_api() method.
* Sanity checks of the input arguments are added to frame creation.
* The storage for long ints is initialized with a known invalid pattern to catch reference to uninitialized digits.
* Low-level tracing and extra exception checking are added to the runtime virtual machine.
* Extra checks are added to the memory arena implementation.
* Extra debugging is added to the thread module.