天天看點

SWIG 3 中文手冊——2. 引言

目錄

  • 2 引言
    • 2.1 SWIG 是什麼?
    • 2.2 為什麼使用 SWIG?
    • 2.3 一個 SWIG 示例
      • 2.3.1 SWIG 接口檔案
      • 2.3.2

        swig

        指令
      • 2.3.3 建構 Perl5 子產品
      • 2.3.4 建構 Python 子產品
      • 2.3.5 快捷方式
    • 2.4 支援的 C/C++ 語言特性
    • 2.5 非直覺的接口建構
    • 2.6 将 SWIG 整合進建構系統
    • 2.7 自動化代碼生成
    • 2.8 SWIG 與自由

SWIG is a software development tool that simplifies the task of interfacing different languages to C and C++ programs. In a nutshell, SWIG is a compiler that takes C/C++ declarations and creates the wrappers needed to access those declarations from other languages including Perl, Python, Tcl, Ruby, Guile, and Java. SWIG normally requires no modifications to existing code and can often be used to build a usable interface in only a few minutes. Possible applications of SWIG include:

  • Building interpreted interfaces to existing C programs.
  • Rapid prototyping and application development.
  • Interactive debugging.
  • Reengineering or refactoring of legacy software into scripting language components.
  • Making a graphical user interface (using Tk for example).
  • Testing of C libraries and programs (using scripts).
  • Building high performance C modules for scripting languages.
  • Making C programming more enjoyable (or tolerable depending on your point of view).
  • Impressing your friends.
  • Obtaining vast sums of research funding (although obviously not applicable to the author).

SWIG was originally designed to make it extremely easy for scientists and engineers to build extensible scientific software without having to get a degree in software engineering. Because of this, the use of SWIG tends to be somewhat informal and ad-hoc (e.g., SWIG does not require users to provide formal interface specifications as you would find in a dedicated IDL compiler). Although this style of development isn't appropriate for every project, it is particularly well suited to software development in the small; especially the research and development work that is commonly found in scientific and engineering projects. However, nowadays SWIG is known to be used in many large open source and commercial projects.

SWIG 是一款軟體開發工具,它簡化了将不同語言連接配接到 C 和 C++ 程式的任務。簡而言之,SWIG 是一個編譯器,它接受 C/C++ 聲明并建立從其他語言(包括 Perl、Python、Tcl、Ruby、Guile 和 Java)通路這些聲明所需的包裝器。SWIG 通常不需要修改現有代碼,并且可以在幾分鐘内建構可用的接口。SWIG 可能的應用包括:
  • 建構現有 C 程式的解釋接口。
  • 快速原型設計和應用程式開發。
  • 互動式調試。
  • 将曆史遺留軟體重新設計或重構為腳本語言元件。
  • 制作圖形使用者(例如使用 Tk)。
  • 測試 C 代碼庫和程式(使用腳本)。
  • 為腳本語言建構高性能 C 子產品。
  • 使 C 程式設計更愉快(或視你的情況而定)。
  • 給你的朋友留下深刻印象
  • 獲得大量研究經費(雖然顯然不适用于作者本人)。
SWIG 最初旨在使科學家和工程師能夠非常輕松地建構可擴充的科學軟體,而無需軟體工程學位。是以,SWIG 的使用往往是非正式的和臨時的(例如,SWIG 不要求使用者提供正式的接口規範,就像你在專用的 IDL 編譯器中找到的那樣)。雖然這種開發方式并不适合每個項目,但它特别适合于小型軟體開發,特别是科學和工程項目中常見的研究和開發工作。但是,如今已知 SWIG 可用于許多大型開源和商業項目。

As stated in the previous section, the primary purpose of SWIG is to simplify the task of integrating C/C++ with other programming languages. However, why would anyone want to do that? To answer that question, it is useful to list a few strengths of C/C++ programming:

  • Excellent support for writing programming libraries.
  • High performance (number crunching, data processing, graphics, etc.).
  • Systems programming and systems integration.
  • Large user community and software base.

Next, let's list a few problems with C/C++ programming

  • Writing a user interface is rather painful (i.e., consider programming with MFC, X11, GTK, or any number of other libraries).
  • Testing is time consuming (the compile/debug cycle).
  • Not easy to reconfigure or customize without recompilation.
  • Modularization can be tricky.
  • Security concerns (buffer overflows for instance).

