2014-05-13 58 views
0

方法映射表是PyMethodDef結構的數組,訪問方法在該方法中映射表不暴露與ctypes的

struct PyMethodDef { 
    char *ml_name; 
    PyCFunction ml_meth; 
    int ml_flags; 
    char *ml_doc; 
}; 

其中ml_name是在解釋器訪問的功能的名稱(即,GC .collect()),ml_meth是上一節中所描述的功能,ml_flags的指示哪個ml_meth使用簽名和ml_doc的是該函數的文檔字符串的地址。

現在,假設我想從gcm接口沒有公開的gcmodule.c中訪問gc_list_append。

我已經試過如下:

pythonapi.PyImport_ImportModule("gcmodule") 

pythonapi.PyImport_ImportModule(ctypes.c_wchar("gcmodule")) 

希望參考返回可用於訪問未曝光的方法,但在這兩種情況下,我得到的錯誤:

ImportError: No module named 'g' 

TypeError: one character unicode string expected 

任何想法如何通過ctypes/pythonapi訪問未暴露的函數或數據結構?

+0

也許'gc_list_append'是一個隨機的例子,但至少從2.4開始沒有使用。 – eryksun

回答

1

PyImport_ImportModule導入一個由const char *參數命名的模塊。它調用PyImport_Import,這又稱爲PY2中的__builtin__.__import__。如果它與C字符串"gc"一起調用,則返回對sys.modules['gc']的引用(如果存在),否則解釋程序通過調用initgc創建模塊,它在_PyImport_Inittab中找到。 gc模塊的初始化函數調用Py_InitModule4,該函數在GcMethods表上循環以向模塊dict添加方法。

您在gcmodule.c中看到的標記爲static的每個全局定義僅在系統級編譯單元中可見,即它沒有外部鏈接。通常,擴展模塊只導出PyMODINIT_FUNC的名稱,但CPython中的一些內置模塊也會導出公共API,如PyObject_GC_Track

在Windows上,通過名稱或序號從DLL導出符號需要額外的步驟,在.def文件中或使用修飾符__declspec(dllexport)進行聲明。在通過宏PyAPI_FUNC(pyport.h),PyAPI_DATAPyMODINIT_FUNC應用的CPython中。例如,objimpl.h聲明PyAPI_FUNC(void) PyObject_GC_Track(void *)

聲明符號static是命名空間管理。但是,如果您可以以某種方式獲取某個函數的地址,則可以使用ctypes函數指針來調用它。尋找地址是問題。 ctypes使用標準的POSIX dlsym和Windows GetProcAddress函數來查找導出的符號,這對你不會有幫助。由於id返回對象基地址,因此您可以訪問由CPython對象直接或間接引用的函數指針。


以下與您的問題沒有直接關係,但我將它列入了一般興趣。

在加載擴展模塊的POSIX系統上使用dlopen,可以指定RTLD_GLOBAL將動態符號合併到全局名稱空間中。例如,_ctypes擴展模塊從多個目標文件鏈接並需要幾個extern符號,如PyCData_set。您可以(例如,通過ctypes.pythonapi)調整進口有PyCData_set訪問全球:

>>> import sys, DLFCN 
>>> sys.setdlopenflags(DLFCN.RTLD_GLOBAL | DLFCN.RTLD_NOW) 
>>> import ctypes 
>>> hasattr(ctypes.pythonapi, 'PyCData_set') 
True 

當然,這不會在Windows上運行。擴展模塊生成C API的正確方法是使用PyCapsule,如datetime.datetime_CAPI(datetimemodule.c)。

+0

但是gcmodule.c沒有PyCapsule ... – user228137

+0

那麼沒有辦法通過ctypes或Python中的任何其他相關模塊訪問它們? – user228137