views:

1171

answers:

4

I've been trying to statically link against a C++ library called Poco on Windows using the Visual Studio 2008 command line tools.

I build my program with:

cl /I..\poco\lib /c myapp.cpp
link /libpath:..\poco\lib myapp.obj PocoNet.lib

This results in an exe that at runtime requires PocoNet.dll and PocoFoundation.dll.

I spent some time reading up on linking in Windows, and learned that cl /MT statically links against the standard library, while cl /MD links dynamically.

I tried to specify /MT, but that didn't seem to change anything; my app still requires the Poco DLLs. (I also suspect that /MT is the default behavior.)

Looking under ..\poco\lib, I found there was also a PocoNetmt.lib, but specifying that instead of PocoNet.lib resulted in a bunch of LNK2005 errors ("already defined"):

msvcprt.lib(MSVCP90.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in exp.obj

I then tried stacking on more flags:

  • /verbose:lib: useful for seeing what's happening

  • /Zl: same results as before

  • /nodefaultlib:libcmt.lib /nodefaultlib:msvcprt.lib: got this error:

    PocoFoundationmt.lib(Exception.obj) : warning LNK4217: locally defined symbol ??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ (public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)) imported in function __ehhandler$??0Exception@Poco@@QAE@ABV01@@Z
    
  • dropping the .lib altogether, as suggested here: same error as above

I also tried some combinations of the above, all to no avail.

Any clues would be greatly appreciated. But just as useful would be any pointers to resources that are useful for debugging (or learning about) these types of issues.

+2  A: 

It sounds like the problem is that the PocoNet.lib file is an import library for the poco.dll. So the externs it resolves are to the DLL.

You'll need to find or build a static library for Poco (if possible).

Michael Burr
But how do I verify this? I mentioned that I eventually found and switched to a `PocoNetmt.lib`; that's what started giving me link errors. (The Poco build system by default produces both shared and static libs.)
Yang
A: 

You will need /MT on your code and all its dependencies to statically link to MSVC runtime (MSVCP90.dll/MSVCR90.dll).

That is because PocoNetmt.lib seems to be build with /MT.

If with /MT you still get msvcprt.lib, turn on /verbose and find out which other library drags it. Then recompile/find static build of that.

Another option is to find static PocoNet lib that is built with /MD (so you link statically to it, but dynamically to runtime) and switch everything to /MD.

EDIT: When Poco dll is linked with /MT that does not affect you. But since you want to get rid of it, you (and all your other dependencies) will have to use same /MT flag.

Eugene
CAPCHA: analy worthier. Go figure...
Eugene
I just got one response from the Poco mailing list telling me that, while indeed the PocoNetmt.lib is for static linking, the Poco libs themselves are all built with /MT, so that I'd still need dynamically link with the standard runtime libs - which is fine. I just don't wish to drag the PocoNet.dll's with me, and that's what I can't figure out how to do.
Yang
/MT means you _don't_ link to runtime dlls. /MD means you do. And this flag must be the same across all libs you link to.
Eugene
Argh, sorry about that. I know this, I meant to write "are all built with /MD."
Yang
+3  A: 

You have to define POCO_STATIC on the command line and link with both PocoFoundationmt and PocoNetmt.lib:

C:\test>cl /MD /WX /nologo /EHsc /DPOCO_STATIC /DUNICODE /D_UNICODE /I..\poco\Foundation\include /I ..\poco\Net\include /c exp.cpp

exp.cpp

C:\test>link /libpath:..\poco\lib /WX /nologo exp.obj PocoNetmt.lib PocoFoundationmt.lib

[UPDATE] If you compile with /DPOCO_STATIC, then it isn't necessary to specify the POCO libraries on the linker command line. The header files contain #pragma comment(lib, "PocoXXXmt.lib") statements that should ensure that all the necessary libraries will be linked in.

If you don't compile with /DPOCO_STATIC, then the DLL import libraries will be automatically linked instead. [/UPDATE]

Alex
Thanks. POCO_STATIC was the key. I highly suggest making this obscure incantation more prominent somewhere in the high-level documentation and README. When Googling for POCO_STATIC, the only references to it are in blog posts.
Yang
A: 

Look dude, .lib come in many flavours. You have some .lib that are only used to find the functions in a dll and some .lib that actually contain real object code.

In your case, if you don't have a .lib made for static linking, there is nothing you can do with your linker to remove this dependency.

If you want to do some serious work with a linker, I recommend using PEView. Open your .lib with it. http://www.magma.ca/~wjr/

toto