Building a DLL (error adding symbols: File format not recognized)

Hello,

I am creating a DLL that I want to build as 32-bit version and as 64-bit version. I am using the TDM gcc compiler, but I also want programmers that use visual studio to be able to use it, so after compiling I generate a corresponding .lib file as an alternative to the .a file.

This works very well for the 32 bit version, but it doesn't work for the 64 bit version. To be specific, the linking of the program that should use the DLL fails with the error: "error adding symbols: File format not recognized".

So I dumbed the problem down as far as I could to ensure it is not something else i did wrong, but can't find a cause for this problem.

This is the dumbed down source for the DLL.

DLL header file (main.h):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>

#ifdef BUILD_DLL
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif


#ifdef __cplusplus
extern "C"
{
#endif

void DLL_EXPORT __cdecl SomeFunction(const LPCSTR sometext);

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__ 


DLL implementation file (main.cpp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "main.h"

// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}


I use TDM-GCC-32 version 5.1.0 to build the 32 bit version of the DLL. This gives me libtest_dll_x32.a, libtest_dll_x32.def and test_dll_x32.dll.
Subsequently I use Visual C++ 2015 build tools from the command line to generate a .lib file based on the .def file. Like this:
1
2
3
4
c:
call "C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat" x86
cd C:\temp\test_dll\bin
lib /def:libtest_dll_x32.def /MACHINE:X86 /out:libtest_dll_x32.lib

This gives me libtest_dll_x32.exp and libtest_dll_x32.lib.

For the 64 bit version I do the same:
I use TDM-GCC-64 version 5.1.0 to build the 64 bit version of the DLL. This gives me libtest_dll_x64.a, libtest_dll_x64.def and test_dll_x64.dll.
Subsequently I use Visual C++ 2015 build tools from the command line to generate a .lib file based on the .def file. Like this:
1
2
3
4
c:
call "C:\Program Files (x86)\Microsoft Visual C++ Build Tools\vcbuildtools.bat" x86_amd64 // I have also used the native x64 option, but with the same result.
cd C:\temp\test_dll\bin
lib /def:libtest_dll_x64.def /MACHINE:X64 /out:libtest_dll_x64.lib

This gives me libtest_dll_x64.exp and libtest_dll_x64.lib.

This is the dumbed down project that I use to use the DLL.
1
2
3
4
5
6
7
8
9
#include <iostream>

#include "../test_dll/main.h"

int main()
{
    SomeFunction("Hello world!");
    return 0;
}

For the 32 bit target I again use TDM-GCC-32 and I link to libtest_dll_x32.lib. This builds, links and executes as expected.

For the 64 bit target I again use TDM-GCC-64 and I link to libtest_dll_x64.lib. This builds the object file, but does not link the executable. The linking process fails with the error"error adding symbols: File format not recognized".
If I link the 64 bit target to libtest_dll_x64.a it does properly link and the executable works as expected.

I would really like to know how I can get a valid .lib file for my 64-bit dll and why my current approach is possible for 32-bit applications, but not for 64-bit applications.

Kind regards, Nico
Sorry, Nico, I’m not a native English speaker and I could have misunderstood what you say in your post.
What I have understood is you compile your project with TDM-GCC to obtain a library.
Then you use Visual C++ build tools to build a .lib file based on the .def you’ve got from TDM-GCC.
This chain works for the 32 bit version, but not for the 64 bit one.

If so, my question is: can’t you simply use Visual Studio to get your .lib file starting from your source files? I’ve never used Ms Visual Studio, but I hope it can build a library without the assistance of other compilers.
Files with .lib and .a extensions are not compatible. Don't switch compilers in the middle of a build.

To initialize your MSVC command-line build environment, you should be running

    "C:\Program Files (x86)\Microsoft Visual Studio XX.0\VC\vcvarsall.bat" 32

or

    "C:\Program Files (x86)\Microsoft Visual Studio XX.0\VC\vcvarsall.bat" 64

(Replace the XX with the largest version number of VS you have installed.)

For MinGW, make sure that the -m32 / -m64 switch is applied at every compilation step, including link. (ar won't care.)
Hello Enoizat, thank you for your response. Yes, msbuild should be able to build the DLL on its own, generating a .lib file immediately, but you would need a project file to tell it what to compile and what to link.

I have not tried to do this with my dumbed down test dll, but for my actual project I have created a makefile and used nmake from the "Visual C++ build tools" to build a DLL out of the same source. Unfortunately that DLL gave me the same error when I tried to use the DLL in a application.

Kind regards, Nico
Hello Duthomhas, thank you for your response. I know a .a file is not compatible with a .lib file. This is why I do not convert the .a file to a .lib file but instead generate the .lib file based on the interface definitions stored in the .def file.

I will try the process again with the native x64 settings for visual studio build tools instead of the cross compiling one and I will check if the -m64 switch is indeed set for the linker, that is a tricky one that i did not check yet.

Kind regards, Nico
Hello Enoizat, I made a makefile for the dumbed down project too and if I build the DLL using nmake, when I try to build the 64-bit application to use the DLL I still get the same result:

1
2
3
g++.exe -Wall -fexceptions -O2 -std=c++11 -m64 -O2 -std=c++11  -c C:\temp\test_app\main.cpp -o obj\test_dll_x64\test_app\main.o
g++.exe  -o bin\test_app_x64.exe obj\test_dll_x64\test_app\main.o  -s -m64  ..\test_dll\bin\libtest_dll_x64.lib
..\test_dll\bin\libtest_dll_x64.lib: error adding symbols: File format not recognized


Could it be that there is something in this minimal amount of code that is allowed in 32-bit applications and is not in 64-bit applications?

Kind regards, Nico Nijman
g++.exe
Your last output prove I previously got the wrong end of the stick: I thought you were experiencing problems while compiling with Ms build tools, but your last post seems to refer only to g++.

Could it be that there is something in this minimal amount of code that is allowed in 32-bit applications and is not in 64-bit applications?

I’m a beginner and the few cases I needed a graphical interfaces I used Qt, so I can’t give any advise about code in the MS API.

The only thing I find a bit strange, but I don’t think it can be an issue, is that you call your library source file ‘main.cpp’, which is usually the name of the source file where there’s main().
I know there’s no naming convention, but I’d check the makefile if all files have unique names. It’s just a desperate attempt, since it would give problem also for 32 bit compilation, but...

One last attempt I could think about is to guarantee you have cleared your ‘dumbed down project’ (removing all .o, .exe, .a, .lib.... anything that’s not a .h or a .cpp) before compiling (I mean, in both cases, before compiling 32bit and before compiling for 64bit).

If your problem doesn’t refer to Ms build tools, maybe later I’ll try to compile the library.
I’ve installed TDM-GCC 64bit to ensure I was following your steps (I normally use this version of mingw: https://nuwen.net/mingw.html )

To avoid any problem, I changed your file names this way:
--> file with main(): main.cpp
1
2
3
4
5
6
7
8
9
#include <iostream>

#include "test_dll\\NicoLib.h"

int main()
{
    SomeFunction("Hello world!");
    return 0;
}


--> sub directory: test_dll
--> header: NicoLib.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef __NICOLIB_H__
#define __NICOLIB_H__

#include <windows.h>

#ifdef BUILD_DLL
    #define DLL_EXPORT __declspec(dllexport)
#else
    #define DLL_EXPORT __declspec(dllimport)
#endif


#ifdef __cplusplus
extern "C"
{
#endif

void DLL_EXPORT __cdecl SomeFunction(const LPCSTR sometext);

#ifdef __cplusplus
}
#endif

#endif // __NICOLIB_H__ 


--> source: NicoLib.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "NicoLib.h"

// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}


I didn’t write makefiles, but I entered test_dll and tried:
g++ -std=gnu++17 -Wall -Wextra -pedantic-errors -pipe -O3 -shared -DBUILD_DLL NicoLib.cpp -o libtest_x64.dll -Wl,--output-def,libtest_x64.def,--out-implib,libtest_x64.a

That built these 3 files:
libtest_x64.dll
libtest_x64.a
libtest_x64.def

It only gave me the following negligible (since it’s just an example code) warnings:
NicoLib.cpp:9:55: warning: unused parameter 'hinstDLL' [-Wunused-parameter]
 extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
                                                       ^
NicoLib.cpp:9:89: warning: unused parameter 'lpvReserved' [-Wunused-parameter]
 extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)


Then I went up to parent directory and typed:
g++ -std=gnu++17 -Wall -Wextra -pedantic-errors -pipe -O3 main.cpp -o main.exe -Ltest_dll -ltest_x64
It compiled without problems. After having copied libtest_x64.dll in its parent directory, I was able to execute main.exe.

So, I’m afraid I can’t help you with your error, since I can’t reproduce it, because I compiled smoothly at 64bit. But I think you could begin by:
in main.cpp, change from
#include "../test_dll/main.h"
into:
#include "test_dll\\NicoLib.h"

in NicoLib.h, avoid writing things like __MAIN_H__ .
MAIN sounds one of those name which could create conflicts and, in generale, even if in this case I followed your steps, I think it’s not a good idea to define names which start with a double underscore: those should be reserved.

I can’t be of any help with MS build tools, but, reading here
http://www.mingw.org/wiki/DLL
it seems if you compile with g++ and the "dllimport" and "dllexport" options, your DLL should be legible by an executable made by MS build tools too...
...or I could have totally misunderstood yet again :-)

Hope someone more reliable than me come here to help you. However, good luck.
Last edited on
Topic archived. No new replies allowed.