2013-07-11 15 views
6

gccとMinGWを使ってLinuxとWindowsの両方で共有ライブラリを構築できるビルド設定の生成に問題があります。 Linuxでは、共有ライブラリはコンパイル時にすべての依存関係を解決する必要はありません。これはWindowsの場合と同じです。ここでは、問題設定は次のとおりです。Linuxでgcc、WindowsでMinGWを使って共有ライブラリを構築する


$ 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 

さて、Linuxでは、これはコンパイルし、うまく動作します:

$ 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! 

は、Windowsでは、我々はマイナーであるDLLにそう変更する必要があると罰金:

$ 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 

ただし、ビルドしようとすると、次のエラーが表示されます。

$ 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 

今、私たちは単にlibbar.dllへのfoo.oからオブジェクトを含めることでエラーを修正することができますlibbar.dllは今の記号が含まれているので

$ 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! 

、私はこのアプローチを好きではありませんフーとバーの両方のために。 Linuxでは、barのシンボルしか含まれていません。この分離は、ライブラリがBLASのような標準的な数値ライブラリに依存している場合に重要です。私は共有ライブラリを配備して、それをユーザのマシン上の数値ライブラリの最適化バージョンに依存させることができたいと思います。

いずれの場合でも、コンパイル時にすべてのシンボルが存在しない共有ライブラリを作成する適切な手順は何ですか?

重要な場合は、これらの例をLinuxの場合はgcc 4.6.3、Windowsの場合はgcc 4.7.2のmingw-get-inst-20120426.exeでコンパイルしました。

+0

'foo.h'と' bar.h'の両方で、必要な '__declspec(dllimport)'と '__declspec(dllexport)'がありません。定義されたEXPORT #elifの 'の#if()は(可視性( "デフォルト"))__ELF__ の#define APIの__attributeを定義し の#define APIの__declspec(のdllexport) の#else の#define APIの__declspec(dllimportの) #endifの:ような何か' ' 'foo.c'と' bar.c'に '#define EXPORT'があります。 – bit2shift

+0

[this](https://github.com/bit2shift/r3dVoxel/blob/master/inc/r3dVoxel/r3vABI.hpp#L7-L13)のようなものですが、C++の構造体である 'extern" C "はありません。 – bit2shift

答えて

8

Windowsでは、DLL用にのインポートライブラリを作成する必要があります。インポートライブラリは静的ライブラリのように見えますが、必要なシンボルはすべて定義されていますが、実際の関数実装はありません。スタブがあります。インポートライブラリは、静的リンクを回避しながら「未定義参照」エラーを解決します。

MinGWでインポートライブラリを作成するには、hereの指示に従ってください。重要な点は、DLLをビルドするときに、インポートライブラリlibexample_dll.aを生成するために、-Wl,--out-implib,libexample_dll.aオプションをリンカーに渡す必要があることです。

メイン実行可能ファイルをコンパイルするときに、オプション(-L.)を使用してインポートライブラリにリンクします。あなたのコードを持つので、私はこれは動作するはずだと思う:

また
all: foo.o bar.o main.o 
    gcc -shared foo.o -o libfoo.dll -Wl,--out-implib,libfoo.a 
    gcc -shared bar.o foo.o -o libbar.dll -Wl,--out-implib,libbar.a 
    gcc main.o -Wl,-rpath=. -L. -lbar -lfoo -o main 

、Windows上の点に注意してください、あなたのDLLにはしたいので、もし、DLLでエクスポート関数の呼び出し規約は、ほとんどいないデフォルト__cdecl常に__stdcallです他のソフトウェアでも使用できる場合は、__cdeclとすることをおすすめします。 DLLのコードとヘッダーファイルの両方が呼び出し規約が一致している限り、厳密には必須ではありません。

+2

これはうまくいった。マイナーなコメントとして、インポートライブラリを使用するために、 "gcc -shared bar.o -L。-lfoo -o libbar.dll -Wl、 - out-implib、libbar.a"を使用しました。 – wyer33

+0

呼び出し規約をすべて間違っています。 Win32 API規約は '__stdcall' **ですが、これはもっとも使用される規約ではありません**、' __cdecl'はです。最良の結果を得るためには、空の呼び出し規約(別名暗黙の '__cdecl')を' extern "C" 'と組み合わせて使用​​するべきです:.defファイルを必要とせずにmanglingする必要はありません。不快なもの)。 – bit2shift

+0

'__stdcall'は主に、' CALLBACK'マクロを使用して、Win32ウィンドウサブシステムでメッセージ処理用のコールバックを定義する際に、ユーザコードで明示的に使用されます。 – bit2shift

関連する問題