To address these limitations, many programmers have arrived at the conclusion that it is much easier to use different programming languages for different tasks. For instance, writing a graphical user interface may be significantly easier in a scripting language like Python or Tcl (consider the reasons why millions of programmers have used languages like Visual Basic if you need more proof). An interactive interpreter might also serve as a useful debugging and testing tool. Other languages like Java might greatly simplify the task of writing distributed computing software. The key point is that different programming languages offer different strengths and weaknesses. Moreover, it is extremely unlikely that any programming is ever going to be perfect. Therefore, by combining languages together, you can utilize the best features of each language and greatly simplify certain aspects of software development.

From the standpoint of C/C++, a lot of people use SWIG because they want to break out of the traditional monolithic C programming model which usually results in programs that resemble this:

  • A collection of functions and variables that do something useful.
  • A

    main()

    program that starts everything.
  • A horrible collection of hacks that form some kind of user interface (but which no-one really wants to touch).

Instead of going down that route, incorporating C/C++ into a higher level language often results in a more modular design, less code, better flexibility, and increased programmer productivity.

SWIG tries to make the problem of C/C++ integration as painless as possible. This allows you to focus on the underlying C program and using the high-level language interface, but not the tedious and complex chore of making the two languages talk to each other. At the same time, SWIG recognizes that all applications are different. Therefore, it provides a wide variety of customization features that let you change almost every aspect of the language bindings. This is the main reason why SWIG has such a large user manual 😉.

如上一節所述,SWIG 的主要目的是簡化 C/C++ 與其他程式設計語言內建的任務。但是,為什麼有人想這樣做呢?要回答這個問題,列出一些 C/C++ 程式設計的優點很有用:
  • 對編寫程式庫的出色支援。
  • 高性能(數值運算、資料處理、圖形等)。
  • 系統程式設計和系統內建。
  • 龐大的使用者社群和軟體基礎。
接着,列出一些 C/C++ 程式設計的問題
  • 編寫使用者界面相當痛苦(即考慮使用 MFC、X11、GTK 或其他庫進行程式設計)。
  • 測試耗時(編譯/調試周期)。
  • 不重新編譯就不容易重新配置或自定義。
  • 子產品化可能很棘手。
  • 安全問題(例如緩沖區溢出)。

為了解決這些限制,許多程式員得出的結論是,在不同的任務使用不同的程式設計語言要容易得多。例如,在 Python 或 Tcl 等腳本語言中編寫圖形使用者界面可能要容易得多(如果需要更多證據,請考慮數百萬程式員使用 Visual Basic 等語言的原因)。互動式解釋器也可以作為有用的調試和測試工具。像 Java 這樣的其他語言可以大大簡化編寫分布式計算軟體的任務。關鍵是不同的程式設計語言提供不同的優點和缺點。而且,任何程式都不太可能是完美的。是以,通過将語言組合在一起,你可以利用每種語言的最佳功能,并大大簡化軟體開發的某些方面。

從 C/C++ 的角度來看,很多人都使用 SWIG,因為他們想要打破傳統的單片機 C 程式設計模型,那通常會産生類似于下面的程式:

  • 一組有用的函數和變量。
  • 一個啟動所有内容的

    main()

    程式。
  • 一個可怕的黑客集合,形成了某種使用者界面(但沒有人真正想要碰一碰)。

将 C/C++ 結合到更進階的語言中,通常會導緻更加子產品化的設計、更少的代碼、更好的靈活性,以及更高的程式員生産力,而不是沿着老路走下去。

SWIG 試圖使 C/C++ 內建問題盡可能輕松。這使你可以專注于底層的 C 程式,并使用進階語言接口,而不是讓兩種語言互相交流的繁瑣複雜的工作。同時,SWIG 認識到所有應用程式都是不同的。是以,它提供了各種自定義功能,使你可以更改語言綁定的幾乎每個方面。這是 SWIG 擁有如此厚的使用者手冊的主要原因 😉。

The best way to illustrate SWIG is with a simple example. Consider the following C code:

闡釋 SWIG 的最佳方式是一個簡單的例子。考慮以下 C 代碼:
/* File : example.c */

double  My_variable  = 3.0;

/* Compute factorial of n */
int fact(int n) {
  if (n <= 1)
    return 1;
  else
    return n*fact(n-1);
}

/* Compute n mod m */
int my_mod(int n, int m) {
  return(n % m);
}
           

Suppose that you wanted to access these functions and the global variable

My_variable

from Tcl. You start by making a SWIG interface file as shown below (by convention, these files carry a .i suffix) :

假設你想要從 Tcl 通路這些函數和全局變量

My_variable

。首先制作一個 SWIG 接口檔案,如下所示(按照慣例,這些檔案帶有

.i

字尾):

