본문 바로가기

Language/python

SWIG Tutorial

 

원본 : http://www.swig.org/tutorial.html

시작하기#

짧은 시간내에 SWIG를 사용해보자. SWIG를 사용법을 설명하기 전에 변환하기를 원하는 C 파일을 가지고 있고 이것을 Tcl, Perl, Python, Java, C#에서 사용하고 싶다고 가정하자. 여기서 그 C 파일을example.c라고 하고, 내용은 아래와 같다.

/* File : example.c */
 
 #include <time.h>
 double My_variable = 3.0;
 
 int fact(int n) {
     if (n <= 1) return 1;
     else return n*fact(n-1);
 }
 
 int my_mod(int x, int y) {
     return (x%y);
 }
    
 char *get_time()
 {
     time_t ltime;
     time(&ltime);
     return ctime(&ltime);
 }
 


Interface file#

위에서 본 C 파일을 당신이 원하는 언어에 추가하기 위해서 "interface file" 이라는 것을 만들어야 한다. 이러한 interface file은 아래와 같다.

/* example.i */
 %module example
 %{
 /* Put header files here or function declarations like below */
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();
 %}
 
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();


Building a Tcl module#

UNIX에서는 다음과 같이 명령을 주면된다.(다른 운영체제는 SWIG Wiki Shared Libraries을 참고한다.)


 unix % swig -tcl example.i
 unix % gcc -fpic -c 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 example
 % puts $My_variable
 3.0
 % fact 5
 120
 % my_mod 7 3
 1
 % get_time
 Sun Feb 11 23:01:07 1996
 
 %


SWIG 명령은 example_wrap.c라는 파일을 생성한다. 이 파일은 원본 소스파일과 같이 컴파일되어 공유 라이브러리 형태로 링크되어야 한다. Tcl의 경우는 Tcl에서 로드할 수 있는 동적 확장 모듈을 생성하였으며, load 명령으로 해당 모듈을 로드하여 사용하였다.

 

Building a Python module#

C 코드를 python 모듈로 변환하는 것도 쉽다. 간단히 아래의 예제를 따라하자.(다른 운영체제에서는 SWIG Wiki Shared Libraries 을 참고한다.)


 unix % swig -python example.i
 unix % gcc -c example.c example_wrap.c \
        -I/usr/local/include/python2.1
 unix % ld -shared example.o example_wrap.o -o _example.so


이렇게 만들어진 python 모듈은 아래와 같이 사용할 수 있다.

 >>> import example
 >>> example.fact(5)
 120
 >>> example.my_mod(7,3)
 1
 >>> example.get_time()
 'Sun Feb 11 23:01:07 1996'
 >>>

 

Building a Perl module#

Perl5 모듈 또한 아래와 같이 쉽게 만들수 있다.

 unix % swig -perl5 example.i
 unix % gcc -c example.c example_wrap.c \
        `perl -MExtUtils::Embed -e ccopts`
 unix % ld -G example.o example_wrap.o -o example.so
 unix % perl
 use example;
 print $example::My_variable,"\n";
 print example::fact(5),"\n";
 print example::get_time(),"\n";
 <ctrl-d>
 3.0
 120
 Sun Feb 11 23:01:07 1996
 unix %

 

Building a Java module#

SWIG는 JAVA로부터 C/C++ 코드로의 접근을 위해 JNI 코드를 만들수 있다. JAVA 모듈을 만드는 예제는 아래와 같다.

 $ swig -java example.i
 $ gcc -c example.c example_wrap.c -I/c/jdk1.3.1/include -I/c/jdk1.3.1/include/win32
 $ gcc -shared example.o  example_wrap.o -mno-cygwin -Wl,--add-stdcall-alias  -o example.dll
 $ cat main.java
 public class main {
   public static void main(String argv[]) {
     System.loadLibrary("example");
     System.out.println(example.getMy_variable());
     System.out.println(example.fact(5));
     System.out.println(example.get_time());
   }
 }
 $ javac main.java
 $ java main
 3.0
 120
 Mon Mar  4 18:20:31  2002
 $

Building a C# module#

