Building a dll with a gcc using a library file (.a) converted from import library (.lib)

5.2k views Asked by At

Step 1. I have an import lib file (main.lib) for my executable (main.exe) which exports some symbols. Those symbols exported using extern "C".

Step 2. I also have a source file (extra.cpp) which exports some extra functions. I generate a static linking library (extra.lib) from it, and I include main.lib into it as those extra functions are the users of exports from main.exe.

Step 3. A dll (bbb.dll) is built linking with this library (extra.lib) to call those extra functions from main.exe. (note that bbb.dll is loaded and used by main.exe in first place.)

Now I'm trying to repeat steps 2 and 3 using Mingw(gcc) instead of MS Visual Studio(cl). Let's call it Step 2x and 3x. Since main.exe is a big project with many files ... the building libmain.a from sources is not a good option, I found here that main.lib can be converted to .a file using following commands:

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. 

Step 2x.

gcc -c -o extra.o -O1 -s -x c++ extra.cpp
ar rs libextra.a extra.o
ar rs libextra.a libmain.a

Step 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 

I'm getting linker errors at step 3x.

libmain.a(lextra.o):extra.cpp:(.text+0x38): undefined reference to `A_Function_In_main'

Is it a name mangling difference problem?

Or is it even possible to build bbb.dll using gcc this way?

What do I do wrong?

I'm using Visual Studio 2012 on Windows 7. MinGW with gcc 4.6.1.

Checking if 'A_Function_In_main' is in libmain.a:

nm libmain.a > libmain_dump.txt

The block of text in libmain_dump.txt regarding '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
1

There are 1 answers

0
MarkU On

Is there a way to simplify this question?

Although there seems to be some circular dependency between the big main program and the extra DLL, I assume you're just using a callback function within main. My efforts are hampered by not having source code or the same versions of MSVC and gcc you are using. (I have MS Visual Studio 2010 and mingw gcc-4.7.2) But the crux of the problem seems to be converting the MS generated import library to work with gcc.

Alternatively, you could implement your own import library by calling LoadLibrary("bbb.dll") and then use GetProcAddress("A_Function_In_Main"). But I assume your real project makes this approach prohibitively expensive.

As a diagnostic, test the reimp import library with a simpler test bench:

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

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

Use MSVC to compile foo.cpp into foo.exe and import library 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 

Verify no compile/link errors. Verify foo.exe return code is 2 as expected.

Use mingw-utils reimp to convert foo.lib into libfoo.a for use with gcc. (Assuming the real foo.cpp was impractical to rebuild, although in this smaller example foo.cpp can be rebuilt with 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. 

Verify libfoo.a contains __imp_foo.

nm libfoo.a | grep __imp_foo

00000000 I __imp__foo

Use gcc to compile test.cpp to test.exe with import library 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

Verify no compile/link errors. Verify test.exe return code is 4 as expected.

This works on my system.

Microsoft Visual Studio 2010 Version 10.0.40219.1 SP1Rel.

gcc 4.7.2

reimp sources from http://sourceforge.net/p/mingw/utils/ci/master/tree/reimp/