Существует очевидное несоответствие соглашения о вызовах, когда позиция и содержимое аргументов неверны при загрузке небольшой функции с помощью модуля Python Ctypes.
В примере, который я создал при попытке заставить что-то работать, один позиционный аргумент получает значение другого, а другой - мусор.
Документы Ctypes утверждают, что cdll.LoadLibrary
ожидает соглашения cdecl
. Результирующий стандартный шаблон:
# Tell Rustc to output a dynamically linked library
crate-type = ["cdylib"]
// Specify clean symbol and cdecl calling convention
#[no_mangle]
pub extern "cdecl" fn boring_function(
n: *mut size_t,
in_data: *mut [c_ulong],
out_data: *mut [c_double],
garbage: *mut [c_double],
) -> c_int {
//...
Загрузка нашей библиотеки после сборки ...
lib = ctypes.CDLL("nothing/lib/playtoys.so")
lib.boring_function.restype = ctypes.c_int
Загрузить результат в Python и вызвать его с некоторыми инициализированными данными
data_len = 8
in_array_t = ctypes.c_ulong * data_len
out_array_t = ctypes.c_double * data_len
in_array = in_array_t(7, 7, 7, 7, 7, 8, 7, 7)
out_array = out_array_t(10000.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9)
val = ctypes.c_size_t(data_len)
in_array_p = ctypes.byref(in_array)
out_array_p = ctypes.byref(out_array)
n_p = ctypes.byref(val)
garbage = n_p
res = boring_function(n_p,
in_array_p,
# garbage cannot be observed in any callee arg
ctypes.cast(garbage, ctypes.POINTER(out_array_t)),
out_array_p)
Обратите внимание на параметр garbage
. Это так называется, потому что он содержит адрес мусора. Обратите внимание, что его позиция поменялась местами с out_array_p
в вызове Python и объявлении Rust.
[src/hello.rs:29] n = 0x00007f56dbce5bc0
[src/hello.rs:30] in_data = 0x00007f56f81e3270
[src/hello.rs:31] out_data = 0x00007f56f81e3230
[src/hello.rs:32] garbage = 0x000000000000000a
in_data
, out_data
и n
выводят правильные значения в этой конфигурации. Позиционный обмен между garbage
и out_data
делает это возможным.
Другие примеры, использующие более или менее аргументы, показывают схожие шаблоны промежуточных упорядоченных переменных, содержащих нечетные значения, которые напоминают адреса ранее в программе, или несвязанный мусор.
Либо я что-то упускаю в настройке соглашения о вызовах, либо какая-то особая магия в argtypes
должна отсутствовать. До сих пор мне не повезло с изменением объявленных соглашений о вызовах или явных аргументов. Есть ли другие ручки, которые я должен попробовать повернуть?