Ich habe Probleme beim Generieren eines Build-Setups, mit dem gemeinsam genutzte Bibliotheken sowohl unter Linux als auch unter Windows mit gcc bzw. MinGW erstellt werden können. Unter Linux muss eine gemeinsam genutzte Bibliothek nicht alle Abhängigkeiten zur Kompilierzeit auflösen; während dies in Windows der Fall zu sein scheint. Hier die Problemstellung:
$ cat foo.h
#ifndef FOO_H
#define FOO_H
void printme();
#endif
$ cat foo.c
#include "foo.h"
#include <stdio.h>
void printme() {
printf("Hello World!\n");
}
$ cat bar.h
#ifndef BAR_H
#define BAR_H
void printme2();
#endif
$ cat bar.c
#include "bar.h"
#include "foo.h"
void printme2() {
printme();
printme();
}
$ cat main.c
#include "bar.h"
int main(){
printme2();
}
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
Nun, unter Linux wird dies kompiliert und läuft einwandfrei:
$ make
gcc -fPIC -c foo.c
gcc -fPIC -c bar.c
gcc -fPIC -c main.c
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
In Windows müssen wir so zu dll ändern, was klein und fein ist:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
Wenn wir jedoch versuchen zu bauen, erhalten wir die folgende Fehlermeldung:
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
bar.o:bar.c:(.text+0x7): undefined reference to `printme'
bar.o:bar.c:(.text+0xc): undefined reference to `printme'
collect2.exe: error: ld returned 1 exit status
make: *** [all] Error 1
Jetzt können wir den Fehler beheben, indem wir einfach die Objekte aus foo.o in libbar.dll einfügen:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
Ich mag diesen Ansatz jedoch nicht, da libbar.dll jetzt Symbole für foo und bar enthält. Unter Linux enthält es nur Symbole für Balken. Diese Trennung ist wichtig für Situationen, in denen eine Bibliothek von einer standardmäßigen numerischen Bibliothek wie BLAS abhängt. Ich möchte in der Lage sein, die gemeinsam genutzte Bibliothek bereitzustellen und sie von der optimierten Version der numerischen Bibliothek auf dem Computer des Benutzers und nicht von meiner eigenen abhängig zu machen.
Was ist in jedem Fall das richtige Verfahren zum Erstellen einer gemeinsam genutzten Bibliothek, in der nicht alle Symbole zur Kompilierzeit vorhanden sind?
Falls es darauf ankommt, ich habe diese Beispiele mit gcc 4.6.3 unter Linux und mingw-get-inst-20120426.exe mit gcc 4.7.2 unter Windows kompiliert.
Ihnen fehlt das Erforderliche
__declspec(dllimport)
Und__declspec(dllexport)
sowohlfoo.h
Undbar.h
. Etwas wie:#if defined __ELF__ #define API __attribute((visibility("default"))) #elif defined EXPORT #define API __declspec(dllexport) #else #define API __declspec(dllimport) #endif
Dann#define EXPORT
Infoo.c
Undbar.c
.– bit2shift
13. September 2017 um 2:58 Uhr
Etwas wie Das aber ohne
extern "C"
bei dem es sich um ein C++-Konstrukt handelt.– bit2shift
13. September 2017 um 3:01 Uhr