Debugging a linker error: error LNK2019

I am back with one of the classic roadblocks on your way up to development . Linker errors! Well some times these can turn out to be time consuming. Although I am going to discuss one of the scenarios that we worked on, the below can apply to most of the linker issues at least the approach. My senior colleague Scot Brennecke had been instrumental in helping us get to the depths of it . So let's get started, we were approached by one of developers about a linker error he was getting, this was a pretty old project. The error is LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup. He started getting this error after he started using Unicode in his project.  In layman terms the error is because you do not have the main visible to the the linker. But you are editing the file with main or WinMain in the VS Editor, 

               Although the error seems pretty straight forward . Almost all the red flags were checked and it did not some pretty obvious. This project is using /clr switch. All the project properties were synonymous with Microsoft recommendations. The application was GUI and as many social discussions suggest /subsystem:console did not apply . This project is using Unicode and adding entry point wWinMainCRTStartup(); in the Linker setting did not help. All the projects in solution(couple of dlls and MFC exe) used /subsystem:windows at Linker properties-> System . I also verified that all of the projects are using cdecl calling convention. We did query the developer if he was calling the main explicitly anywhere in the program , since this is an old project he did not have it top of his mind. I decided to capture link repro. For those of you who have not heard of link repro , link repro will help you reproduce the error on a remote machine. You just need link.exe to simulate it. The kb article speaks about link repro. This is specially good when you cannot have the entire project with us to debug , it creates a folder of required binaries to examine and repro the error. Below are the steps to collect link repro.

 

a) Create a folder c:\linkrepro

b) Go to Project ->Properties->Configuration Properties->Linker->CommandLine /linkrepro:c:\linkrepro

c) Now build your project and reproduce the linker error in Visual Studio.

d) Go to the VS2010 command prompt and go the folder c:\linkrepro and then enter the command link @link.rsp, notice that you see the linker error there.

e) Copy the buildlog.htm into the linkrepro folder, zip up and upload to the following location

 

Step e is redundant, but for a more meticulous approach I have added it. Once I had the link repro on my machine. I started examining the headers, disassembly and directives . I used dumpbin to dump them out for all lib file and obj files in the link repro folder. In the disassembly I observed some thing strange , 4E3 00000000 UNDEF notype () External | ?WinMainCRTStartup@@$$J0YAXXZ (extern "C" void __cdecl WinMainCRTStartup(void)).

Considering that the project is now Unicode, something was bringing in “WinMainCRTStartup” even though tchar.h has #defined _tmainCRTStartup as wWinMainCRTStartup. So, we searched through the binary contents of all the .lib and .obj files being linked(available in linkrepro). Aside from the Microsoft CRT libraries (where we expect to see all variations mainCRTStartup, wmainCRTStartup, WinMainCRTStartup, and wWinMainCRTStartup), the only file where WinMainCRTStartup was found is myexe.obj. This implies that the developer has either defined his own WinMainCRTStartup, or he is linking to that name directly, or has somehow undefined UNICODE so the tchar #define didn’t work.

 

We now have to examine his code in myexe , which is his GUI app(exe). I got a .i file for myexe.cpp. Here is how you can get a .i file. In the .i file I observed the belo

extern "C" void WinMainCRTStartup();

[System::STAThread]

void MyMain()

{

  WinMainCRTStartup();

}

 

There was a call to the start up function WinMainCRTStartup explicitly.
It may have been done in order to force it to be an STA thread, now that its Unicode we need to call wWinMainCRTStartup,. Myexe project needs to specify MyMain as the entry point. Voila ! After the changes linker error is no longer extant J.