Может ли python загружать определения из файла заголовка C? - PullRequest
4 голосов
/ 06 ноября 2019

Я пишу Python Wrapper вокруг C API. У меня есть подробное описание API, и сейчас я борюсь с реализацией перечислений, определенных в заголовочном файле.

Давайте предположим, что у меня есть функция C API внутри myAPI.dll, которая принимает перечисление в качестве аргумента, например:

void SomeFunction(SomeEnum data)

Из заголовочного файла я вижу, что SomeEnum выглядит так:

enum SomeEnum{
    SomeValue = 1,
    SomeOtherValue = 2,
    SomeVeryStupidValue = -1
};

В Python я загружаю .dll как:

myAPI = ctypes.cdll.LoadLibrary('myAPI.dll')

теперь я хотел бы иметь возможность звонить:

myAPI.SomeFunction(SomeValue)

Я знаю, что я мог бы определить SomeValue в python, но было бы удобно загрузить его определение прямо из заголовочного файла. или имейте это непосредственно как атрибут myAPI. Это возможно?

1 Ответ

2 голосов
/ 07 ноября 2019

Это возможно. Много лет назад я написал инструмент для сканирования файла на синтаксис C ++ enum с использованием pyparsing . Теперь это пример синтаксического анализа , который я воспроизвел здесь в случае изменения ссылки. Как вы можете видеть, файл не обязательно должен быть полностью верным C ++. Он определяет грамматику enum и сканирует файл на наличие текста, соответствующего грамматике, генерируя переменные Python.

#
# cpp_enum_parser.py
#
# Posted by Mark Tolonen on comp.lang.python in August, 2009,
# Used with permission.
#
# Parser that scans through C or C++ code for enum definitions, and
# generates corresponding Python constant definitions.
#
#

from pyparsing import *

# sample string with enums and other stuff
sample = """
    stuff before
    enum hello {
        Zero,
        One,
        Two,
        Three,
        Five=5,
        Six,
        Ten=10
        };
    in the middle
    enum blah
        {
        alpha,
        beta,
        gamma = 10 ,
        zeta = 50
        };
    at the end
    """

# syntax we don't want to see in the final parse tree
LBRACE, RBRACE, EQ, COMMA = map(Suppress, "{}=,")
_enum = Suppress("enum")
identifier = Word(alphas, alphanums + "_")
integer = Word(nums)
enumValue = Group(identifier("name") + Optional(EQ + integer("value")))
enumList = Group(enumValue + ZeroOrMore(COMMA + enumValue))
enum = _enum + identifier("enum") + LBRACE + enumList("names") + RBRACE

# find instances of enums ignoring other syntax
for item, start, stop in enum.scanString(sample):
    id = 0
    for entry in item.names:
        if entry.value != "":
            id = int(entry.value)
        print("%s_%s = %d" % (item.enum.upper(), entry.name.upper(), id))
        id += 1

Вывод:

HELLO_ZERO = 0
HELLO_ONE = 1
HELLO_TWO = 2
HELLO_THREE = 3
HELLO_FIVE = 5
HELLO_SIX = 6
HELLO_TEN = 10
BLAH_ALPHA = 0
BLAH_BETA = 1
BLAH_GAMMA = 10
BLAH_ZETA = 50
...