gpt4 book ai didi

c - 在 Linux 上使用 gcc 并在 Windows 上使用 MinGW 构建共享库

转载 作者:IT王子 更新时间:2023-10-29 00:06:06 25 4
gpt4 key购买 nike

我在生成build设置时遇到了问题,该设置允许分别使用 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下,我们需要将so改成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 中,它只包含 bar 的符号。这种分离对于库依赖于某些标准数字库(如 BLAS)的情况很重要。我希望能够部署共享库,并让它依赖于用户机器上数值库的优化版本,而不是我自己的。

无论如何,在编译时创建并非所有符号都存在的共享库的正确过程是什么?

以防万一,我在 Linux 上使用 gcc 4.6.3 编译了这些示例,在 Windows 上使用 gcc 4.7.2 编译了 mingw-get-inst-20120426.exe。

最佳答案

在 Windows 上,您需要为 DLL 创建一个导入库。导入库看起来像静态库,因为它定义了所有需要的符号,但它没有实际的函数实现,它只有 stub 。导入库将解决“ undefined reference ”错误,同时避免静态链接。

要使用 MinGW 创建导入库,请遵循说明 here .关键是在构建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 中的代码和头文件中的代码都同意调用约定是什么即可。

关于c - 在 Linux 上使用 gcc 并在 Windows 上使用 MinGW 构建共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17601949/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com