0

第 1 步。我有一个用于导出一些符号的可执行文件 ( main.exe ) 的导入库文件 ( main.lib )。使用 extern "C" 导出的那些符号。

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

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

现在我尝试使用 Mingw(gcc) 而不是 MS Visual Studio(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

步骤 3x。

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 步时遇到链接器错误。

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。

检查“A_Function_In_main”是否在 libmain.a 中:

nm libmain.a > libmain_dump.txt

libmain_dump.txt 中关于“A_Function_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
4

1 回答 1

0

有没有办法简化这个问题?

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

或者,您可以通过调用 LoadLibrary("bbb.dll") 来实现自己的导入库,然后使用 GetProcAddress("A_Function_In_Main")。但我认为您的真实项目会使这种方法过于昂贵。

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

foo.h

#ifdef FOO_DLL_EXPORTS
#define FOO_DLL_API __declspec(dllexport)
#else
#define FOO_DLL_API __declspec(dllimport)
#endif

extern "C" int FOO_DLL_API foo (int x);

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;
}

测试.cpp

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

int main()
{
    cout << "test.exe foo(3) returns " << foo(3) << endl; // expect 4
    return 0;
}

使用 MSVC 将 foo.cpp 编译成 foo.exe 并导入库 foo.lib。

# compile foo.cpp; define FOO_DLL_EXPORTS
/ZI /nologo /W3 /WX- /Od /Oy- /D "FOO_DLL_EXPORTS" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\foo.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue 
# linker; generate foo.lib
/OUT:"C:\svn_local\0\Users\mku\MinGW_w32\stackoverflow.com\20484904\trunk\msvc2010_build_foo_exe\foo\Debug\foo.exe" /INCREMENTAL /NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"Debug\foo.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\svn_local\0\Users\mku\MinGW_w32\stackoverflow.com\20484904\trunk\msvc2010_build_foo_exe\foo\Debug\foo.pdb" /SUBSYSTEM:CONSOLE /PGD:"C:\svn_local\0\Users\mku\MinGW_w32\stackoverflow.com\20484904\trunk\msvc2010_build_foo_exe\foo\Debug\foo.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"foo.lib" /MACHINE:X86 /ERRORREPORT:QUEUE 

验证没有编译/链接错误。验证 foo.exe 返回码是否为 2,符合预期。

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

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. 

验证 libfoo.a 是否包含 __imp_foo。

nm libfoo.a | grep __imp_foo

00000000 I __imp__foo

使用 gcc 将 test.cpp 编译为 test.exe 并导入库 libfoo.a。

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。

GCC 4.7.2

从http://sourceforge.net/p/mingw/utils/ci/master/tree/reimp/ reimp 来源

于 2013-12-13T10:08:21.423 回答