Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]11909[/thread]

Windows: Perl-Modul einer DLL mit XS

Leser: 1


<< >> 9 Einträge, 1 Seite
Gast Gast
 2008-05-24 01:58
#110205 #110205
Hallo Forum,
ich versuche gerade unter Windows eine C-Funktion die in einer DLL abgelegt ist mittels XS von Perl aus aufzurufen.
Als Compiler verwende ich den MinGW mit dmake.

Bei "dmake test" bekomme ich jedoch folgende Fehlermeldung:

Code: (dl )
1
2
3
4
5
#   Failed test 'use HalloDLLtest;'
# at t/HalloDLLtest.t line 9.
# Tried to use 'HalloDLLtest'.
t/HalloDLLtest....NOK 1/1# Error: Can't load 'D:\c\hallo_dll\perl_use_dll\HalloDLLtest\blib\arch/auto/HalloDLLtest/
HalloDLLtest.dll' for module HalloDLLtest: load_file:Die angegebene Prozedur wurde nicht gefunden at C:/Perl/lib/DynaLoader.pm line 229.


Mein Makefile.PL habe ich folgendermaßen ergänzt:

LIBS => ['-lHalloDLLtest.a'], # e.g., '-lm'
DEFINE => '-DBUILD_DLL', # e.g., '-DHAVE_SOMETHING'

Die HalloDLLtest.a habe ich mir beim gcc mit der Option "--out-implib,HalloDLLtest.a" erzeugen lassen.

Meine HalloDLLtest.h sieht so aus:

[cpp]
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif

EXPORT int add_dll(int a, int b);[/cpp]

Meine .xs so:
[cpp]
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "HalloDLLtest.h"
MODULE = HalloDLLtest PACKAGE = HalloDLLtest

int add_dll(a, b);
int a
int b
PROTOTYPE: $$
CODE:
RETVAL = add_dll(a, b);
OUTPUT:
RETVAL
[/cpp]

Eine dll wird bei dmake auch im entsprechenden Verzeichnis erzeugt.
Ich hoffe, dass ich mit meiner .a Datei bei LIBS richtig liege, so ganz verstanden wie das nachher eingebunden wird habe ich das auch noch nicht.

Hat jemand vielleicht einen Hinweis wo der Fehler liegen könnte?

Danke und Gruß
Thomas
betterworld
 2008-05-24 05:38
#110208 #110208
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
Gast+2008-05-23 23:58:08--
LIBS => ['-lHalloDLLtest.a'], # e.g., '-lm'

Ich hoffe, dass ich mit meiner .a Datei bei LIBS richtig liege

Das sieht in der Tat etwas seltsam aus. Versuch doch mal, das '-l' da wegzulassen. Und eventuell den Pfad zu der Datei mit anzugeben. Aber ich hab keine Ahnung, wie das unter Windows laeuft :)
Aber ich frage mich, warum Du ueberhaupt eine .a-Datei brauchst, wo Du doch Dein eigentliches Ziel als das Aufrufen einer Funktion aus einer DLL-Datei beschrieben hast.
Gast Gast
 2008-05-24 14:20
#110213 #110213
In der .a-Datei ist ja meine C-Funktion. D.h. ich habe erst in einem anderen Projekt aus der HalloDLLtest.c die Bibliothek HalloDLLtest.a erzeugt.

