使用Linux上的gcc和Windows上的MinGW构build共享库

我在生成一个构build设置时遇到了问题,它允许共享库分别在Linux和Windows中分别使用gcc和MinGW构build。 在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 .co: 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 .co: 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 

但是,当我们尝试构build时,会出现以下错误:

 $ 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 .co: 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中,它只包含bar的符号。 这种分离对于图书馆依赖于BLAS等标准数字图书馆的情况很重要。 我想能够部署共享库,并取决于用户的机器上的数字图书馆的优化版本,而不是我自己的。

在任何情况下,创build共享库的正确过程是什么?在编译时并不是所有的符号都存在?

万一重要,我在Linux上用gcc 4.6.3编译这些例子,在Windows上用gcc 4.7.2编译mingw-get-inst-20120426.exe。

Solutions Collecting From Web of "使用Linux上的gcc和Windows上的MinGW构build共享库"

在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和头文件中的代码都符合调用约定。