15

gcc と MinGW をそれぞれ使用して Linux と Windows の両方で共有ライブラリをビルドできるようにするビルド セットアップの生成に問題があります。Linux では、共有ライブラリはコンパイル時にすべての依存関係を解決する必要はありません。一方、これは Windows の場合に当てはまります。問題の設定は次のとおりです。


$ 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

これで、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!

ただし、libbar.dll には foo と bar の両方のシンボルが含まれているため、このアプローチは好きではありません。Linux では、バーの記号のみが含まれます。この分離は、ライブラリが BLAS などの標準的な数値ライブラリに依存している場合に重要です。共有ライブラリを展開して、自分のマシンではなく、ユーザーのマシン上の数値ライブラリの最適化されたバージョンに依存できるようにしたいと考えています。

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

念のため、Linux では gcc 4.6.3 を使用してこれらの例をコンパイルし、Windows では gcc 4.7.2 を使用して mingw-get-inst-20120426.exe をコンパイルしました。

4

1 に答える 1

17

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

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

次に、メインの実行可能ファイルをコンパイルするときに、-lexample_dllオプションを (とともに-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 内のエクスポートされた関数の呼び出し規約はほとんどの場合__stdcall、デフォルト__cdeclではなく です。そのため、DLL を他のソフトウェアで使用できるようにする場合は、それらを にすることをお勧めします__cdecl。ただし、DLL 内のコードとヘッダー ファイルの両方で呼び出し規約が一致している限り、これは厳密には必要ではありません。

于 2013-07-11T19:50:17.983 に答える