我正试图从编译的共享对象访问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文件中的变量?
必须导出中的变量和函数,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);
}
test.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)
在标题中更改
const uint8_t variable1 = 3;
至
extern const uint8_t variable1;
并添加此
extern const uint8_t variable1 = 3;
到.cpp文件
默认情况下,const
变量在C++中具有内部链接,因此不会从共享库中导出。