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/swig-1.3.25.tar.gz?download. 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.