首页 > 解决方案 > SWIG、Python 和带有内联指令的接口文件

问题描述

我有带有 Python-3.7.9 和 SWIG-4.0 的 Ubuntu-20.04、Anaconda-3(安装到用户目录中)。

这是我的文件。

a.h

void foo(void);

a.c

#include <stdio.h>
#include "a.h"
void foo(void) { printf("Foo!\n"); }

a.i

%module a
%inline %{
#include "a.h"
%}

test.py

import a
a.foo()

编译脚本compile.sh

A=$HOME/opt/anaconda3
I=$A/include/python3.7m
gcc -c -fpic -DHAVE_CONFIG_H -I$I a.c
$A/bin/swig -python -py3 a.i
gcc -c -fpic -DHAVE_CONFIG_H -I$I a_wrap.c
gcc -shared a.o a_wrap.o -o _a.so

编译后测试脚本产生

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    a.foo()
AttributeError: module 'a' has no attribute 'foo'

但是,如果我编写更长的接口文件,一切都可以:

%module a
%{
#include "a.h"
%}
%include "a.h"

UPD @Jens 建议在第一个(短)接口文件中替换#为。%在这种情况下,我得到了

a_wrap.c:2701:1: error: expected identifier or '(' before '%' token
 2701 | %include "a.h"
      | ^
a_wrap.c:2720:12: error: '_wrap_foo' undeclared here (not in a function)
 2720 |   { "foo", _wrap_foo, METH_NOARGS, NULL},
      |            ^~~~~~~~~
gcc: error: a_wrap.o: No such file or directory

标签: pythoncswig

解决方案


%inline两者都直接在 SWIG 生成的包装器代码中包含括号代码,但也将其处理为生成的目标语言接口。所以这:

%module a
%inline %{
void foo(void);
%}

相当于:

%module a
%{
void foo(void) {}
%}
void foo(void) {}

但是这个:

%module a
%inline %{
#include "a.h"
%}

相当于:

%module a
%{
#include "a.h"
%}
#include "a.h"  // NOT the same as %include "a.h" and isn't processed for interfaces

为了表明%inline它既包含在内又经过处理,我做了:

%module a
%inline %{
#include "a.h"   // ignored in "include-in-wrapper" pass
#ifdef SWIG
%include "a.h"   // processed in "wrap-with-SWIG" pass
#endif
%}

上面做了正确的事情并暴露了接口,但它比仅仅使用更糟糕:

%module a
%{
#include "a.h"
%}
%include "a.h"

%inline真正用于将新函数插入包装器并暴露接口,例如:

%module a
%inline %{
class myClass
{
private: 
  int a;
public: 
  myClass(){} 
  void foo(){}
};
%}

否则你必须至少写:

%module a

%{ // new functionality added to wrapper
class myClass
{
private: 
  int a;
public: 
  myClass(){} 
  void foo(){}
};
%}

class myClass   // process the interface
{
public:         // note don't need to repeat private part or
  myClass();    // implementation, just public declarations to be exposed.
  void foo();
};

推荐阅读