Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unresolved Externals Nightmare

Hello industry veterans,

I am a junior in college embarking on my first summer programming internship, and I am in way over my head. The company I'm working for has purchased a colossal application from another company that has slowly been expanding and modifying it since the early 90's. The solution contains over 200,000 lines of code which are spread across more than 300 files. The entire solution has purportedly been written to ANSI-C++ standards. The code is almost entirely undocumented, and most of it looks like hieroglyphs to me. Ultimately, my job is to port this code to embedded Linux. At the moment, my job is simply to get it compiling using Visual Studio 2008 on Windows XP.

Today, I'm running into linker errors such as this one:

libcmtd.lib(sprintf.obj) : error LNK2005: _sprintf already defined in msvcrtd.lib(MSVCR90D.dll)

My understanding is that this often happens when different projects within a solution are compiled using different runtime libraries. There are 6 projects in my solution. 4 of them were set to compile using the multi-threaded debug DLL runtime library (/MDd), one of them was set to compile using the multi-threaded debug library (/MTd), and one of them was set to compile using the multi-threaded dll runtime library (/MD). The first thing I tried after receiving this error message was to change the /MTd and /MD switches to /MDd so that everything would have compiled with the same runtime libraries. Unfortunately, this led to the following error in afx.h:

fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]

After some digging around, I discovered that it had already told me what I needed to do. I went ahead and changed the "Use of MFC" option under Project Properties->Configuration Properties->General to "Use MFC in a Shared DLL". At this point I started receiving dozens of unresolved external errors such as these:

dataPropertySheet.obj : error LNK2019: unresolved external symbol "public: __thiscall CResizableSheet::CResizableSheet(unsigned short const *,class CWnd *,unsigned int)" (??0CResizableSheet@@QAE@PBGPAVCWnd@@I@Z) referenced in function "public: __thiscall CdataPropertySheet::CdataPropertySheet(unsigned short const *,class CWnd *,unsigned int)" (??0CdataPropertySheet@@QAE@PBGPAVCWnd@@I@Z)

ResizableLib.lib(ResizablePage.obj) : error LNK2001: unresolved external symbol "public: virtual int __thiscall CWnd::Create(char const *,char const *,unsigned long,struct tagRECT const &,class CWnd *,unsigned int,struct CCreateContext *)" (?Create@CWnd@@UAEHPBD0KABUtagRECT@@PAV1@IPAUCCreateContext@@@Z)

After reading through the MSDN pages on LNK2001 and LNK2019, I've realized I have no idea what's going on. These are not the sort of issues they've taught us how to deal with in school. I know my data structures, and that's about it. How I ended up where I am now is beyond me!

From my limited knowledge, it seems that the various debug and release versions of these modules are all tangled up in a web of preprocessor directives and #includes. There are a number of nested #ifdef checks and #define statements done in nearly every header and source file throughout the solution for environment variables, file names, macros, and possibly more. By making even small changes to my compiler settings, I seem to be redirecting large parts of the program to different libraries which have very different function definitions. This is my vague conceptual understanding of what's going on.

I feel as though I'm going to need a better understanding of how this code works before I stand any chance of troubleshooting these compiler errors. To that end, I've been trying to step through many of the files line by line to see where they lead, what objects and variables are in scope, and so on. Unfortunately, this doesn't get me very far, because every call to an external function is ambiguous, and I have no way of seeing through the preprocessor mess to know which version of any given function is supposed to be called.

I was looking around for magic solutions to map out the program and try to make sense of it. I tried one called Doxygen, but either I don't know how to use it properly or it's getting just as confused by the preprocessor stuff as I am.

My question is this:
What are my remaining options?

At this point it's a toss up between:
a.) Switch majors
b.) Jump off a bridge

Neither of these choices are going to help me better understand this code base and get it compiling. Does anybody have any better ideas? Similar experiences? Sage wisdom to share?

Thanks a ton,
-Alex

like image 654
Alex Jansen Avatar asked Jul 13 '12 21:07

Alex Jansen


People also ask

What are unresolved externals?

Unresolved external references occur when the symbol for a function or global variable is referenced in a program, but none of the object files or libraries specified in the link step contain a definition for that symbol.

How do I fix unresolved external symbol in C++?

So when we try to assign it a value in the main function, the linker doesn't find the symbol and may result in an “unresolved external symbol” or “undefined reference”. The way to fix this error is to explicitly scope the variable using '::' outside the main before using it.

How do I fix LNK2001 unresolved external symbol?

To fix this issue, add the /NOENTRY option to the link command. This error can occur if you use incorrect /SUBSYSTEM or /ENTRY settings in your project. For example, if you write a console application and specify /SUBSYSTEM:WINDOWS, an unresolved external error is generated for WinMain .

How do I fix LNK1120?

Error LNK1120 reports the number of unresolved external symbol errors in the current link. Each unresolved external symbol first gets reported by a LNK2001 or LNK2019 error. The LNK1120 message comes last, and shows the unresolved symbol error count. You don't need to fix this error.


2 Answers

It appears you're using the CResizableSheet and CResizeablePage from CodeProject. If you're using the compiled static lib from that page, you could try downloading the source and compiling that with the matching /MDd setting and using the .lib it outputs in the linker input section of your project. I'd also suggest doing a clean all (go to build->batch build->select all then click clean) and then try building again to make sure everything is up to date.

like image 170
syplex Avatar answered Oct 17 '22 20:10

syplex


I hear nursing is a great program ...

At the risk of being pedantic, what you are fighting with are linker errors, not compiler errors. My basic approach to this would be to create a new solution, and start adding projects one at a time, getting each one to build in turn.

I would also seriously consider trying to standardize the settings of each project as much as possible. The easiest way to do this is to create empty projects in your new solution, and copy the existing code into them.

To start with you should assume the following settings (related to MFC):

Debug: Use MFC in a shared DLL, /MDd
Release: Use MFC in a shared DLL, /MD

MDd and MD are the same mode, but one links against debug libraries with extra information for debugging.

Then all you can do is work on one project at a time. Note that if you create a new solution as suggested, you'll need to rebuild the dependency tree between projects. (Right click on a project and choose 'Dependencies', you'll see what I mean.)

When you run into problems doing this, you should make friends with a senior developer at your workplace =).

like image 2
Nathanael Avatar answered Oct 17 '22 20:10

Nathanael