[英]access variable in so file and register callback function in ctypes
我正在嘗試從編譯的共享對象訪問在 cpp 頭文件中聲明的變量。 下面是我的情況
/cpp_header.hpp/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
//variables declaration
const uint8_t variable1 = 3;
const uint16_t variable2 = 4056;
const uint16_t variable3 = 3040;
typedef struct {
void* a;
uint32_t b
uint16_t w;
uint16_t h;
size_t p;
} structure1 ;
typedef struct {
uint32_t a;
uint32_t b
} structure2 ;
//callback function declaration
typedef void (*one_callback) (const structure1 *);
typedef void (*output_callback) (const structure1 *);
typedef void (*inpout_callback) (const structure2 *);
//APIs using the callback function
int start_api(enum_type, output_callback, inpout_callback);
我在 ctypes 中嘗試什么
/ctype_wrapper.py/
import ctypes
from ctypes import *
lib_instance = CDLL('test.so')
#accessing the variable declared in cpp header
variable1 = c_uint8.in_dll(lib_instance, 'variable1')
variable2 = c_uint16.in_dll(lib_instance, 'variable2')
variable3 = c_uint16.in_dll(lib_instance, 'variable2')
//registering callback function
ctype_start_api = lib_instance.start_api
ctype_start_api.argtypes = [enum_type, output_callback, inpout_callback] # register the callback
ctype_start_api.restype = c_int
錯誤輸出
#error for variable access
File "ctype_wrapper.py", line 6, in <module>
variable1 = c_uint8.in_dll(lib_instance, 'variable1')
ValueError: ./test.so: undefined symbol: variable1
對於回調寄存器,我參考了 ctypes 文檔,但不知道如何為我的場景實現它。
我的變量聲明在 header.hpp 文件中是否正確,或者我需要添加任何內容才能導出已編譯的 so 文件中的變量?
在標題更改中
const uint8_t variable1 = 3;
至
extern const uint8_t variable1;
並添加這個
extern const uint8_t variable1 = 3;
到 .cpp 文件
默認情況下const
變量在 C++ 中具有內部鏈接,因此不會從共享庫中導出。
必須導出變量和函數,以便ctypes
找到它們。 extern
在 Linux 上可能足以導出變量,但在 Windows 上,變量和函數都需要額外的__declspec(dllexport)
聲明。
ctypes
還期望導出的變量和函數是 C 鏈接,因此 C++ 變量和函數需要包裝在extern "C"
中。
這是一個在 Windows 上測試的工作示例,它還演示了回調:
測試.hpp
#include <stdint.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
typedef struct {
void* a;
uint32_t b;
uint16_t w;
uint16_t h;
size_t p;
} structure1;
typedef struct {
uint32_t a;
uint32_t b;
} structure2;
typedef void (*output_callback) (const structure1 *);
typedef void (*inpout_callback) (const structure2 *);
extern "C" {
API extern const uint8_t variable1;
API extern const uint16_t variable2;
API extern const uint16_t variable3;
API int start_api(output_callback, inpout_callback);
}
測試.cpp
#include "test.hpp"
extern "C" {
const uint8_t variable1 = 3;
const uint16_t variable2 = 4056;
const uint16_t variable3 = 3040;
int start_api(output_callback ocb, inpout_callback iocb) {
structure1 s1 { nullptr, 1, 2, 3, 4 };
structure2 s2 { 5, 6 };
if(ocb)
ocb(&s1);
if(iocb)
iocb(&s2);
return 0;
}
}
測試.py
import ctypes as ct
class Structure1(ct.Structure):
_fields_ = (('a', ct.c_void_p),
('b', ct.c_uint32),
('w', ct.c_uint16),
('h', ct.c_uint16),
('p', ct.c_size_t))
# Good habit: print representation of class so it can print itself.
def __repr__(self):
return f'Structure1(a={self.a}, b={self.b}, w={self.w}, h={self.h}, p={self.p})'
class Structure2(ct.Structure):
_fields_ = (('a', ct.c_uint32),
('b', ct.c_uint32))
def __repr__(self):
return f'Structure2(a={self.a}, b={self.b})'
OCB = ct.CFUNCTYPE(None, ct.POINTER(Structure1))
IOCB = ct.CFUNCTYPE(None, ct.POINTER(Structure2))
# decorating a function with the callback signature makes it callable from C
@OCB
def output_callback(ps1):
print(ps1.contents)
@IOCB
def inpout_callback(ps2):
print(ps2.contents)
lib_instance = ct.CDLL('./test')
start_api = lib_instance.start_api
start_api.argtypes = OCB, IOCB
start_api.restype = ct.c_int
variable1 = ct.c_uint8.in_dll(lib_instance, 'variable1')
variable2 = ct.c_uint16.in_dll(lib_instance, 'variable2')
variable3 = ct.c_uint16.in_dll(lib_instance, 'variable3')
print(variable1.value, variable2.value, variable3.value)
start_api(output_callback, inpout_callback)
輸出:
3 4056 3040
Structure1(a=None, b=1, w=2, h=3, p=4)
Structure2(a=5, b=6)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.