当前位置: 首页 > 面试题库 >

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

左丘恩
2023-03-14
问题内容

我在生成允许分别使用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中,它仅包含bar符号。对于库依赖于某些标准数值库(例如BLAS)的情况,这种分离非常重要。我希望能够部署共享库,并使其取决于用户计算机上而不是我自己计算机上数字库的优化版本。

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

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


问题答案:

在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可被其他软件使用,则建议使它们成为DLL
__cdecl。但这并不是严格要求的,只要DLL中的代码和头文件中的调用约定是一致的即可。



 类似资料:
  • 问题内容: 我正在尝试通过Windows 7计算机上的Docker容器设置开发人员环境。 我已经为Windows安装了Docker工具箱。 我有一个包含Apache和PHP 5.6的映像,这里是: 该映像已创建,当我在Docker快速入门终端中运行“ docker映像”时可以看到它。 在我的apache-config.conf中,我只有一个小的虚拟主机,仅使用index.php文件即可访问测试网站

  • 问题内容: 我正在尝试使用通过Cmake创建的Makefile在Linux中编译共享库,但是运行make会出现以下错误: 我在CMakeLists.txt中提供以下命令,以便说我想要共享(.so)库: 为了避免上面显示的-fPIC错误,我还需要指定什么? 提前谢谢 问题答案: 需要使用-fPIC编译boost库:请看一下:如何使用boost.python中的-fPIC编译静态库。 尝试在项目中按c

  • 我们有一个内部开发的基于客户机/服务器的应用程序。客户端和服务器通过TCP/IP连接与特定于应用程序的协议进行通信。客户端在Windows上运行,服务器在Linux上运行。所有计算机都位于相同的Active Directory/Kerberos域/领域中。 目前,用户在启动应用程序时输入用户名和密码。服务器检查用户名和密码(身份验证)。服务器还根据用户名确定对资源的访问(授权)。 我们希望向应用程

  • 问题内容: 这是使用g ++ 进行动态共享库编译的后续版本。 我正在尝试在Linux上的C++中创建一个共享的类库。当我尝试使用库中定义的类时,我的问题开始了。我链接到的第二篇教程展示了如何加载用于创建库中定义的类的对象的符号,但是没有_使用_ 这些对象来完成任何工作。 有谁知道用于创建共享C ++类库的更完整的教程,该教程还显示了如何在单独的可执行文件中 使用 这些类?一个非常简单的教程,显示了

  • 我已经为Windows安装了Docker工具箱。 我有一个包含Apache和PHP5.6的图像,下面是: 创建了这个映像,我可以在Docker quickstart终端中运行“Docker映像”时看到它。

  • 问题内容: 我有一个Java应用程序的Maven构建,可以通过键入相同的命令在Linux或Windows上成功运行。 然而,使用Jenkinsfile方法设置此生成,在Linux上文件需要包含和Windows 。 如果在Windows上正确配置了路径和工具,则日志显示: 有没有办法让单个Jenkinsfile允许在两种环境中构建? 问题答案: 管道脚本可以包含常规代码,因此允许分支。您可以使用并根