Um die Probleme mit den Pfaden zu umgehen, habe ich dann die Dateien HalloDLLtest.h und HalloDLLtest.a in mein Perl-Verzeichnis kopiert.
Würde ich die .a in meinem Makefile.PL nicht angeben, wäre die eigentliche C-Funktion gar nicht bekannt.
(dann kommt bei dmake:
HalloDLLtest.o:HalloDLLtest.c:(.text+0x122): undefined reference to `add_dll')

Gebe ich die .a-Datei an so wird bei dmake ja auch dann eine dll erzeugt, nur scheint an dieser etwas nicht ganz korrekt zu sein.

Eine Beschreibung wie man das unter Linux mittels einer .so-Datei macht würde mir auch weiterhelfen.
Dann könnte ich das da erstmal testen und mir die Compileraufrufe ansehen. Evtl. kann ich das dann auf Windows umsetzen.

betterworld
 2008-05-24 14:26
#110214 #110214
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
Gast+2008-05-24 12:20:40--
Würde ich die .a in meinem Makefile.PL nicht angeben, wäre die eigentliche C-Funktion gar nicht bekannt.
(dann kommt bei dmake:
HalloDLLtest.o:HalloDLLtest.c:(.text+0x122): undefined reference to `add_dll')

Ich meinte nicht, dass Du die .a-Datei gar nicht angeben sollst, sondern vielmehr das "-l" vor dem Dateinamen weglassen versuchen koenntest.

Quote
Eine Beschreibung wie man das unter Linux mittels einer .so-Datei macht würde mir auch weiterhelfen.

Hm, also in perlxstut wird es ja eigentlich beschrieben. Da wird -lm verwendet, was sich dann auf die Datei /usr/lib/libm.so oder ähnlich bezieht. Wenn die Datei nicht in /usr/lib oder einem anderen Systembibliotheksverzeichnis liegt, kann man bei LIBS noch -L/pfad/verzeichnis angeben.
murphy
 2008-05-24 18:21
#110230 #110230
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
betterworld+2008-05-24 03:38:48--
[...]
Aber ich frage mich, warum Du ueberhaupt eine .a-Datei brauchst, wo Du doch Dein eigentliches Ziel als das Aufrufen einer Funktion aus einer DLL-Datei beschrieben hast.


Aufgrund dümmlichen Designs braucht man unter Windows um gegen eine DLL zu linken eine statische Importbibliothek, die Einsprungpunkte für die eigentlichen Funktionen in der DLL zur Verfügung stellt.

Deswegen erwähnt der OP auch, dass er diese statische Bibliothek mit der zum Generieren von Importbibliotheken gedachten Option --out-implib des Linkers erzeugt hat.

Für mich sieht es eigentlich so aus, als wäre auf der Perl- und XS-Seite alles in Ordnung. Obwohl bei -lHalloDLLtest.a eigentlich das -l nicht hingehört – aber wenn der Linker da nicht mault, wird es wohl funktionieren. In der DLL selbst hingegen scheint einfach die Implementation von add_dll zu fehlen.

Meine Empfehlung wäre daher, zunächst einmal die Kommandos zu überprüfen, mit denen die DLL gelinkt wurde bzw. mit objdump nachzusehen, ob die Funktion add_dll überhaupt in der DLL vorhanden ist.
When C++ is your hammer, every problem looks like your thumb.
Gast Gast
 2008-05-24 19:54
#110236 #110236
murphy+2008-05-24 16:21:04--
Meine Empfehlung wäre daher, zunächst einmal die Kommandos zu überprüfen, mit denen die DLL gelinkt wurde bzw. mit objdump nachzusehen, ob die Funktion add_dll überhaupt in der DLL vorhanden ist.


Also in der erzeugten DLL scheint zumindest meine Funktion add_dll vorhanden zu sein. Ein objdump -p ergibt u.a.:
Code: (dl )
1
2
3
4
5
        DLL Name: HalloDLLtest.dll
vma: Hint/Ord Member-Name Bound-To
6374 0 add_dll

00006050 00000000 00000000 00000000 00000000 00000000


Die Kompileroptionen die bei dmake versuche ich gerade zu verstehen, aber jeden Schalter kenne ich auch nicht, bzw. muss jeden im Manual nachsehen. Falls hier jemand vielleicht aus dem Kopf weiß wie das aussehen muss, stell ich die Ausgaben mal rein.

Die vorgehensweise wie bei dmake eine DLL erzeugt wird unterscheidet sich aber von der, mit der ich meine eigene erzeugt habe.
Gast Gast
 2008-05-24 19:59
#110237 #110237
Halt, im Abschnitt der Name Pointer Tabelle steht nur folgendes:
Code: (dl )
1
2
3
[Ordinal/Name Pointer] Table
[ 1] _boot_HalloDLLtest
[ 0] boot_HalloDLLtest


Also scheint doch was zu fehlen.
Gast Gast
 2008-05-24 21:28
#110241 #110241
Bin etwas weitergekommen:
Mittels dmake wird eine DLL nach der 'alten' Vorgehensweise über ein zusätzliches def-File, in dem alle Funktionen in der DLL aufgelistet sind, erstellt.

In dieser .def Datei steht nun:

EXPORTS
boot_HalloDLLtest
_boot_HalloDLLtest = boot_HalloDLLtest

Diese Datei wird beim make-Vorgang über folgenden Eintrag erstellt:

Code: (dl )
1
2
3
4
5
# --- MakeMaker dlsyms section:

HalloDLLtest.def: Makefile.PL
$(PERLRUN) -MExtUtils::Mksymlists \
-e "Mksymlists('NAME'=>\"HalloDLLtest\", 'DLBASE' => '$(BASEEXT)', 'DL_FUNCS' => { }, 'FUNCLIST' => [], 'IMPORTS' => { }, 'DL_VARS' => []);"


Diesen Eintrag habe ich jetzt testweise mal auskommentiert, und das .def-File händisch angelegt und um die anderen Funktionen (also auch add_dll) ergänzt.

Zumindest der Standard-Test mit dmake test funktioniert.
Bei dem Versuch die Funktion aufzurufen bleibt das Programm hängen und ich kanns nur noch mit SIGINT beenden.

Mir scheint, das Problem ist sehr MinGW-Compiler spezifisch...
murphy
 2008-05-24 21:34
#110242 #110242
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Mir ist gerade noch aufgefallen, dass auch diese Zeile beim Bauen Deines XS-Codes vermutlich Käse ist:
Gast+2008-05-23 23:58:08--
[...]
DEFINE => '-DBUILD_DLL', # e.g., '-DHAVE_SOMETHING'
[...]


Wegen
[cpp]
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
[...]
[/cpp]
führt sie nämlich dazu, dass add_dll genau die falschen Linkageattribute bekommt.

Beim Bauen der DLL selbst hingegen, sollte dieses Präprozessormakro auf jeden Fall definiert sein. Ausserdem würde ich sicherheitshabler noch C-Linkage für die Funktion add_dll angeben, falls man den Header mal durch einen C++Compiler jagt. Und man sollte Praeprozessormakros wie das BUILD_DLL tunlichst nicht so generisch benennen, weil sich sonst mehrere Bibliotheksheader ganz schnell in die Quere kommen können.

Also besser so, das ist auch gleich portabler:
[cpp]
/**
* @file hallo.h
*/
#ifndef _HALLO_H_
#define _HALLO_H_

#ifdef HALLO_SHARED_LIB
# ifdef _HALLO_EXPORTS_
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
# define HALLO_EXPORT __declspec(dllexport)
# else
# define HALLO_EXPORT
# endif
# else
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
# define HALLO_EXPORT __declspec(dllimport)
# else
# define HALLO_EXPORT
# endif
# endif /* _HALLO_EXPORTS_ */
#else
# define HALLO_EXPORT
#endif /* HALLO_SHARED_LIB */

#ifdef __cplusplus
extern "C" {
#endif

HALLO_EXPORT int hallo_add(int a, int b);

#ifdef __cplusplus
}
#endif

#endif /* _HALLO_H_ */
[/cpp]
und
[cpp]
/**
* @file hallo.c
*/
#define _HALLO_EXPORTS_
#include "hallo.h"

int hallo_add(int a, int b) {
return a + b;
}
[/cpp]

Compilerkommando zum Bau der DLL:
Code: (dl )
gcc -Wall -O2 -DHALLO_SHARED_LIB -fPIC -shared hallo.c -o hallo.dll -Wl,--out-implib=libhallo.a


Testprogramm:
[cpp]
/**
* @file test.c
*/
#include <stdlib.h>
#include <stdio.h>

#include "hallo.h"

int main(int nargs, char **args) {
const int a = 1, b = 2;

printf("hallo_add(%d, %d) = %d\n", a, b, hallo_add(a, b));

return EXIT_SUCCESS;
}
[/cpp]

Compilerkommando zum Benutzen der DLL:
Code: (dl )
gcc -Wall -O2 -DHALLO_SHARED_LIB test.c -o test.exe -L. -lhallo


Warnhinweis: Ich habe kein MinGW zum Testen zur Hand. Die Compilerkommandos sind vielleicht nicht völlig korrekt.
When C++ is your hammer, every problem looks like your thumb.
<< >> 9 Einträge, 1 Seite



View all threads created 2008-05-24 01:58.