C++ 使用从导入库(.lib)转换的库文件(.a)使用gcc构建dll

C++ 使用从导入库(.lib)转换的库文件(.a)使用gcc构建dll,c++,visual-studio,gcc,dll,dlltool,C++,Visual Studio,Gcc,Dll,Dlltool,步骤1。我有一个导入lib文件(main.lib),用于导出一些符号的可执行文件(main.exe)。使用外部“C”导出的符号 步骤2。我还有一个源文件(extra.cpp),它导出一些额外的函数。我从中生成一个静态链接库(extra.lib),并将main.lib包含在其中,因为这些额外函数是从main.exe导出的用户 第3步。构建一个dll(bbb.dll),链接到此库(extra.lib),从main.exe调用这些额外函数。 (请注意,bbb.dll首先由main.exe加载和使用。)

步骤1。我有一个导入lib文件(main.lib),用于导出一些符号的可执行文件(main.exe)。使用外部“C”导出的符号

步骤2。我还有一个源文件(extra.cpp),它导出一些额外的函数。我从中生成一个静态链接库(extra.lib),并将main.lib包含在其中,因为这些额外函数是从main.exe导出的用户

第3步。构建一个dll(bbb.dll),链接到此库(extra.lib),从main.exe调用这些额外函数。 (请注意,bbb.dll首先由main.exe加载和使用。)

现在我尝试使用Mingw(gcc)而不是MS-visualstudio(cl)重复步骤2和3。让我们称之为步骤2x和3x。 由于main.exe是一个包含许多文件的大型项目。。。从源代码构建libmain.a不是一个好选项,我发现main.lib可以使用以下命令转换为.a文件:

reimp -d main.lib
dlltool -k -d main.def -l libmain.a
# reimp creates the .def file. 
# dlltool uses the .def to create the .a that is linked in to the app. 
第2x步。

gcc -c -o extra.o -O1 -s -x c++ extra.cpp
ar rs libextra.a extra.o
ar rs libextra.a libmain.a
g++ -O2 -o bbb.dll -shared -x c++ bbb.cpp  -static-libgcc -static-libstdc++  -Wl,-s -Wl,--kill-at,--export-all-symbols,--enable-stdcall-fixup -Wl,--large-address-aware -lextra 
第3步。

gcc -c -o extra.o -O1 -s -x c++ extra.cpp
ar rs libextra.a extra.o
ar rs libextra.a libmain.a
g++ -O2 -o bbb.dll -shared -x c++ bbb.cpp  -static-libgcc -static-libstdc++  -Wl,-s -Wl,--kill-at,--export-all-symbols,--enable-stdcall-fixup -Wl,--large-address-aware -lextra 
我在第3x步得到链接器错误

libmain.a(lextra.o):extra.cpp:(.text+0x38): undefined reference to `A_Function_In_main'
这是名称差异问题吗?

或者甚至可以通过这种方式使用gcc构建bbb.dll吗?

我做错了什么?

我正在Windows 7上使用Visual Studio 2012。MinGW符合gcc 4.6.1

检查libmain中是否有“函数”。A:

libmain_dump.txt中有关“A_函数_in_main”的文本块

dshms00350.o:
00000000 b .bss
00000000 d .data
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$6
00000000 i .idata$7
00000000 t .text
00000000 T A_Function_In_main
00000000 I __imp_A_Function_In_main
         U _head_libmain_a

有没有办法简化这个问题

虽然在大的主程序和额外的DLL之间似乎存在一些循环依赖关系,但我假设您只是在主程序中使用回调函数。由于没有源代码或您正在使用的MSVC和gcc的相同版本,我的努力受到了阻碍。(我有MS Visual Studio 2010和mingw gcc-4.7.2),但问题的关键似乎是将MS生成的导入库转换为使用gcc

或者,您可以通过调用LoadLibrary(“bbb.dll”)实现自己的导入库,然后使用GetProcAddress(“A_函数_In_Main”)。但我认为你真正的项目使这种方法的成本高得让人望而却步

作为诊断,使用更简单的测试台测试reimp导入库:

福安

foo.cpp

// define FOO_DLL_EXPORTS when building foo.cpp

#include "foo.h"
#include <iostream>
using std::cout;
using std::endl;

extern "C" int FOO_DLL_API foo (int x)
{
    return x + 1;
}
int main()
{
    cout << "foo.exe foo(1) returns " << foo(1) << endl; // expect 2
    return 0;
}
验证没有编译/链接错误。 验证foo.exe返回代码是否如预期的那样为2

使用mingw-utils-reimp将foo.lib转换为libfoo.a,以便与gcc一起使用。(假设真正的foo.cpp无法重建,尽管在这个较小的示例中,foo.cpp可以使用gcc-4.7.2重建)

验证libfoo.a是否包含_imp_foo

nm libfoo.a | grep __imp_foo

00000000 I __imp__foo
使用gcc将test.cpp编译为带有导入库libfoo.a的test.exe

g++.exe test.o  -o test.exe -static -static-libgcc -static-libstdc++ -L"C:/MinGW/lib"  /MinGW/lib/gcc/mingw32/4.7.2/libstdc++.a /MinGW/lib/gcc/mingw32/4.7.2/libgcc.a  libfoo.a
验证没有编译/链接错误。 验证test.exe返回代码是否为预期的4

这对我的系统有效

Microsoft Visual Studio 2010版本10.0.40219.1 SP1Rel

通用条款4.7.2


哪些工具重新映射源,我可以使用这些工具查看导出的名称以及它们是如何被破坏的?为了验证,dumpbin/exports bbb.dll(在visual studio tools命令提示符下)将列出dll的入口点。DLL名称永远不应该被名称弄乱(您确实提到了导出每个函数的“C”),因为DLL必须在所有编译器中运行。但实际的问题是使用MinGW构建bbb.DLL,在链接阶段失败,对不对?gnu binutils:nm libextra.a>libextra_dump.txt,并验证主函数中的函数确实在libextra.a中?谢谢。DLL名称不应被破坏,因为使用了外部“C”,是的。
reimp -d foo.lib
# reimp creates the foo.def file. 
dlltool -k -d foo.def -l libfoo.a
# dlltool uses the .def to create the .a that is linked in to the app. 
nm libfoo.a | grep __imp_foo

00000000 I __imp__foo
g++.exe test.o  -o test.exe -static -static-libgcc -static-libstdc++ -L"C:/MinGW/lib"  /MinGW/lib/gcc/mingw32/4.7.2/libstdc++.a /MinGW/lib/gcc/mingw32/4.7.2/libgcc.a  libfoo.a