七、SWIG 之 一个构件结构的策略

一、为 SWIG 准备 C 程序

SWIG 不需要修改你的 C 代码,但如果提供原始 C 头文件或源代码的集合,结果可能不是所期望的——实际上,它们可能很糟糕。以下是为 C 程序创建接口时可以遵循的一系列步骤:

1. 确定要包装的功能。可能没有必要访问 C 程序的每个单独的函数——因此,一点预先的考虑可以大大简化最终的脚本语言接口。查找要包装的东西的话,C 头文件是特别好的源头。
2. 创建一个新的接口文件来描述程序的脚本语言接口。
3. 将适当的声明复制到接口文件中,或使用 SWIG 的 %include 指令处理整个 C 源/头文件。
4. 确保接口文件中的所有内容都使用 ANSI C/C++ 语法。
5. 确保接口文件中提供了所有必需的 typedef 声明和类型信息。特别是,确保按照 C/C++ 编译器的要求以正确的顺序指定类型信息。最重要的是,在使用之前定义一个类型!如果需要,C 编译器将告诉你完整类型信息是否不可用,而 SWIG 通常不会发出警告或错误,因为它设计为在没有完整类型信息的情况下工作。但是,如果未正确指定类型信息,则包装器可能是次优的,甚至会导致无法编译的 C/C++ 代码。
6. 如果你的程序具有 main() 函数,则可能需要重命名(只读), 或者删除
7. 运行 SWIG 并编译。

二、SWIG 接口文件

使用 SWIG 的首选方法是生成单独的接口文件。假设你有以下 C 头文件:

/* File : header.h */
 
#include <stdio.h>
#include <math.h>
 
extern int foo(double);
extern double bar(int, int);
extern void dump(FILE *f);

此头文件的典型 SWIG 接口文件如下所示:

/* File : interface.i */
%module mymodule
%{
#include "header.h"
%}
extern int foo(double);
extern double bar(int, int);
extern void dump(FILE *f);

当然,在这种情况下,我们的头文件非常简单,所以我们可以使用更简单的方法并使用这样的接口文件:

/* File : interface.i */

%module mymodule
%{
#include "header.h"
%}
%include "header.h"

这种方法的主要优点是,当头文件将来发生变化时,接口文件的维护很少。在更复杂的项目中,包含许多 %include 和 #include 语句的接口文件是最常见的接口文件设计方法之一,因为维护成本较低。

三、为什么使用单独的接口文件

虽然 SWIG 可以解析许多头文件,但更常见的是编写一个特殊的 .i 文件来定义包的接口。你希望这样做的可能原因有以下几种:

1. 很少需要访问大型包中的每个功能。许多 C 函数可能在脚本环境中很少或没有用处。
2. 单独的接口文件提供了一个机会,可以提供有关如何构造接口的更精确的规则。
3. 接口文件可以提供更多的结构和组织。
4. SWIG 无法解析头文件中出现的某些定义。拥有单独的文件可以消除或解决这些问题。
5. 接口文件提供了更精确的接口定义。想要扩展系统的用户可以转到接口文件,并立即查看可用的内容,而无需将其从头文件中删除。

四、获得正确的头文件

有时,必须使用某些头文件才能使 SWIG 生成的代码正确编译。确保使用 %{ %} 块包含某些头文件,如下所示:

/* example.i */
%module example

%{
#include <GL/gl.h>
#include <GL/glu.h>
%}

// Put the rest of the declarations here

 

posted on 2022-11-22 17:24  软饭攻城狮  阅读(187)  评论(0编辑  收藏  举报

导航