Situation:
I am using CI to compile a Windows version of my project using CMake and MSVC
It errors out right at the end complaining of two missing symbols (__std_system_error_allocate_message and __std_system_error_deallocate_message)
When I replicate the build process on my own computer, the build finishes fine and the artifacts run without errors.
Searching for these symbols on Google yields no clues as to which libraries they are supposed to be defined in.
Which leads to my question:
Is it possible to see where the MSVC linker is finding a particular symbol?
I was able to find instructions to look at what symbols are defined in a particular library, but this project is linking dozens of libraries, and the ones I have searched so far do not define the symbol. I think this approach is prone to errors as I might miss a library without knowing it.
#Richard Critten pointed me on the right path, the problem was due to having different versions of the MSVC toolchain on each system. GitLab's CI runners were using build tools version 16.2.3.0 while I was using a more recent 16.6.1.0. Uninstalling that and installing 16.2.3 from this page reproduced the error. Recompiling a dependency I had previously compiled with the newer toolchain then resolved the error on both systems.
Related
Tools and versions:
Visual Sudio 2017, Google Protobufs 3.11.3, gRPC 1.27.1, vcpkg 2020.02.04, on Microsoft Windows
I used vcpkg to build the Windows native C++ versions of gRPC and protobuf (and other dependencies) for Windows (x86). Everything builds successfully.
When I build my application I include "libprotobuf.lib" as a linker input. However, it doesn't get linked. Instead, my program will only run if the "libprotobuf.dll" is present for the program to load. I don't know of another way to specify that the library should be statically linked.
During the build of my application, I see a lot of warnings like this:
include\google\protobuf\duration.pb.h(220): warning C4251: 'google::protobuf::Duration::_internal_metadata_': class 'google::protobuf::internal::InternalMetadataWithArena' needs to have dll-interface to be used by clients of class 'google::protobuf::Duration'
This page mentions the warnings and says that static linking is the default but it seems like vcpkg isn't building it that way or I need to reference the library a different way.
I've also seen this page that offers a solution. That helped a bit. It made Visual Studio recognize unresolved externals, so at least it was trying to statically link the .lib file(s). With that in place I've tried various combinations of .lib files for protobuf, grpc, and dependencies but I still can't get a successful build - and the compiler warnings are still generated.
I feel like I'm missing something (a pre-processor define maybe) during the vcpkg build that would build the headers or libraries differently. I've tried to change some of the build settings but they're always overwritten when vcpkg generates cmake files for the build.
Or I'm missing the right combination of library files to reference from my project.
Has anyone gotten this to work? If you have examples of building the libraries for static linking via vcpkg, or the correct way to link the libraries in VS2017 project, could you share your information?
Finally got a chance to come back to this. The problem came down to two things:
1. Realizing that you can specify a triplet (as noted in original question).
2. Finally realizing using the static libraries also meant I had to switch my application to static c runtime libraries instead of shared dlls.
I can't switch my application. I've done testing with this non-static mode operation though. I haven't seen any problems, but does anyone else use protobufs (and gRPC this way) - it doesn't appear to be recommended.
I am doing a build on a 32bit SLES10 machine. Using GCC 3.4.2
Here is a sample error
`.L8245' referenced in section `.rodata' of CMakeFiles/myproj.dir/c++/util/MyObj.o: defined in discarded section
`.gnu.linkonce.t._ZN5boost9re_detail9reg_grep2INS0_21grep_search_predicateIPKcSaIcEEES4_cNS_12regex_traitsIcEES5_S5_EEjT_T0_SA_RKNS_14reg_expressionIT1_T2_T3_EEjT4_' of CMakeFiles/myproj.dir/c++/util/MyObj.o
This is typically due to 2 different .cpp's being compiled with different compiler switches - but also using the same templates. The generated template instantiations may differ in what they define/reference, and if the instantiation that is selected doesn't define/refer to the exact same symbols as the ones that got discarded you may get this error.
Validate that all your .cpp's are compiled with the exact same compiler switches and defines. If this isn't possible, reorder the .obj files on the linker commandline, in particular try to move the .obj files mentioned in the error message to the end or beginning of the .obj file list.
EDIT:
Also, if you're linking against prebuilt c++ libraries, see if you can duplicate the compiler switches used for building these libraries.
This may be due to using a newer version of binutils. binutils version 2.15 treated this as a non-fatal error, but later versions of binutils changed and so the link started failing. See https://bugzilla.redhat.com/show_bug.cgi?id=191618 for a similar report.
In my case, I was able to get things to link once more by explicitly using binutils 2.16.1, instead of binutils 2.17.
I used CMake and Visual C++ to build the HyDE library. Then, still in VC++, I was able to successfully create code and build an executable that links into HyDE.lib and the HyDE header files.
I then discovered that in order to work with others at my company, it would be preferable to develop in Eclipse CDT. Knowing very little about Eclipse CDT, I created a default hello world project, deleted the code and then dumped in all of my code into the src folder. Then I attempted to change the includes and lib path and libs to mirror what had worked in VC++. At this point everything seems to compile, but I get an error in linking:
/cygdrive/c/EclipseWorkspace/425HyDE/Debug/../src/FS5HyDE.cpp:16: undefined reference to `HyDEAPI::HyDE::HyDE(HyDESystemModel::SystemModel*, bool)'
(There are many more errors like this, all referring to HyDE methods.) Here is what is being run at the command line:
g++ -L"C:\Progra~1\boost\boost_1_42\lib" -L"C:\EclipseWorkspace\HyDE" -o"425HyDE.exe" ./src/Adapter_FS5HyDE.o ./src/EPSCommands.o ./src/EPSCurrentSensor.o ./src/EPSFault.o ./src/FS5HyDE.o ./src/HyDEObservation.o ./src/MCDH.o ./src/MCDH_Module.o ./src/PDBComponent.o ./src/PowerSystem.o ./src/Program.o ./src/SSPCComponent.o ./src/Telemetry.o ./src/TelemetryReport.o -l:libboost_thread-vc90-mt-gd-1_42.lib -lHyDE
This is definitely not a library ordering problem because I've the other ordering as well (there are only two). Is it possible that there is a problem with compiling HyDE.lib in VC++ (which uses a Windows compiler) and compiling my program with g++? Could there be a problem in the way that Eclipse CDT is autogen'ing the makefiles? Any other ideas?
(Note: there appear to be plenty of others questions on SO with similar problems, but after reading through them I have yet to find one that addresses my problem.)
Classic missing symbol error. Which source file defines:
HyDEAPI::HyDE::HyDE(HyDESystemModel::SystemModel*, bool)' ?
Was this file added to the compilation? Can you spot it on the command line you pasted?
If this symbol belongs to an external library, after adding the directory path with -L , you could add the name of the specific library you want to link with your program using -l.
I'm going to suggest that you try to add to the compilation command the directory path to HyDE.lib, followed immediately by the library name, like this:
-L"C:\path_to_hyde_library" -l:HyDE.lib
and then tell us what happened.
Solution: Since the HyDE library was compiled with the Visual Studios compiler and I'm attempting to build the code that links to it with the Cygwin toolchain the two compilers use different name mangling schemes so that the latter linker can not find the expected symbols in the HyDE library. The only solution that I've found is to recompile the HyDE library with the Cygwin toolchain or compile the new code with whatever compiler Visual Studios is using. (grumble grumble)
./src/FS5HyDE.o and ./src/HyDEObservation.o should be the latest parameter if other object files (*.o files) need them, it means that the most needed object files should be appeared as last as possible in the parameters list.
I am currently building a rather large application, using cmake to generate cross platform build scripts. During this process of putting together the cmake build scripts, I have discovered the pain of gcc link line ordering.
The basic issues is that including static libraries in the wrong order leads to unused library symbols being thrown away that then cannot be found by subsequent dependent libraries.
Thus, I am in the situation where cmake generates a visual studios build system that compiles just fine, but the unix makefiles throw all kinds of "undefined symbol" errors. I have figured out a work around for this - in the add_executable command, I am including the static libraries twice.
My hope is that there is a more standard/better way to deal with this issue. Being that I am not the only developer, and that the majority of regular development is done in windows, I really want a link-order agnostic CMake script. The windows developers just don't deal with this link order issue. On top of that, figuring out the correct order would be very difficult - I do not have that information readily available and there are a lot of static libraries (70 or so).
After searching the internet, I did learn about the -static and -dynamic flags, but getting CMake to include them is non-obvious and gcc complains about not being able to find the dynamic libraries.
Anyway, I welcome suggestions on how to do the right thing.
Did you try disabling the strip? Maybe with something like cmake -DCMAKE_STRIP=/bin/true ..? Maybe that will stop the symbols being thrown out.
I think this is less of a CMake issue, and more of a GCC behavior. This question/answer should help out a bit:
Linker order in GCC
You will have to bite the bullet and modify your CMakeLists.txt files to link properly on Linux. Since the Windows developers don't care, you shouldn't disturb them.
Best,
-dan
Problem:
I'm trying to use a library named DCMTK which used some other external libraries ( zlib, libtiff, libpng, libxml2, libiconv ). I've downloaded these external libraries (*.LIB & *.h files ) from the same website. Now, when I compile the DCMTK library I'm getting link errors (793 errors) like this:
Error 2 error LNK2005: __encode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Error 3 error LNK2005: __decode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Error 4 error LNK2005: __CrtSetCheckCount already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Error 5 error LNK2005: __invoke_watson already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Error 6 error LNK2005: __errno already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Error 7 error LNK2005: __configthreadlocale already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Error 8 error LNK2005: _exit already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir
Documentation:
This seems to be a popular error for this library so, they do have a FAQ entry addressing this issue which ( http://forum.dcmtk.org/viewtopic.php?t=35 ) says:
The problem is that the linker tries to combine different,
incompatible versions of the Visual
C++ runtime library into a single
binary.
This happens when not all parts of your project and the libraries you
link against are generated with the
same code generation options in Visual
C++.
Do not use the /NODEFAULTLIB workaround, because strange software
crashes may follow. Fix the problem!
DCMTK is by default compiled with the "Multithreaded" or "Multithreaded
Debug" code generation option (the
latter for Debug mode).
Either change the project settings of all of your code to use these code
generation options,
or change the code generation for all DCMTK modules and re-compile.
MFC users beware: DCMTK should be compiled with "Multithreaded DLL" or
"Multithreaded DLL Debug" settings if
you want to link the libraries into an
MFC application.
Solution to same problem for others:
Huge Amount of Linker Issues with Release Build Only says:
It seems that your release build is
trying to link to something that was
built debug. You probably have a
broken dependency in your build, (or
you missed rebuilding something to
release by hand if your project is
normally built in pieces).
More technically, you seem to be
linking projects built with different
C Run Time library settings, one
with "Multi-Threaded", another one
with "Multi-Threaded Debug". Adjust
the settings for all the projects to
use the very same flavour of the
library and the issue should go away
Questions:
Till now I used to think that Name mangling is the only problem that may cause linking failures if its not been standardized. Just now I knew there are other things also which can cause same effect.
Whats up with the "Debug Mode" (Multi-Threaded Debug) and "Release Mode" (Multi-Threaded)? What exactly is happening under the hood? Why exactly this thing is causing linking error?
I wonder if there is something called "Single-Threaded Debug" and "Single-Threaded" which again causes the same thing.
Documentation talks something about "Code Generation Options". What Code Generation Options? WTH are they?
Documentation specifically warns us not to use /NODEFAULTLIB workaround. (example /NODEFAULTLIB :msvcrt ). Why? How would I cause troubles? what exactly is it?
Please explain the last point in the documentation for MFC users. Because I'm going to use MFC later in this project. Explain Why should we do it? What troubles would it cause if I don't.
Anything more you'd like to mention? I mean regarding similar errors. I'm very interested in Linker & its problems. So, if there are any similar things you can mentions them or some keywords atleast.
Whats up with the "Debug Mode"
(Multi-Threaded Debug) and "Release
Mode" (Multi-Threaded)? What exactly
is happening under the hood? Why
exactly this thing is causing linking
error?
The linker drags in libraries for several different reasons. The simplest is that a library is listed on the linker command line, or in the linker answer file on the linker command line. But any object files, whether compiled in your project or packed into a library, can also contain linker options including requesting particular libraries be linked in. In fact, the Visual C++ compiler automatically embeds such linker options matching the project options you use when compiling.
At link time, all the linker options from all object files and objects in static library files get combined. If more than one CRT library filename is requested, the linker reads in all of them and them you get naming conflicts, where the linker doesn't know which one to use.
I wonder if there is something called
"Single-Threaded Debug" and
"Single-Threaded" which again causes
the same thing.
There used to be, but the last few versions of Visual C++ have only shipped multi-thread compatible libraries.
Documentation talks something about
"Code Generation Options". What Code
Generation Options? WTH are they?
Look inside your project options.
Documentation specifically warns us
not to use /NODEFAULTLIB workaround.
(example /NODEFAULTLIB :msvcrt ). Why?
How would I cause troubles? what
exactly is it?
If you use /NODEFAULTLIB, all the linker settings stored within object files and objects in libraries get ignored. You'll end up with no runtime library and maybe missing other libraries. You can add them back in by hand, but it's still a big mess.
Please explain the last point in the
documentation for MFC users. Because
I'm going to use MFC later in this
project. Explain Why should we do it?
What troubles would it cause if I
don't. Anything more you'd like to
mention? I mean regarding similar
errors. I'm very interested in Linker
& its problems. So, if there are any
similar things you can mentions them
or some keywords atleast.
MFC applications and the MFC library have to use the same memory management functions, so that memory allocated by MFC can be freed by the application and vice-versa. FILE handles and other resources are also shared. The MFC DLLs are already compiled to use the CRT in a DLL, and in order to be able to share resources you need to use the same CRT, which means using a DLL too.
You need to configure project properties so that your debug build links with DCMTK's debug build and your release build links with DCMTK's release build.
The above is what you need to do. Below are explanations of some other random things you asked about.
Older versions of Visual Studio used to have single threaded libraries (release and debug versions) besides multithreaded libraries (release and debug versions). For your project you can pretend single threaded libraries never existed.
If you experiment with random ways to trick the linker into shutting up and leaving problems to be found by your customers instead of by yourself, you might find that the /NODEFAULTLIB option will do that. The makers of the DCMTK library are warning you not to do that because some other people did the same dumb thing in the past.
Whats up with the "Debug Mode" (Multi-Threaded Debug) and "Release Mode" (Multi-Threaded)? What exactly is happening under the hood? Why exactly this thing is causing linking error?
They are different versions of the C runtime library. You can statically link to the runtime library in debug and release mode. In the Code Generation Options (mentioned below), those would be "Multi-Threaded Debug" and "Multi-Threaded". The options "Multi-Threaded Debug DLL" and "Multi-Threaded DLL" dynamically link to the C runtime. By dynamically linking to the runtime, you'll also have to ship your installer configured to install the VC redistributable package that contains the proper runtime dlls for your version of Visual C++.
Statically linking to the C runtime is generally frowned upon, even by Microsoft:
In addition to all the methods
described above of distributing the
Visual C++ libraries DLLs, there is
one last option for building your
application which does not require you
to distribute the DLLs. However, this
option only works for native-only code
(it is not supported with /clr) and
leaves your customers seriously
vulnerable to any security holes as
well as adds a significant burden upon
yourself to patch all customer systems
should a vulnerability be found in any
of the libraries. This option is to
statically link in the libraries as
.lib files instead of dynamically
loading them as DLLs. You do this by
using the /MT flag on the cl.exe
command line (vs /MD), or selecting
the appropriate option in your project
properties through Visual Studio. You
may wish to use this option when
testing early debug builds of your
application on test machines before
you start working on setup. [See
footnote 3]
However, I can think of no scenarios
in which this is actually the right
thing to do when shipping your product
to customers. Basically, what this
approach does is pulls in the binary
code needed from .LIB files at compile
time, making it a part of your .exe or
.dll files. It increases the size of
your application, and there is no way
to update the libraries apart from
recompiling your application with new
.LIBs and redistributing your
application all over again. What this
means is that unless you go touch
every single machine which has
installed your application every time
there is a security vulnerability
found in the Visual C++ libraries and
completely reinstall your updated
binaries, you will be leaving your
customers vulnerable to attack. If
instead you use the DLLs, every time
there is a security vulnerability
found in the Visual C++ libraries,
Microsoft will install the update
centrally into the WinSxS folder via
Windows Update and all requests for
the DLLs will be redirected to the
updated version. This removes all
servicing burden on your side and also
allows the user to install one small
update which will touch all their
applications instead of replacing
every installed exe and DLL on their
system. Please, do not distribute an
application built by linking
statically against the Visual C++
libraries unless you have a system in
place for updating every customer
machine and also have a very good
reason to do so. At this time, I can
think of no circumstance under which
this would be the right thing to do
for a shipping application.
I wonder if there is something called
"Single-Threaded Debug" and
"Single-Threaded" which again causes
the same thing.
No such thing, see above.
Documentation talks something about "Code Generation Options". What Code Generation Options? WTH are they?
Right click on your Visual C++ project (from within Visual Studio) and select Properties. Under Configuration Properties->C/C++->Code Generation
Documentation specifically warns us not to use /NODEFAULTLIB workaround. (example /NODEFAULTLIB :msvcrt ). Why? How would I cause troubles? what exactly is it?
Take their advice and don't do it.
Please explain the last point in the documentation for MFC users. Because I'm going to use MFC later in this project. Explain Why should we do it? What troubles would it cause if I don't.
Because MFC is dynamically linked to the C runtime, using libraries that are statically linked to the C runtime will cause the linker errors you listed first in your post.
Anything more you'd like to mention? I mean regarding similar errors. I'm very interested in Linker & its problems. So, if there are any similar things you can mentions them or some keywords atleast.
From my experience, always dynamically link to the C runtime. It generally saves you a lot of headaches like the one you're experiencing right now.