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.

Doba čtení: 3 minuty

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.

MIF18 tip v článku témata

// 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?