SWIG는 또한 C/C++의 코드를 C#에서 접근할 수 있도록 PInvoke를 사용하여 코드를 생성할 수 있다.

 $ swig -csharp  example.i
 $ gcc -c -fpic  example.c example_wrap.c
 $ gcc -shared example.o  example_wrap.o   -o libexample.so
 $ cscc -o runme *.cs
 $ cat runme.cs
 using System;
 public class runme {
     static void Main() {
         Console.WriteLine(example.My_variable);
         Console.WriteLine(example.fact(5));
         Console.WriteLine(example.get_time());
     }
 }
 $ ilrun runme
 3
 120
 Tue May 13 10:45:45 2003
 
 $

SWIG for the truly lazy#

interface file을 항상 꼭 작성해야 할 필요는 없다. 만약 header 파일을 가지고 있다면, SWIG interface 파일에서 직접적으로 header 파일을 포함할 수도 있다. 예를 들어,

 %module example
 %{
 /* Includes the header in the wrapper code */
 #include "header.h"
 %}
 
 /* Parse the header file to generate wrappers */
 %include "header.h"


다른 방법으로는 header 파일에 조건 컴파일 문을 넣어 SWIG 지시문을 넣을 수도 있다. 예를 들어,

 #ifdef SWIG
 %module example
 %{
 #include "header.h"
 %}
 #endif
 
 extern int fact(int n);
 ...

Running SWIG under Microsoft Windows#

SWIG는 32bit Windows 시리즈에서도 잘 동작한다.(95/98/NT/2000/XP) SWIG는 간단히 cmd 프롬프트에서 사용되어 지며, NMAKE와 같이 사용할 수 있다. 모듈들은 일반적으로 Tcl, Python 또는 어떤 언어든지 동적으로 로드될 수 있는 DLL 폼으로 컴파일된다. 약간의 노력을 더한다면, SWIG는 또한 MS Developer Studio상에서 사용자 빌드 옵션을 동해 사용될 수 있다.

That's it (well, more or less)#

시작하기 위해 알아야 할 체크리스트가 아래에 있다.

  • 모듈 이름을 주어야한다.
  • ANSI C/C++ 문법을 사용해야 한다.
  • shared library module과 dynamic link library 컴파일 방법을 이해해야 한다.
  • Relax...

Surely there's more to it...#

지금까지의 예제들은 의도적으로 간단하였지만, 일반적으로 보다 복잡한 C/C++ 프로그래밍 일을 요구한다. 사실, SWIG는 거의 모든 언어들의 특징을 지원하는 완벽한 C++ 컴파일러이다. SWIG는 preprocessing, pointers, classes, inheritance, 및 심지어 C++ templates 에 대한 지원을 포함한다. SWIG는 또한 대상 언어(target language)에서 structure와 class 들을 구조화하는데에도 사용된다.

이것을 설명하기 위해, 아래와 같은 C++ 자료 구조를 wrap하고 싶다고 하자.

  // pair.h.  A pair like the STL
 namespace std {
    template<class T1, class T2> struct pair {
        T1 first;
        T2 second;
        pair() : first(T1()), second(T2()) { };
        pair(const T1 &f, const T2 &s) : first(f), second(s) { }
    };
 }


SWIG로 래핑하기 위해서, 아래와 같은 interface를 만들자.

 // pair.i - SWIG interface
 %module pair
 %{
 #include "pair.h"
 %}
 
 // Ignore the default constructor
 %ignore std::pair::pair();     
 
 // Parse the original header file
 %include "pair.h"
 
 // Instantiate some templates
 
 %template(pairii) std::pair<int,int>;
 %template(pairdi) std::pair<double,int>;


이제 컴파일하자.(Python):

 $ swig -python -c++ pair.i
 $ c++ -c pair_wrap.c -I/usr/local/include/python2.1
 $ c++ -shared pair_wrap.o -o _pair.so
 $ python
 Python 2.1 (#3, Aug 20 2001, 15:41:42)
 [GCC 2.95.2 19991024 (release)] on sunos5
 Type "copyright", "credits" or "license" for more information.
 >>> import pair
 >>> a = pair.pairii(3,4)
 >>> a.first
 3
 >>> a.second
 4
 >>> a.second = 16
 >>> a.second
 16
 >>> b = pair.pairdi(3.5,8)
 >>> b.first
 3.5
 >>> b.second
 8


이 글은 스프링노트에서 작성되었습니다.