My experience from Windows is that DLL's are both blessing and pain. I'll give a concrete example, a not so small Qt application.

If you use the DLL version of Qt you get the following benefits:

- Faster link time (More on this later). This is the big winner.

- Minor-versions can be updated apart from the executables or other DLL's using it. This requires the library itself to be well written and respect that (Qt follows good procedures, sqlite is awesome example, but there are some terrible ones - like the P4 C++ api which constantly adds/removes virtual members, enums, etc.)

- Fully optimized (/LTCG) dlls, if Qt allows to mix all in one DLL then even better (calls between QtCore and QtGui could be further reduced, code inlined, etc.). Okay you don't get full whole app (only full static link would do), but you get still good link times with overall good optimization.

- Exceptions kept there, not propagated (controversial whether this is a good idea, but I like it).

- No clashes with other (usually) statically linked libraries - like png, zlib, etc. Unless you really want both QtCore and your app to use exactly the same versions (for one reason or another).

- Smaller executable size (this does not matter lately, but may come)

Minuses of DLL, pluses of static linking:

- Deployment madness no more. You push one executable, everyone is happy. You don't need to make sure that pushed DLLs (.so) won't break other executables. You might be able to rollback or work on specific version if things go badly (this could be also done with Dlls', .so, but they have to reside along with the executable).

- Somewhat faster execution time (less time to resolve symbols, load DLLs, etc.)

- You get RTTI, exceptions, and in older versions of certain systems __declspec(thread) and other things working correctly.

- Real full whole code optimization. But you should have other release targets (for development).

My biggest pain with DLLs (and executables) was on Windows where people would sync directly from P4 (perforce) and ran directly the executables from where they were synced (this way, there is no extra step - "Press or Run this thing after syncing"). But this comes with price - on Windows you can't replace running executable with another (or DLL). I've tried the various hacks where you set the executable/dll to be loaded from the NET or CD so that it's fully put in the swap, but still does not work. A correct way seems to be a proper deployment - you sync, you ran some kind of "Deployment" tool and then work.

From Windows point of view I really liked the idea of loading the DLL by first looking at your executable path, then for other places. Seems like UNIX is not this way, but then on UNIX people had stabilized places and locations for things (/usr/lib, /usr/local/lib, etc.).

Another problem is if you want to have simulatenously 32-bit and 64-bit dlls/.so. I like OSX's solution most of fat binaries, but seems like Linux folks do not like that (there was a proposal time ago), and on Windows that's out of the question.

It doesn't scale really when you get more architectures/models, but if you have mainly 2 it might work pretty well (apart from being pain for the build system).