coapp-packages / zlib

CoApp package for zlib
coapp.org
7 stars 5 forks source link

why /MT for static libraries? #6

Open cosminonea opened 10 years ago

cosminonea commented 10 years ago

I've got an app that is using QT and some of the Nugets. QT is built with /MD (multi-threaded dynamic library) but the static nugets are built with /MT. I want to statically link my app to the nugets and dynamically link it with QT.

This is error I get: Error 3 error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MTd_StaticDebug' in 'someclass.obj'

Any specific reason you are using /MT for static versions of the nugets?

fearthecowboy commented 10 years ago

Well, because we had to make a couple of choices.

It's impossible to guess which CRT you're going to want to link with, so, we thought that if you're going to statically link to a library, it follows that you're probably statically linking with the CRT as well.

If we don't make that assumption, then we need to provide at least twice as many variants of the libraries. Which is a number getting waaaaay too far out of hand already.

Is there a particular reason that you think we should always dynamically link the CRT?

cosminonea commented 10 years ago

I haven't got much experience with c++ but, according to this http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx all the modules used by the linker when producing an obj file must have been compiled with the same flags /MT or /MD. Then googling around for the best practice about /MT or /MD compilation I found the following, which suggest that /MD is better: http://stackoverflow.com/questions/757418/should-i-compile-with-md-or-mt

Quote from the question: "If you are using DLLs then you should go for the dynamically linked CRT (/MD).

If you use the dynamic CRT for your .exe and all .dlls then they will all share a single implementation of the CRT - which means they will all share a single CRT heap and memory allocated in one .exe/.dll can be freed in another.

If you use the static CRT for your .exe and all .dlls then they'll all get a seperate copy of the CRT - which means they'll all use their own CRT heap so memory must be freed in the same module in which it was allocated. You'll also suffer from code bloat (multiple copies of the CRT) and excess runtime overhead (each heap allocates memory from the OS to keep track of its state, and the overhead can be noticeable)."

cosminonea commented 10 years ago

Question: if I want to build any of the libraries do I just go to contrib/coapp and build the solution?

BTW, I think you are doing a fantastic job. This is a major thing for windows developers.

Thanks.

fearthecowboy commented 10 years ago

So first, a few clarifications:

Yes, you do want all your libraries using the same CRT. However, if they all link to the static CRT, in the final binary, they use exactly the same functions. Linking to the CRT doesn't happen until the EXE or DLL is created; referencing the static CRT by multiple libraries doesn't replicate the CRT at all (and even if it did, the Linker is really smart and removes duplicate copies of functions anyway)

So, when we make static libs, we assume that the intent is to eliminate the dependency on the dynamic CRT. (well, any dynamic library). Otherwise, you'd just use a the dynamic version of the library :D

Now, If you use the static CRT for and EXE and a static CRT for a DLL, you will get multiple copies of the functions in the same program space. If they are the same version of the CRT, it's really not dangerous--as it turns out the CRT is actually smart enough to work correctly in this case (although, they don't wanna say that).

Code bloat would be a potential issue tho'.

So, the best practice is... never use static libraries ever unless you really are aware of absolutely everything that you're doing. Certainly mixing static and dynamic libs is ... not wise (as you can easily run into exactly the same issues that you're seeing).

We actually thought about not supporting static libraries at all, simply because sooner or later you will start to do stuff like this. Rather than impose a strange and somewhat arbitrary rule, we've opted instead to allow you to do this, but with the caveat: Good Luck!

Question: if I want to build any of the libraries do I just go to contrib/coapp and build the solution?

Sortof.

if you've cloned one of our repositories, you can run the invoke-build cmdlet from anywhere in the project directory tree, which will build every variant of the library that you have the compiler support to build. Look at the .buildinfo file found in the contrib/coapp folder -- it's the secret sauce to building everything from scratch.

The one in the zlib project is actually going to get a serious update later this week -- I've done a ton of work on improving the automation for building across multiple compilers, and will have some really great optimization for dealing with the fact that some variants are not 'legal' (ie, you can't compile a library with stdcall on x64 -- it doesn't exist).

Really, though, wait till I publish the next version of the tools for that, we're cleaning up a ton of things around that. (since what's there right now is pretty primitive in comparison)