Как получить доступ к C ++ typedef'd структурам в Python с помощью интерфейса SWIG - PullRequest
1 голос
/ 30 октября 2019

Я пытаюсь настроить свой SWIG-интерфейс для предоставления всех определенных typedefs.

Пример: для следующего в моем заголовочном файле C ++ я хочу, чтобы мой код на python мог создавать объекты A, B, C,D, E.

//MyHeader.h
struct Common
{
    uint8_t     eId;
};
typedef Common A, B, C, D, E;

Я протестировал со следующими структурами в моем заголовочном файле, и объекты, доступные через интерфейс SWIG, это Test, Test2Typedef и Test3Typedef1, но не TestTypedef, Test2, Test3 или Test3Typedef2.

//MyHeader.h
struct Test {
    uint8_t uValue;
};
typedef Test TestTypedef;

typedef struct Test2 {
    uint8_t uValue;
} Test2Typedef;

typedef struct Test3 {
    uint8_t uValue;
} Test3Typedef1, Test3Typedef2;

Я попытался добавить следующие typedefs в мой файл .i и все еще не могу получить доступ к TestTypedef:

//MyHeader.i
%{
#include "MyHeader.h"
typedef Test TestTypedef;
%}

typedef Test TestTypedef;
%include "MyHeader.h"

1 Ответ

0 голосов
/ 03 ноября 2019

Как правило, SWIG пытается максимально точно отразить поведение C на целевом языке. Иногда это немного сложно, хотя нет общего отображения семантики typedef на многие языки, на которые нацелена SWIG. В этом конкретном случае вы все равно можете добиться нужного вам поведения в Python, используя один из двух возможных вариантов. Чтобы упростить вещи, вы захотите быть более последовательными в своем заголовке, поэтому либо всегда набирайте структуры TestN, либо никогда не печатайте их.

Во-первых, вы можете написать немного дополнительного кода Pythonвнутри %pythoncode, который обеспечивает псевдоним для каждого типа в Python, который соответствует ожидаемому. Следующий интерфейс показывает, что:

%module test


%inline %{

struct Test {
    uint8_t uValue;
};
typedef Test TestTypedef;

struct Test2 {
    uint8_t uValue;
};
typedef Test2 Test2Typedef;

struct Test3 {
    uint8_t uValue;
};
 typedef Test3 Test3Typedef1, Test3Typedef2;

%}

%pythoncode %{
  TestTypedef = Test
  Test2Typedef = Test2
  Test3Typedef1 = Test3
  Test3Typedef2 = Test3
%}

Альтернативный подход, однако, состоит в том, чтобы сделать некоторую хитрость на уровне C ++. Все, что нам нужно сделать на самом деле, - это убедиться, что SWIG генерирует нужный нам интерфейс, и это все допустимый, правильный, компилируемый код C ++. Однако не имеет значения, если мы лжем SWIG о том, на что действительно похож наш код C ++. Таким образом, на практике, если мы утверждаем, что каждый из наших typedefs на самом деле является производным классом, но на самом деле это просто typedefs, мы все равно получим прекрасно работающий интерфейс. И в качестве бонуса, в основном, на целевом языке вещи будут более безопасными, что, вероятно, хорошо:

%module test


%{
// This is what the C++ compiler sees:    
struct Test {
    uint8_t uValue;
};
typedef Test TestTypedef;

struct Test2 {
    uint8_t uValue;
};
typedef Test2 Test2Typedef;

struct Test3 {
    uint8_t uValue;
};
typedef Test3 Test3Typedef1, Test3Typedef2;

%}

// This is the lie we tell SWIG, but it's compatible with what the C++ code really is doing
struct Test {
    uint8_t uValue;
};

struct Test2 {
    uint8_t uValue;
};

struct Test3 {
    uint8_t uValue;
};

struct Test2Typedef : Test2 {};
struct Test3Typedef1 : Test3 {};
struct Test3Typedef2 : Test3 {};

Любой из этих вариантов позволяет нам запустить этот код Python:

import test

a = test.Test3Typedef2()

Если бы это былоделая это, я определил бы макрос для генерации typedef:

#ifndef SWIG
#define MAKE_TYPEDEF(original, renamed) typedef original renamed
#else
#define MAKE_TYPEDEF(original, renamed) struct renamed : original {}
#endif 

, который мог бы жить в заголовочном файле и позволил бы вам использовать %include still.

...