Hlavní navigace

SWIG - Úvod

Jakub Matys

Popularita vysokoúrovňových interpretovaných jazyků, jako je Python, Ruby nebo Java, stále roste. Se zvyšující se výkoností počítačů se zlepšuje i rychlost programů. Pokud však stále není dostačující, můžeme to řešit kompilací určitých rizikových modulů do binární podoby. Pomoci by nám měl projekt zvaný SWIG.

Nespornou výhodou interpretovaných skriptovacích jazyků je jejich přenositelnost a jednoduchost, což z nich činí mocné nástroje. Protože je však jejich kód prováděn interpretem z textového souboru nebo bajtového kódu, nedosahují takových výkonů jako překládané programy. Řešením tohoto „neduhu“ může být dynamické nahrávání binárních knihoven jako modulů jazyka. Při psaní modulu musíte řešit dvě věci – samotnou logiku rozšíření a rozhraní mezi modulem a interpretem. Můžeme se podívat na příklad modulu jazyka Python.

Samotná logika modulu:

/* Vypocet nejvetsiho spolecneho delitele dvou kladnych celych cisel x a y */
int gcd(int x, int y) {
    int g;
    g = y;
    while (x > 0) {
        g = x;
        x = y % x;
        y = g;
    }
    return g;
}

/* Vytisk urcitych dat */
void print_data(char *name, char *email, char *phone) {
    printf("Name    : %s\n", name);
    printf("Email   : %s\n", email);
    printf("Phone   : %s\n", phone);
} 

Rozhraní modulu:

/* modul "spam" */
/* Zahrnuti Pythonskeho C API */
#include "Python.h"

/* Vnejsi deklarace */
extern int gcd(int,int);
extern void print_data(char *, char *, char *);

/* Wrapper pro funkci gcd() */
PyObject *spam_gcd(PyObject *self, PyObject *args) {
    int x, y, g;
    /* Ziskani pythonskych argumentu */
    if (!PyArg_ParseTuple(args, "ii", &#x, &y)) {
        return NULL;
    }
    /* Zavolani funkce jazyka C */
    g = gcd(x, y);
    return Py_BuildValue("i", g);
}

/* Wrapper pro funkci print_data() */
PyObject *spam_print_data(PyObject *self, PyObject *args, PyObject *kwargs) {
    char *name = "None";
    char *email = "None";
    char *phone = "None";
    static char *argnames[] = {"name", "email", "phone", NULL};

    /* Ziskani pythonskych argumentu */
    if (!PyArg_ParseTupleAndKeywords(args, kwargs,"|sss", argnames, &name, &email, &phone)) {
        return NULL;
    }
    /* Zavolani funkce jazyka C */
    print_data(name, email, phone);
    return Py_BuildValue("");
}

/* Tabulka metody zobrazujici nazvy na wrappery */
static PyMethodDef spammethods[] = {
    {"gcd", spam_gcd, METH_VARARGS},
    {"print_data", spam_print_data, METH_VARARGS | METH_KEYWORDS },
    {NULL, NULL}
};
/* Funkce pro inicializaci modulu */
initspam(void) {
    Py_InitModule("spam", spammethods);
} 

Tento kousek kódu byl převzat z knihy „Python: Referenční programátorská příručka“ od Davida M. Beazleyho, který je též autorem SWIGu.

Takovéto řešení je poněkud těžkopádné, nejenže musíte vymyslet samotný modul, ale musíte ho ručně „spojit“ s interpretem. Tento problém přichází řešit projekt zvaný SWIG (Simplified Wrapper and Interface Generator). Tento program/knihovna umožňuje rozšiřování a zapouzdřování jazyků, jako jsou: Allegro CL, C#, Chicken, Guile, Java, Modula-3, Mzscheme, OCAML, Perl, PHP, Python, Ruby a Tcl.

SWIG byl poprvé použit v roce 1995 v Theoretical Physic Division Los Angeleské National Laboratory pro vytvoření uživatelského rozhraní k simulačnímu programu superpočítače. Vědci velmi často měnili kód simulace, použili proto skriptovací jazyk. Samotný simulační program musel být kvůli rychlosti napsán v překládaném jazyce. SWIG byl tedy použit k „provázání“ těchto jazyků.

Aktuální verze je 1.3.25 a můžete ji stáhnout z prdownloads­.sourceforge.net/swig/sw­ig-1.3.25.tar.gz?dow­nload. Kompilace se provádí klasickým „trojhmatem“ ./configure && make && make install. Skriptu configure můžete předat argumenty, kterými vypnete anebo zapnete podporované jazyky (samozřejmě můžete měnit ještě další volby).

A jak tedy SWIG pracuje? Máme vytvořený zdrojový kód modulu (viz např. první příklad) a soubor rozhraní SWIGu (SWIG interface file), který má příponu  i.

// spam.i
%module spam

int gcd(int,int);
void print_data(char *, char *, char *); 

Příkazem swig -python spam.i vytvoříme wrappery modulu. A můžeme překládat …

# swig -python spam.i
# gcc -c spam.c spam_wrap.c -I/usr/include/python2.3/ -I/usr/lib/python2.3/config/
# ld -shared spam.o spam_wrap.o -o spam.so 

Máme za sebou první modul Pythonu, příště si povíme ještě o dalších možnostech nástroje SWIG.

Našli jste v článku chybu?