4

Situation:

  • Static library LIB1, compiled from source and linked as lib1.lib (with /MD). Uses library LIB2 and has inside objects from lib2.lib
  • Static library LIB2, also compiled with /MD.
  • EXE that (not directly) depends on both libraries.

Result of linking this EXE on MSVC 15.9.19: a lot of LNK2005 errors like

lib2.lib: error LNK2005: "function <funcsig> already defined in lib1.lib"

Also I get a lot of warnings like

lib1.lib: warning LNK4099: PDB 'lib2.pdb' was not found with 'lib1.lib' or at '<path>'; linking object as if no debug info

The question: why didn't the linker merge duplicate definitions? How do I diagnose the exact reason for this problem?

Thanks!

UPDATE: The errors are NOT about the standard library. They are about the Google Protobuf functions. LIB2 is Google's libprotobuf.lib. LIB1 is also Google's OR-Tools library that uses Protobuf. But we also use Protobuf, hence the conflict!

Alex Jenter
  • 4,324
  • 4
  • 36
  • 61
  • 2
    It seems like LIB1 is making assumptions it shouldn't make. It should either not have linked with another static library, or should not have exported any symbols from that library. What happens if you use the [`/NODEFAULTLIB:LIB2`](https://learn.microsoft.com/en-us/cpp/build/reference/nodefaultlib-ignore-libraries?view=vs-2019) linker option? – 1201ProgramAlarm Jan 30 '20 at 17:24
  • Does /FORCE:MULTIPLE help? https://learn.microsoft.com/en-us/cpp/build/reference/force-force-file-output?view=vs-2019 – srinivirt Feb 01 '20 at 17:48
  • To tell the linker to use libraries other than the defaults, on the command line, specify the libraries to use, and use the /NODEFAULTLIB option to disable the default libraries. In the IDE, add references to your project to specify the libraries to use, and then open the Property Pages dialog for your project, and in the Linker, Input property page, set either Ignore All Default Libraries, or Ignore Specific Default Libraries properties to disable the default libraries. – Nagappa Feb 03 '20 at 07:10
  • It would help to know what "funcsig" is. Specifically, is it symbol from your code, or from the CRT (C-Run Time library). If it's a CRT function, it is likely you are not setting the /MD flag correctly. If not then you have duplicate symbol between your libraries. The most obvious way this can happen is a non-inline'd function in a header. – Tiger4Hire Feb 04 '20 at 10:23
  • @1201ProgramAlarm: /NODEFAULTLIB:LIB2 doesn't help, still same error messages – Alex Jenter Feb 05 '20 at 15:30
  • @srinivirt, /FORCE helps somewhat - EXE file builds, but this is not the solution: first, it can hide real linking issues that lead to UB, and second, it WILL lead to UB if we ever update LIB2 independent of LIB1. I want to understand why this happens and fix the reason, not hack around it. – Alex Jenter Feb 05 '20 at 15:31
  • @Tiger4Hire: the fincsig's are basically all exported functions of the Google Protobuf library. – Alex Jenter Feb 05 '20 at 15:35
  • @AlexJenter The error is self-explanatory to understand why it happens, i.e. same function multiple defined. Options such as /FORCE, allow-multiple-definition exist for a purpose but should be used with care, not used blindly, I agree. – srinivirt Feb 07 '20 at 16:19

1 Answers1

1

This link to MSDN will almost certainly help.

As you say these are not standard C/C++ functions, you can ignore the sections about the mixing Debug and Release code. Unfortunately this still leaves you with plenty of possible causes. This one is a good one to rule out.

This error can occur if you mix use of static and dynamic libraries when you use the /clr option.

If you view the command line options as you compile, either by switching on verbose mode or examining the properties of each file.

Once this is ruled out, all the other causes are that you literally declaring the same thing (function/variable) twice. The most likely way for this to happen is to put something (like a function) in a header file, which is included by more than one module file. Diagnosing this without seeing the code is hard. You must pick one of the errors, and select part of the name that is not mangled, basically the human readable bit. You then need to examine where it is declared, and see if is in a header. If it is not, you must be including a non-header from a source file. A quick (and dirty) way to find where a file is included from is to add a #pragma message to the file, then recompile one file at a time to see when it is printed. To understand why it is included use show includes.

If the symbol is declared from a header file, you must fix it, by making it a forward declare. If you don't know how to do this, I would suggest starting a new question, along the lines of, "how do I forward declare this?". It should get you answers pretty quickly.

Hope this helps.

Tiger4Hire
  • 1,065
  • 5
  • 11
  • This is a good answer, thanks. Unfortunately it doesn't help me much. 1) I don't use the /clr option. 2) If Protobuf's headers violated ODR, the library would be virtually unusable, but it's a pretty popular library from Google itself. Basically, the error comes from the fact that the Or-Tools library (LIB1) should not re-export symbols from Protobuf, but it does. I hoped someone would give advice how to avoid this. – Alex Jenter Feb 06 '20 at 07:58
  • A library is a container for object files (an archive). Object files come from module files. If you are using static linking as you state, you must be creating duplicate functions in your modules. A DLL does "export" symbols. It mirrors the dynamically loaded symbols (which are not linked) with static functions with the same name. They load the dynamic functions and call them. (This is called thunk'ing). Is it possible that you are accidentally using DLL's. see here https://stackoverflow.com/questions/5040965/how-to-switch-a-project-built-on-visual-studio-2010-from-dynamic-to-static – Tiger4Hire Feb 06 '20 at 09:36