Monday, 14 April 2014

Intel and Microsoft compiler linker errors (already defined in)

Recently I ran into a rather strange error that took me a little while to track down. So to make it easier for anyone else who runs into this then Ill describe the error and its resolution here.

Basically the error was during linking a program and showed up as:

LIBCMT.lib(log10.obj) : error LNK2005: _log10 already defined in libmmt.lib(log10_stub.obj)

This was just one of may errors that decided to pop up (basically the same errors but for things like sin/cos etc.). This was a rather odd error and it pretty much doesn't matter what linker options you change there is no way to save you from this one (don't bother trying to ignore specific libs as that will just make things worse - trust me). The problem was due to a program that includes static libs where 1 of those libs was created by the standard Microsoft compiler and the other was created by the Intel compiler. The problem is that each of these input libs declared the same function but in different ways (one the Intel way the other the Microsoft way).

The issue revolves around the standard C library (obviously I was writing C/C++ code). When using the Microsoft compiler the standard C library is libcXX where XX can change based on different settings. In the above example I was using the standard multi-threaded version (hence the mt appended to the end of libc). The Intel compiler also defines it own implementation of various standard C functions which it puts in its own libmXX. So the above problem arises because these two libs are clashing with each other. This would not be a problem if both input libs were compiled with the same compiler but if that is not an option then we have to find a solution.

Luckily Intel is not entirely clueless here and there libmXX libraries are designed to play nice with the default Microsoft ones. So why the above error? Well the problem arises when each input library uses a different compilation option. There will always be a problem with mixing code generated against different libcXX versions even when using the same compiler but as you can see from above both are generated using the 'mt' version so all should be fine. The actual solution is due to the implementation of each of these clashing functions. Above the example was the log10 function which is only clashing because it is being used in different ways that can not be resolved between the Intel and Microsoft compiler.

The culprit is a setting called "FloatingPointModel". If building through Visual Studio then this setting can be found under "C/C++->Code Generation" in the project properties. The issue occurs when 1 of the input libs was compiled using a different floating point model than the other lib. For instance if one of the libs was set to use Intel compilers "Fast2" setting then it will use the appropriate optimizations and optimized functions from within libmXX. However if the other lib was compiled using a different floating point model then it will try and use that version of the function. The problem is that they both have the same function name but have different implementations in different compiler libc implementations. All of a sudden libmXX and libcXX wont play nice together as they are both trying to use different optimized versions of a math function that has the same name. The linker doesn't know which one to use and so errors abound.

The solution is simply making sure that all input libs are compiled using the same setting for the floating point model. This rules out using Intels "Fast2" option as this is never available on Microsoft's so it will always cause problems. But apart from that making sure they are all the same value (or not setting any value) should make this rather rare and frustrating bug go away.