К сожалению, похоже, что SWIG не поддерживает сопоставление нескольких элементов структуры одновременно.Изучив сгенерированный вывод, мы узнаем, что (arg1)
указывает на структуру ввода.Таким образом, мы должны:
- Сделать неизменным
word
, чтобы обертка set
не создавалась. - Импортировать фрагмент
SWIG_FromCharPtrAndSize
- он недоступенпо умолчанию. - Карта
word
с использованием SWIG_FromCharPtrAndSize
, как вы пожелали, ссылаясь на (arg1)->wordlen
. - Пропустить
wordlen
, чтобы он не отображался (либо с помощью %ignore
-ingэто или не предоставлено в struct
видимом для SWIG).
Ниже приведен полный пример.Во-первых, заголовок:
// main.h
#pragma once
struct Token {
const char *word;
unsigned short wordlen;
};
struct Token *make_token(void);
extern char *word_check;
И модуль SWIG - обратите внимание, что мы используем дословно заголовок, только переопределяя определение struct Token
:
// token_mod.i
%module token_mod
%{#include "main.h"%}
%ignore Token;
%include "main.h"
%rename("%s") Token;
struct Token {
%immutable word;
%typemap (out, fragment="SWIG_FromCharPtrAndSize") const char *word {
$result = SWIG_FromCharPtrAndSize($1, (arg1)->wordlen);
}
const char *word;
%typemap (out) const char *word;
};
Демонстрационный код, который используетPython для проверки работоспособности:
// https://github.com/KubaO/stackoverflown/tree/master/questions/swig-pair-53915787
#include <assert.h>
#include <stdlib.h>
#include <Python.h>
#include "main.h"
struct Token *make_token(void) {
struct Token *r = malloc(sizeof(struct Token));
r->word = "1234";
r->wordlen = 2;
return r;
}
char *word_check;
#if PY_VERSION_HEX >= 0x03000000
# define SWIG_init PyInit__token_mod
PyObject*
#else
# define SWIG_init init_token_mod
void
#endif
SWIG_init(void);
int main()
{
PyImport_AppendInittab("_token_mod", SWIG_init);
Py_Initialize();
PyRun_SimpleString(
"import sys\n"
"sys.path.append('.')\n"
"import token_mod\n"
"from token_mod import *\n"
"token = make_token()\n"
"cvar.word_check = token.word\n");
assert(word_check && strcmp(word_check, "12") == 0);
Py_Finalize();
return 0;
}
Наконец, CMakeLists.txt
, который делает демо - его можно использовать с Python 2.7 или 3.x.Примечание. Для переключения версий Python каталог сборки должен быть стерт (или, по крайней мере, должны быть стерты кэши cmake в нем).
cmake_minimum_required(VERSION 3.2)
set(Python_ADDITIONAL_VERSIONS 3.6)
project(swig-pair)
find_package(SWIG 3.0 REQUIRED)
find_package(PythonLibs 3.6 REQUIRED)
include(UseSwig)
SWIG_MODULE_INITIALIZE(${PROJECT_NAME} python)
SWIG_ADD_SOURCE_TO_MODULE(${PROJECT_NAME} swig_generated_sources "token_mod.i")
add_executable(${PROJECT_NAME} "main.c" ${swig_generated_sources})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYTHON_INCLUDE_DIRS} ".")
target_link_libraries(${PROJECT_NAME} PRIVATE ${PYTHON_LIBRARIES})