Проблема в том, что ffi.cdef()
не может дать результат, который зависит от директив предварительной обработки, потому что они известны только позже, когда вызывается компилятор Си. (Это может быть исправлено в случае сборок вне линии, но это не сразу.)
Существует два возможных решения:
Выполнить несколько шагов компиляции.
Не раскрывайте необязательное поле, но добавляйте пользовательские функции доступа.
Для 1. напишите что-то вроде этого:
ffi_pre = FFI()
ffi_pre.cdef("#define CAN_MON_IS_DEFINED ...")
ffi_pre.set_source("_tmp_cffi", """
#include <foo_mon.h>
#ifdef CAN_MON
# define CAN_MON_IS_DEFINED 1
#else
# define CAN_MON_IS_DEFINED 0
#endif
""")
ffi_pre.compile()
from _tmp_cffi import ffi as ffi_tmp
can_mon = ffi_tmp.CAN_MON_IS_DEFINED
... затем напишите остальную часть кода, как у вас уже есть, но используйте if can_mon:
где-нибудь в качестве кода Python, например. построить строку в cdef так:
"""
typedef struct can_config_tag
{
char_t type[4];
uint16_t module_nr;
""" + ("uint16_t rx_main_mon;" if can_mon else "") + """
byte_t rx_obj;
};
"""
Решение № 2 состоит в том, чтобы никогда не определять поле rx_main_mon
, а вместо этого добавить функции C, которые читают и пишут его, если поле определено:
ffi.cdef("""
typedef struct can_config_tag
{
char_t type[4];
uint16_t module_nr;
byte_t rx_obj;
};
int my_read_rx_main_mon(struct can_config_tag *);
void my_write_rx_main_mon(struct can_config_tag *, int value);
""")
ffi.set_source("somename", """
#include <foomon.h>
static int my_read_rx_main_mon(struct can_config_tag *p)
{
#ifdef CAN_MON
return p->rx_main_mon;
#else
return -1;
#endif
}
static void my_write_rx_main_mon(struct can_config_tag *p, int value)
{
#ifdef CAN_MON
p->rx_main_mon = value;
#endif
}
""")