views:

1316

answers:

7

I apologize in advance for the long post...

I used to be able to build our VC++ solutions (we're on VS 2008) when we listed the STLPort include and library directories under VS Menu > Tools > Options > VC++ Directories > Directories for Include and Library files. However, we wanted to transition to a build process that totally relies on .vcproj and .sln files. These can be checked into source control unlike VS Options which have to be configured on each development PC separately. We handled the transition for most libraries by adding the Include directories to each Project's Property Pages > Configuration Properties > C/C++ > General > Additional Include Directories, and Library directories to Linker > General > Additional Library Directories.

Unfortunately, this approach doesn't work for STLPort. We get LNK2019 and LNK2001 errors during linking:

Error   1 error LNK2019: unresolved external symbol "public: virtual bool __thiscall MyClass::myFunction(class stlp_std::basic_istream<char,class stlp_std::char_traits<char> > &,class MyOtherClass &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > &)const " (?myFunction@MyClass@@UBE_NAAV?$basic_istream@DV?$char_traits@D@stlp_std@@@stlp_std@@AAVSbprobScenarioData@@AAV?$basic_string@DV?$char_traits@D@stlp_std@@V?$allocator@D@2@@3@@Z) referenced in function _main MyLibrary.obj 

Error   5 error LNK2001: unresolved external symbol "public: static void __cdecl MyClass::myFunction(class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &,long,enum MyClass::MessageType,int,class stlp_std::basic_string<char,class stlp_std::char_traits<char>,class stlp_std::allocator<char> > const &)" (?myFunction@MyClass@@SAXABV?$basic_string@DV?$char_traits@D@stlp_std@@V?$allocator@D@2@@stlp_std@@000JW4MessageType@1@H0@Z) MyLibrary.lib

This happens while linking and executable project to dependencies which are library projects. Curiously, this does not happen while linking the library projects themselves. Any ideas?

A: 

This is a link error. It doesn't have to do with your include paths.

You either forgot to add MyClass.cpp to your project, or forgot to define those two functions.

The reason the error doesn't happen when "linking" library projects is that library projects are not linked. They are simply a bunch of OBJs that are put together by the LIB program into a library file.

A: 

Thanks, but I'm such a noob. I don't know how to do this. I've tried adding:

#pragma comment(lib, "stlport.5.1")

to all files that use it. But that doesn't take the cake either.

Jeremy
A: 

Add the library name to the list of additional libraries to link. Sorry I'm not in front of a recent version of VS to know exactly where it goes.

Mark Ransom
Yeah, I've tried that too. But then again I might need more time to look over everything to make sure it's all linked together properly. It's tough maintaining decades old software as I'm sure y'all know. Especially for us noobs. XD
Jeremy
+1  A: 

These link errors suggest that certain classes in your application either haven't been compiled using STLPort or have been omitted from the build. They do not suggest that you aren't linking against STLport.

My guesses would be that:

  • The build settings for MyClass somehow overwrite the project-wide setting for the include path and thus MyClass is being built using the default C++ STL implementation and not STLport. This should be easy to check - run dumpbin against the object file and check the functions in there reference the standard library in the stlp_* namespace or not. If not, it's likely that the compiler is not picking up the correct include path. I'd also have a look at the command line that the IDE is calling the compiler with. These can be viewed via the C/C++ Configuration properties as well.
  • As other posters also mentioned, there is a chance that MyClass isn't being built, but that should be very easy to check.
Timo Geusch
A: 

You have to configure STL port to use the native IOStreams implementation.

Also is there any specific reason you use STLPort? The default STL implementation is recommended unless you are trying to make a cross platform application - even then its not really needed in most cases.

rep_movsd
It's legacy code that I can't change without causing great pain to myself and others. I tried it, but I'm not sure if I got all the settings right. Not sure if I have to recompile it either.
Jeremy
+2  A: 

Raymond Chen recently talked about this at The Old New Thing-- one cause of these problems is that the library was compiled with one set of switches, but your app is using a different set. What you have to do is:

Get the exact symbol that the linker is looking for. It will be a horrible mangled name. Use a hex editor (IIRC, Visual Studio will do this) to look at the .lib file you're linking to. Find the symbol that's almost the thing the linker is looking for, but not quite. Given the differences in the symbols, try to figure out what command line switches will help. Good luck -- for people who aren't used to this sort of problem, the solution can take days to figure out (!)

SunriseProgrammer
Another trick is to link using /VERBOSE, which will print the things it finds. That helped me at least locate a problem of this type. THANKS for this post, it really did help me pinpoint my problem.Now the questions is why one .lib has a _cdecl declaration of a function and the other a _this_call.
jakobengblom2
+4  A: 

As mentioned in other answers, this is a linker error and likely the result of the library and the application being compiled with different options. There are a few solutions on tracking this down already (one of them as the chosen answer, currently). These solutions will work. However, there are a few tools that will make your search much much easier.

For starters, understanding decorated names will help. Within all that garbage, you will recognise some things: The name of your function, namespaces, some class types you are using. All of those characters around them mean something to the compiler, but you don't need the compiler to tell you what they are.

Enter undname.exe:


undname.exe <decoratedname>
  • is a simple command line program that is in your VS bin directory.
  • takes the decorated name as it's first argument.
  • outputs a human readable format of the symbol.

Armed with that knowledge, you can now move on to finding a reasonable candidate for the mis-created symbol.

First off, you could edit your libraries in a hex editor, as suggested elsewhere. However, there is a much easier way to find the symbols.

Enter dumpbin.exe:


dumpbin.exe <switches> <library name>
  • is a simple command line program that is in your VS bin directory.
  • takes a set of switches and a library to apply them to.
  • outputs information from the library

The switch you will be interested in for your question is /linkermember. There are many other switches that can get you very interesting information, but this one will list out all the symbols in the library.

At this point, a little commandline savvy will serve you well. Tools like grep can really shorten your work-cycle, but you can get by with redirecting to a file and using notepad or the like.

Since I don't have your code or library, I'll contrive an example from TinyXML.

Assuming your error message was this:

Error   1       error LNK2019: unresolved external symbol "public: unsigned char __cdecl TiXmlComment::Accept(bool,class TiXmlVisitor *) " (?Accept@TiXmlComment@@ZBE_NPAVTiXmlVisitor@@@Z) referenced in function _main     MyLibrary.obj

Having determined this is a function in the TinyXML, I can start looking for the mismatched symbol. I'll start by dumping the linkermembers of the library. (Notice the switch is singular, this always gets me when I type it from memory!)


>dumpbin /linkermember tinyxml.lib
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file tinyxml.lib

File Type: LIBRARY

Archive member name at 8: /
4992E7BC time/date Wed Feb 11 08:59:08 2009
         uid
         gid
       0 mode
    B402 size
correct header end

    859 public symbols

    16292 ??$_Allocate@D@std@@YAPADIPAD@Z
    16292 ??$_Char_traits_cat@U?$char_traits@D@std@@@std@@YA?AU_Secure_char_traits_tag@0@XZ
    16292 ??$copy_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDI@Z
    16292 ??$copy_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDIU_Secure_char_traits_tag@1@@Z
    16292 ??$move_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDI@Z
    16292 ??$move_s@U?$char_traits@D@std@@@_Traits_helper@std@@YAPADPADIPBDIU_Secure_char_traits_tag@1@@Z
    16292 ??$use_facet@V?$ctype@D@std@@@std@@YAABV?$ctype@D@0@ABVlocale@0@@Z
    16292 ??0?$_String_val@DV?$allocator@D@std@@@std@@IAE@V?$allocator@D@1@@Z
    16292 ??0?$_String_val@DV?$allocator@D@std@@@std@@QAE@ABV01@@Z

This is obviously too much to read, but we don't have to, we know what we're looking for, so we'll just look for it.


>dumpbin /linkermember tinyxml.lib | grep Accept
    529AE ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlDeclaration@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlDocument@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlElement@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlText@@UBE_NPAVTiXmlVisitor@@@Z
    529AE ?Accept@TiXmlUnknown@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlDeclaration@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlDocument@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlElement@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlText@@UBE_NPAVTiXmlVisitor@@@Z
        3 ?Accept@TiXmlUnknown@@UBE_NPAVTiXmlVisitor@@@Z

That's much easier to read. Looking at our error, we're looking for the Accept Function of TiXmlComment. We could grep the output additionally for that name, if we had lots of matches (like looking at the size function in the stl!), but in this case, we can pick it out of the list. Here is where we turn to undname:


>undname ?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?Accept@TiXmlComment@@UBE_NPAVTiXmlVisitor@@@Z"
is :- "public: virtual bool __thiscall TiXmlComment::Accept(class TiXmlVisitor *)const "

So, in this example, our application is looking for a function which returns an unsigned char, but the library has a function returning a bool.

This is a contrived example, but it illustrates the technique to use to track down your issue. You are probably looking for a typedef type which is set differently based on your options.

The problem where I ran into this was with time_t. In some libraries I was using, the time_t used a 32-bit type as part of it's internal representation. This library was generated with an older compiler, where that was the default. In VS 2005, the time_t uses a 64-bit type by default. I had to add the preprocessor define _USE_32BIT_TIME_T to get it to compile. I tracked this issue down precisely as I have described.

I hope this helps someone solve this issue!

Aaron
Thanks! Sounds promising, I'll try it first thing on tomorrow.
Jeremy