tutorials.de Buch-Aktion 05/2012
RSS-Feed anzeigen

Dem Dennis sein Blogdingen da...

Swingen mit Swig

Bewerten
von Dennis Wronka am 22.03.09 um 14:24 (1753 Hits)
Wie ich ja bereits berichtet habe befasse ich mich zur Zeit mit C#.
Heute kam dann mal die Frage auf wie denn Libraries die eigentlich fuer C/C++ sind in C# genutzt werden. Wie bei GTK#, welches ja auf GTK aufsetzt.

Hab also gesucht, und gefunden habe ich SWIG - Simplified Wrapper and Interpreter Generator.
Bekannt war mir Swig bereits durch meine Arbeit an EasyLFS. Jedoch nur als Abhaengigkeit fuer irgendeines der SELinux-Pakete.

Entsprechend hab ich also heute mal was genauer auf Swig geschaut und etwas herumgespielt.

Kurz erklaert: Mit Swig nimmt man eine Library, am besten als Source, und legt eine Interface-Beschreibung an.
Diese jagt man durch Swig und kompiliert die Library in beiden Sprachen.
Es geht aber auch mit fertig kompilierten Libraries. Man muss halt nur einen Weg haben die Schnittstellen beschreiben zu koennen.

Hier mal mein kleines Script "sharpify.sh", welches ich dafuer gebastelt habe:
sharpify.sh:
Code bash:
1
2
3
4
5
6
#!/bin/sh
swig -csharp ${1}.i
gcc -c -fpic ${2} ${1}.c ${1}_wrap.c
gcc -shared ${2} ${1}.o ${1}_wrap.o -o lib${1}.so
gmcs -target:library ${1}.cs ${1}PINVOKE.cs
rm ${1}{,_wrap}.o ${1}_wrap.c ${1}{,PINVOKE}.cs

Zum Test hab ich in C eine kleine Library geschrieben die wiederum auf der LibClamAV aufsetzt und diese dann mittels Swig nach C# portiert.

Dazu sei natuerlich noch gesagt dass Swig sich nicht auf C# als Ziel-Sprache beschraenkt.
Moegliche Ziele sind, unter anderem, PHP 4 und 5, TCL, Java oder Python.

Hier mal der von mir erstellte C-Code, zum Teil basierend auf einem aelteren C-Projekt wo ich mal mit der LibClamAV gearbeitet habe.
ClamScan.c:
Code c:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <stdio.h>
#include <clamav.h>
 
struct cl_node *node;
const char *virname;
int ScanRet;
 
char *DbDir(void)
{
  return cl_retdbdir();
}
 
int LoadDb(char *DbPath)
{
  int ret;
  unsigned int signo;
 
  ret=cl_loaddbdir(DbPath,&node,&signo);
 
  if (ret)
  {
    return 0;
  }
 
  ret=cl_build(node);
 
  if (ret)
  {
    return 0;
  }
 
  return signo;
}
 
int ScanFile(char *FilePath)
{
  struct cl_limits limits;
 
  ScanRet=cl_scanfile(FilePath,&virname,NULL,node,&limits,CL_SCAN_STDOPT | CL_SCAN_BLOCKMAX);
  if (ScanRet==CL_VIRUS)
  {
    return 1;
  }
  else if (ScanRet==CL_CLEAN)
  {
    return 0;
  }
  else
  {
    return -1;
  }
}
 
const char *GetVirus(void)
{
  return virname;
}
 
const char *GetError(void)
{
  return cl_strerror(ScanRet);
}

Dazu dann die folgende Interface-Beschreibung:
ClamScan.i:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
%module ClamScan
%{
        extern char *DbDir(void);
        extern int LoadDb(char *DbPath);
        extern int ScanFile(char *FilePath);
        extern const char *GetVirus(void);
        extern const char *GetError(void);
%}
 
extern char *DbDir(void);
extern int LoadDb(char *DbPath);
extern int ScanFile(char *FilePath);
extern const char *GetVirus(void);
extern const char *GetError(void);

Mit dem Shell-Script oben hab ich dann sowohl die Shared Library LibClamScan.so als auch die .NET-Assembly ClamScan.dll erstellt.

Hier nun das C#-Programm in dem ich meine gestutzte C#-Version der LibClamAV teste.
Code csharp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
 
namespace ClamTest
{
    class MainClass
    {
        public static string Scan(string FilePath)
        {
            int ScanRet=ClamScan.ScanFile(FilePath);
            switch (ScanRet)
            {
            case 1:
                return ClamScan.GetVirus();
            case 0:
                return "Clean";
            case -1:
                return ClamScan.GetError();
            }
            return "";
        }
 
        public static void Main(string[] args)
        {
            ClamScan.LoadDb(ClamScan.DbDir());
            Console.WriteLine(Scan("/home/dennis/sharpify.sh"));
            Console.WriteLine(Scan("/home/dennis/doll.com"));
            Console.WriteLine(Scan("/home/dennis/doll.exe"));
        }
    }
}

Die drei Dateien die ich im Test scanne sind zum einen das oben gezeigte Shell-Script, gefolgt von einem Virus der mal den Weg in meine Mailbox gefunden hat, und anschliessend eine nicht-existente Datei.

Das funktioniert nun alles soweit ganz gut, und war auch recht einfach. Mal davon abgesehen dass ich hier erst eine eigene Library basierend auf LibClamAV geschrieben habe weil der Weg direkt ueber LibClamAV nicht erfolgreich war. Dieses Problem schiebe ich aber auf meine eingeschraenkten Faehigkeiten in C und bei der Erstellung der Interface-Beschreibung als auf Swig oder C#.

"Swingen mit Swig" bei Twitter speichern "Swingen mit Swig" bei Facebook speichern

Kategorien
Programming

Kommentare

  1. Avatar von Matthias Reitinger
    Jetzt bin ich dir aber schon ein bisschen beleidigt, dass du Ruby nicht in deine Auswahl von unterstützten Sprachen aufgenommen hast

    Eine Alternative zu einem solchen direkten Wrapper wäre vielleicht FFI. Allerdings weiß ich nicht, ob es da für C# was entsprechendes gibt.

    PS: So würde das in etwa in Ruby via FFI aussehen: http://pastie.org/423855