/* File : example.i */
%module example
%{
/* Put headers and other declarations here */
extern double My_variable;
extern int    fact(int);
extern int    my_mod(int n, int m);
%}

extern double My_variable;
extern int    fact(int);
extern int    my_mod(int n, int m);
           

The interface file contains ANSI C function prototypes and variable declarations. The

%module

directive defines the name of the module that will be created by SWIG. The

%{ %}

block provides a location for inserting additional code, such as C header files or additional C declarations, into the generated C wrapper code.

接口檔案包含 ANSI C 函數原型和變量聲明。

%module

指令定義 SWIG 建立的子產品的名稱。

%{ %}

塊提供了一個位置,用于在生成的 C 包裝器代碼中插入其他代碼,例如 C 頭檔案或其他 C 聲明。

swig

SWIG is invoked using the

swig

command. We can use this to build a Tcl module (under Linux) as follows :

使用

swig

指令調用 SWIG。我們可以使用它來建構一個 Tcl 子產品(在 Linux 下),如下所示:
unix > swig -tcl example.i
unix > gcc -c -fpic example.c example_wrap.c -I/usr/local/include
unix > gcc -shared example.o example_wrap.o -o example.so
unix > tclsh
% load ./example.so
% fact 4
24
% my_mod 23 7
2
% expr $My_variable + 4.5
7.5
%
           

The

swig

command produced a new file called

example_wrap.c

that should be compiled along with the

example.c

file. Most operating systems and scripting languages now support dynamic loading of modules. In our example, our Tcl module has been compiled into a shared library that can be loaded into Tcl. When loaded, Tcl can now access the functions and variables declared in the SWIG interface. A look at the file

example_wrap.c

reveals a hideous mess. However, you almost never need to worry about it.

swig

指令生成了一個名為

example_wrap.c

的新檔案,該檔案應與

example.c

檔案一起編譯。現在,大多數作業系統和腳本語言都支援動态加載子產品。在我們的示例中,我們的 Tcl 子產品已編譯為可以加載到 Tcl 的動态庫。加載後,Tcl 現在可以通路 SWIG 接口中聲明的函數和變量。看看檔案

example_wrap.c

就會發現可怕的混亂。但是,你幾乎不需要擔心它。

Now, let's turn these functions into a Perl5 module. Without making any changes type the following (shown for Solaris):

現在,讓我們将這些函數轉換為 Perl5 子產品。在不進行任何更改的情況下鍵入以下内容(針對 Solary 顯示):
unix > swig -perl5 example.i
unix > gcc -c example.c example_wrap.c \
        -I/usr/local/lib/perl5/sun4-solaris/5.003/CORE
unix > ld -G example.o example_wrap.o -o example.so # This is for Solaris
unix > perl5.003
use example;
print example::fact(4), "\n";
print example::my_mod(23, 7), "\n";
print $example::My_variable + 4.5, "\n";
<ctrl-d>
24
2
7.5
unix >
           

Finally, let's build a module for Python (shown for Irix).

