user1641398
user1641398

Reputation: 89

Why is "WinMain" unresolved when linked as a *.a static library?

Given a simple program:

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, 
                   LPSTR lpCmdLine, int nCmdShow)
{
  return 0;
}

If I run g++ a.cpp it works fine.

However, running g++ -c a.cpp && ar rcs a.a a.o && g++ a.a gives the following error:

c:/mingw32/bin/../lib/gcc/i686-w64-mingw32/4.8.1/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status

Any insight as to why this occurs? How can I link a program with only .a files?

Upvotes: 3

Views: 3753

Answers (3)

user3123061
user3123061

Reputation: 769

I am using Code::Blocks. Today i have same problem with WinMain in static library. Changing order of libraries does not works in my case. I finally solved it by adding -lmingw32 to Project/Build options/Linker settings/Other linker options.

Upvotes: 0

greatwolf
greatwolf

Reputation: 20878

The gcc ld linker handles *.a static libraries a little differently from *.o object files. In particular, symbols from the static library do not get included into the final binary image executable unless an object file or another static library linked in earlier uses it.

Additionally, the order you pass in the static libraries matter for ld. For example, say libb.a needs a function that's in liba.a. If you link it like so:

g++ -Wall example.cpp -o example.exe -la -lb

This will fail to resolve because when liba is processed it doesn't see what symbols -lb requires (libb hasn't been processed yet). The only symbols retrieved from liba.a is everything it has seen up to that point.

Why is this important?

If you apply the above process to your question it becomes clear why WinMain isn't getting resolved.

g++ a.a

When ld processes a.a it says "oh nothing is using WinMain so I won't include it"; and that is true up that point of processing since no other object files are provided before it.

What you don't see above is that mingw, by default, also includes a bunch of important boilerplate code needed for your program to work. One of these is crt0_c.o from mingw32.a which makes up part of the mingw runtime that does call your WinMain.

Solutions

There are two ways to ensure that WinMain from your a.a gets included:

  1. Use -Wl,--whole-archive to force inclusion of all symbols in a.a so they're available for symbol resolution. Append -Wl,--no-whole-archive afterwards so it doesn't erroneously apply this to other libraries that comes after. eg.

    g++ -o example.exe -Wl,--whole-archive a.a -Wl,--no-whole-archive
    
  2. The second way is to include mingw32.a manually before a.a so WinMain becomes a pending unresolved symbol when a.a is processed:

    g++ -o example.exe -lmingw32 a.a
    

    or

    g++ -o example.exe libmingw32.a a.a
    

But you'll probably need to fully qualify the path to libmingw32.a or else the linker won't find it.

Upvotes: 7

Andreas Bombe
Andreas Bombe

Reputation: 2470

.a files are static libraries, as far as the linker is concerned. The linker only takes objects out of the archives that define symbols that are currently unresolved. Thus, without any object files referencing symbols defined in the .a files, they won't be pulled in. The linker output in your example is empty, thus WinMain is not defined.

Actually it appears to work when you define the standard main(). I assume that's because of there being a reference to main() required by the language standard. There is also a gcc / ld command line option to generate a reference to a symbol. Try adding -u WinMain@16 before the .a file.

Upvotes: 0

Related Questions