Use C++ DLLs from the same VS compiled at differen

2019-06-16 12:57发布

问题:

To repeat: I'm looking for ABI compatibility between libraries of the same Visual-C++ version!

We want to mix and match some internal C++ DLLs from different teams - built at different times with different project files. Because of long build times, we exactly want to avoid large monolithic builds where each team re-compiles the source code of another team's library.

When consuming C++ DLLs with C++ interfaces it is rather clear that you only can do this if all DLLs are compiled with the same compiler / Visual Studio version.

What is not readily apparent to me is what, exactly needs to be the same to get ABI compatibility.

  • Obviously debug (_DEBUG) and release (NDEBUG) cannot be mixed -- but that's also apparent from the fact that these link to different versions of the shared runtime.
  • Do you need the exact same compiler version, or is it sufficient that the resulting DLL links to the same shared C++ runtime -- that is, basically to the same redistributable? (I think static doesn't fly when passing full C++ objects around)
  • Is there a documented list of compiler (and linker) options that need to be the same for two C++ DLLs of the same vc++ version to be compatible?
    • For example, is the same /O switch necessary - does the optimization level affect ABI compatibility´? (I'm pretty sure not.)
    • Or do both version have to use the same /EH switch?
    • Or /volatile:ms|iso ... ?

Essentially, I'd like to come up with a set of (meta-)data to associate with a Visual-C++ DLL that describes it's ABI compatibility.

If differences exist, my focus is on VS2015 only at the moment.

回答1:

Have been thinking this through the last days, and what I did do was to try to see if some use-cases exists where devs have already needed to categorize their C++ build to make sure binaries are compatible.

One such place is the Native Packages from nuget. So I looked at one package there, specifically the cpprestsdk:

The binaries in the downloadable package as split like this:

native\v120\windesktop\msvcstl\dyn\rt-dyn\x64\Release\
        ^      ^         ^      ^    ^     
  VS version   |       not sure |    uses cpp-runtime dynamically
               |               lib itself dynamic (as opposed to static)
    or WinXP or WinApp(WinRT?)

I pulled this out from this example, because I couldn't find any other docs. I also know that the boost binaries build directory is separated in a similar way.

So, to get to a list of meta data to identify the ABI compatibility, I can preliminarily list the following:

  • VC version (that is, the version of the C and CPP runtime libraries used)
    • one point here is that e.g. vc140 should be enough nowadays - given how the CRT is linked in, all possible bugfixes to the versioned CRT components must be ABI compatible anyway, so it shouldn't matter which version a given precompiled library was built with.
  • pure native | managed (/CLI) | WinRT
  • how the CRT is consumed (statically / dynamically)
  • bitness / platform (Win32, x64, ARM, etc.)
  • Release or Debug version (i.e. which version of the CRT we link to)
  • plus: _ITERATOR_DEBUG_LEVEL ... if everyone goes with the defaults, fine, if a project does not, it must declare so

Additionally my best guess as to the following items:

  • /O must not matter - we constantly mix&match binaries with different optimization settings - specifically, this is even working for object files within the same binary
  • /volatile - since this is a code-gen thing, I have a hard time imagining how this could break an ABI
  • /EH - except for the option to disable all exception, in which case you obviously can't call anything that throws, I'm pretty confident this is save from an ABI perspective: There are possible pitfalls here, but I think they can't really be categorized into ABI compat. (Maybe some complex callback chains could be said to be ABI incompatible, not sure)

Others:

  • Default calling convention (/G..) : I think this would break at link time, when mangled export symbols and header declarations don't match up.
  • /Zc:wchar_t - will break at link time (It's actually ABI compatible, but the symbols won't macth.)
  • Enable RTTI (/GR) - not too sure 'bout this one - I never have worked with this disabled.