最後,讓我們為 Python 建構一個子產品(針對 Irix 顯示)。
unix > swig -python example.i
unix > gcc -c -fpic example.c example_wrap.c -I/usr/local/include/python2.0
unix > gcc -shared example.o example_wrap.o -o _example.so
unix > python
Python 2.0 (#6, Feb 21 2001, 13:29:45)
[GCC egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> import example
>>> example.fact(4)
24
>>> example.my_mod(23, 7)
2
>>> example.cvar.My_variable + 4.5
7.5
           

To the truly lazy programmer, one may wonder why we needed the extra interface file at all. As it turns out, you can often do without it. For example, you could also build a Perl5 module by just running SWIG on the C header file and specifying a module name as follows

對于真正懶惰的程式員,人們可能想知道為什麼我們需要額外的接口檔案。事實證明,你經常可以不需要它。例如,你還可以通過在 C 頭檔案上運作 SWIG,并指定子產品名稱來建構 Perl5 子產品,如下所示
unix > swig -perl5 -module example example.h
unix > gcc -c example.c example_wrap.c \
        -I/usr/local/lib/perl5/sun4-solaris/5.003/CORE
unix > ld -G example.o example_wrap.o -o example.so
unix > perl5.003
use example;
print example::fact(4), "\n";
print example::my_mod(23, 7), "\n";
print $example::My_variable + 4.5, "\n";
<ctrl-d>
24
2
7.5
           

A primary goal of the SWIG project is to make the language binding process extremely easy. Although a few simple examples have been shown, SWIG is quite capable in supporting most of C++. Some of the major features include:

  • Full C99 preprocessing.
  • All ANSI C and C++ datatypes.
  • Functions, variables, and constants.
  • Classes.
  • Single and multiple inheritance.
  • Overloaded functions and methods.
  • Overloaded operators.
  • C++ templates (including member templates, specialization, and partial specialization).
  • Namespaces.
  • Variable length arguments.
  • C++ smart pointers.

Most of C++11 is also supported. Details are in the C++11 section.

It is important to stress that SWIG is not a simplistic C++ lexing tool like several apparently similar wrapper generation tools. SWIG not only parses C++, it implements the full C++ type system and it is able to understand C++ semantics. SWIG generates its wrappers with full knowledge of this information. As a result, you will find SWIG to be just as capable of dealing with nasty corner cases as it is in wrapping simple C++ code. In fact, SWIG is able to handle C++ code that stresses the very limits of many C++ compilers.

SWIG 項目的主要目标是使語言綁定過程變得非常容易。雖然隻展示了一些簡單的例子,但 SWIG 能夠很好地支援 C++ 的大多數功能。主要包括:
  • 完整的 C99 預處理;
  • 全部 ANSI C&C++ 資料類型;
  • 函數、變量與常量;
  • 類;
  • 單繼承與多繼承;
  • 重載函數與方法;
  • 重載運算符;
  • C++ 模闆(包括成員模闆、特化和偏特化);
  • 命名空間;
  • 變長參數;
  • C++ 智能指針。

支援絕大部分 C++11 功能。細節請見 C++11 章節。

需要着重強調一點,SWIG 不是一個簡單的 C++ 詞法分析工具,就像幾個明顯相似的包裝器生成工具一樣。SWIG 不僅解析 C++,它實作了完整的 C++ 類型系統,并且能夠了解 C++ 語義。SWIG 在充分了解這些資訊的情況下生成包裝器。是以,你會發現 SWIG 能夠像處理簡單的 C++ 代碼一樣處理令人讨厭的特殊情況。事實上,SWIG 能夠處理強調許多挑戰 C++ 編譯器極限的代碼。

When used as intended, SWIG requires minimal (if any) modification to existing C or C++ code. This makes SWIG extremely easy to use with existing packages and promotes software reuse and modularity. By making the C/C++ code independent of the high level interface, you can change the interface and reuse the code in other applications. It is also possible to support different types of interfaces depending on the application.

當按預期使用時,SWIG 要求對現有 C 或 C++ 代碼進行最少(如果有)修改。這使 SWIG 非常易于使用現有軟體包,并有助于軟體重用和子產品化。通過使 C/C++ 代碼獨立于進階接口,你可以更改接口,并在其他應用程式中重用代碼。還可以根據應用程式支援不同類型的接口。

SWIG is a command line tool and as such can be incorporated into any build system that supports invoking external tools/compilers. SWIG is most commonly invoked from within a Makefile, but is also known to be invoked from popular IDEs such as Microsoft Visual Studio.

If you are using the GNU Autotools (Autoconf/ Automake/ Libtool) to configure SWIG use in your project, the SWIG Autoconf macros can be used. The primary macro is

ax_pkg_swig

, seehttp://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html#ax_pkg_swig. The

ax_python_devel

macro is also helpful for generating Python extensions. See theAutoconf Archive for further information on this and other Autoconf macros.

There is growing support for SWIG in some build tools, for example CMake is a cross-platform, open-source build manager with built in support for SWIG. CMake can detect the SWIG executable and many of the target language libraries for linking against. CMake knows how to build shared libraries and loadable modules on many different operating systems. This allows easy cross platform SWIG development. It can also generate the custom commands necessary for driving SWIG from IDEs and makefiles. All of this can be done from a single cross platform input file. The following example is a CMake input file for creating a python wrapper for the SWIG interface file, example.i:

SWIG 是一個指令行工具,是以可以合并到任何支援調用外部工具/編譯器的建構系統中。SWIG 最常在 Makefile 中調用,但也可以從流行的 IDE(如 Microsoft Visual Studio)調用。

如果你正在使用 GNU 自動工具(Autoconf/ Automake/ Libtool)來為你的項目配置 SWIG,可以使用 SWIG 的

Autoconf

宏。主要的宏是

ax_pkg_swig

,詳見 http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html#ax_pkg_swig。在建構 Python 擴充時

ax_python_devel

也很有用。細節資訊和其他

Autoconf

宏詳見 Autoconf Archive。

一些建構工具中對 SWIG 的支援越來越多,例如 CMake 是一個跨平台的開源建構管理器,内置了對 SWIG 的支援。CMake 可以檢測 SWIG 可執行檔案和許多目智語言庫以進行連結。CMake 知道如何在許多不同的作業系統上建構動态庫和可加載子產品。這樣可以輕松實作跨平台 SWIG 開發。它還可以生成從 IDE 和 makefile 驅動 SWIG 所需的自定義指令。所有這些都可以從單個跨平台輸入檔案中完成。以下示例是一個 CMake 輸入檔案,用于為 SWIG 接口檔案

example.i

建立 python 包裝器:
# This is a CMake example for Python

FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})

FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

SET(CMAKE_SWIG_FLAGS "")

SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(example python example.i example.cxx)
SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})
           

The above example will generate native build files such as makefiles, nmake files and Visual Studio projects which will invoke SWIG and compile the generated C++ files into _example.so (UNIX) or _example.pyd (Windows). For other target languages on Windows a dll, instead of a .pyd file, is usually generated.

上面的示例将生成本機建構檔案,例如 makefile、nmake 檔案和 Visual Studio 項目檔案,它們将調用 SWIG 并将生成的 C++ 檔案編譯為

_example.so

(UNIX)或

_example.pyd

(Windows)。 對于 Windows 上的其他目智語言,通常會生成 dll 而不是

.pyd

檔案。

SWIG is designed to produce working code that needs no hand-modification (in fact, if you look at the output, you probably won't want to modify it). You should think of your target language interface being defined entirely by the input to SWIG, not the resulting output file. While this approach may limit flexibility for hard-core hackers, it allows others to forget about the low-level implementation details.

SWIG 旨在生成無需手動修改的工作代碼(事實上,如果檢視輸出,你可能不希望對其進行修改)。你應該認為目智語言接口完全由 SWIG 的輸入定義,而不是生成的輸出檔案。雖然這種方法可能會限制硬核黑客的靈活性,但它允許其他人忘記低級的實作細節。

No, this isn't a special section on the sorry state of world politics. However, it may be useful to know that SWIG was written with a certain "philosophy" about programming---namely that programmers are smart and that tools should just stay out of their way. Because of that, you will find that SWIG is extremely permissive in what it lets you get away with. In fact, you can use SWIG to go well beyond "shooting yourself in the foot" if dangerous programming is your goal. On the other hand, this kind of freedom may be exactly what is needed to work with complicated and unusual C/C++ applications.

Ironically, the freedom that SWIG provides is countered by an extremely conservative approach to code generation. At its core, SWIG tries to distill even the most advanced C++ code down to a small well-defined set of interface building techniques based on ANSI C programming. Because of this, you will find that SWIG interfaces can be easily compiled by virtually every C/C++ compiler and that they can be used on any platform. Again, this is an important part of staying out of the programmer's way----the last thing any developer wants to do is to spend their time debugging the output of a tool that relies on non-portable or unreliable programming features. Dependencies are often a source of incompatibilities and problems and so additional third party libraries are not used in the generated code. SWIG will also generally avoid generating code that introduces a dependency on the C++ Standard Template Library (STL). SWIG will generate code that depends on the C libraries though.

這不是關于世界政治糟糕狀況的特别章節。然而,知道 SWIG 是由程式設計的某種“哲學”編寫的,這可能是有用的——即程式員是聰明的,工具不應該擋路。是以,你會發現 SWIG 極度地放任你。事實上,如果危險的程式設計是你的目标,那麼你可以使用 SWIG 遠離“打到自己的腳”。另一方面,這種自由可能正是處理複雜和不尋常的 C/C++ 應用程式所需要的。

具有諷刺意味的是,SWIG 提供的自由被極端保守的代碼生成方法所抵消。從本質上講,SWIG 是試圖将最進階的 C++ 代碼提煉為基于 ANSI C 程式設計的一組定義明确的接口建構技術。是以,你會發現幾乎每個 C/C++ 編譯器都可以輕松編譯 SWIG 接口,并且可以在任何平台上使用它們。再一次,這對程式員很重要——任何開發人員最不想要做的一件事就是花時間調試依賴于非便攜或不可靠程式設計工具的輸出。依賴性通常是不相容性和問題的根源,是以生成的代碼中不使用其他第三方庫。SWIG 通常還會避免生成依賴于 C++ 标準模闆庫(STL)的代碼。然而,SWIG 将生成依賴于 C 庫的代碼。

★ 持續學習 ★ 堅持創作 ★