Thursday, February 15, 2007

Fixing "Minimize CRT Use in ATL"

One of our products uses an ATL-based DLL as part of its installation. Under Visual Studio 6, the component was 39KB. When I rebuilt the DLL under VC2005, the size jumped to 108KB, a rather large increase for no additional functionality.

The "General" property sheet contains an item "Minimize CRT Use in ATL", which seems to be exactly what I want to solve the problem. However, getting it to work ended up being a big effort.

This problem had been discussed in several other places with no solution. Examples include the following sites. The last site concerned me the most, because Microsoft closed a bug filed against the problem saying "Won't Fix."

forums.microsoft.com
www.tutorials-ne.com
groups.google.com
connect.microsoft.com

The problem can be reproduced very easily:

1. Create an ATL DLL project using VC++ 2005 wizard
2. Switch projects to the Release configuration
3. Set "Use of ATL" to Static Link to ATL and set "Minimize CRT Use In ATL" to Yes.
4. Build the project.

You'll get the following errors:
LIBCMT.lib(tidtable.obj) : error LNK2005: __encode_pointer already defined in atlmincrt.lib(atlinit.obj)
LIBCMT.lib(tidtable.obj) : error LNK2005: __encoded_null already defined in atlmincrt.lib(atlinit.obj)
LIBCMT.lib(tidtable.obj) : error LNK2005: __decode_pointer already defined in atlmincrt.lib(atlinit.obj)
LIBCMT.lib(crt0dat.obj) : error LNK2005: __get_osplatform already defined in atlmincrt.lib(atlinit.obj)
LIBCMT.lib(crt0dat.obj) : error LNK2005: __osplatform already defined in atlmincrt.lib(atlinit.obj)
[etc.]

I first tried ignoring LIBCMT by adding it to "Ignore Specific Library" in the property sheet. This produced another set of errors, including:
atlmincrt.lib(atlloadcfg.obj) : error LNK2001: unresolved external symbol ___security_cookie
atls.lib(atlbase.obj) : error LNK2001: unresolved external symbol __except_handler4

I next tried excluding both ATLS and LIBCMT. This didn't work either. Some of the posts mentioned above tried excluding atlmincrt.lib, but since this appears to me to be the key library that makes everything work, I didn't consider excluding it to be a viable solution.

After several hours of trial and error, I determined that disabling exception handling allows the DLL to link successfully. You do this in the project properties under C/C++ | Code Generation | Enable C++ Exceptions. Set it to No.

At this point I was successful. My component was now 50KB. This was still not ideal, but much better than the 108KB I started with.

There is one important caveat to this approach. If you don't let ATL use the C run-time, then you can't use it either. Any attempt to call a function such as atoi, printf, or any other C run-time function will bring back all of the original link errors, such as error LNK2005: __encode_pointer already defined in atlmincrt.lib(atlinit.obj). Many C run-time functions have Windows equivalents, such as lstrcpy instead of strcpy, so it's possible to not use the C run-time, but it requires discipline.

If your project is generating the "__encode_pointer" link errors and you can't figure out what function you are calling that is causing the problem, then temporarily add LIBCMT to the Ignore Libraries list and build the project. Look for unresolved symbols in your object files. Ignore unresolved symbols in atls.lib, stdafx.obj, and atlmincrt.lib

2 comments:

  1. well done! This is the only article which help me.

    ReplyDelete
  2. Thanks for this information.. Searching all over the net this the only one that my project works..

    ReplyDelete