Of course there are things other than described below that I'm not brining to memory right now. You might consider looking at large cross platform open source projects, like say wxWidgets which has already considered such issues.
Static
A static lib (.a|.lib) is like making a zip of your object (.o) files so you can manage them as one unit, when you compile some other program to use the static lib all the object files it needs will be compiled in.
In most cases you won't need to do anything more, you could just as well include the object files directly.
Consideration should be made for module size and how many times you might need to use the features - avoid static if you want to use the lib from more than one module in the one application.
Dynamic
You will need to specify more than your standard classes for MSVC
- What to export using
__declspec(dllexport)
- What users of the lib can access using
__declspec(dllimport)
- will you have more than one library
Example header stub, make it unique enough so you won't clash with other libraries
// MartinsHeader.h
#ifdef BUILDING_DLL_A
#define DLL_A_EXPIMP __declspec(dllexport)
#else
#define DLL_A_EXPIMP __declspec(dllimport)
#endif
void DLL_A_EXPIMP MyFunction();
class DLL_A_EXPIMP MyClass{};
Template classes in public interfaces may raise warnings if not explicitly instantiated so all the template code is compiled.
You may want to consider PIMPL to minimise the externally visible changes to the implementation of your classes. (reduce need for users of lib to recompile for new lib)
Memory issues
The runtime becomes important in terms of who is (de)allocating what.
A) You can stick with the native memory model at which point
- some libraries will have a bunch of different compilations for single/multi threaded debug and release modes. It will need to match the runtime of the calling module (EXE/DLL)
- Usage of classes in the interface will often add a requirement that you use the same version of the class in both the library and the app - often means multiple compilations on version of visual C.
B) You can force memory (de)allocation by introducing factory only allocations and destruction methods so it is all performed by the library. (I'm not a big fan of this as it makes the code more difficult, but it can make runtime issues easier)