Mysterious "unresolved symbols" linker errors when compiling against large static lib - c++

I am receiving a lot of strange LNK2001 and LNK2019 errors when attempting to compile and link against a somewhat large static library (developed in-house). Here are the facts:
There are several static libs (most built in-house) all compiled into one large wrapper static lib for public consumption ("Pimpl" idiom). Essentially, we have libs A, B, and C all compiled into an internal/private lib called D. Then, we have an external/public lib that wraps around D called E.
The final product is not an executable, but a plug-in for Adobe Illustrator. Plug-ins are essentially just a DLL with a couple special resources and a special entry point (PluginMain() function). Compiling and linking works just great until I use the /INCLUDE option to specify that PluginMain should always be exported.
Creating a plug-in and linking against lib D works fine (no errors whatsoever). Creating a plug-in and linking against lib E gives over 100 unresolved symbol errors (symbols that should be present in E).
When I run DUMPBIN on the E.lib file, it appears to have all the symbols that the linker is complaining about when trying to create a plug-in. However, I'm not entirely certain I understand all the output syntax from DUMPBIN...
The libs are all cross-platform and compile and link just fine with GCC/LLVM on Mac.
Most of the functions that the linker complains about are either plain functions or static member functions. Most of those look suspiciously like functions that the compiler might try to inline. I have tried disabling optimization and/or automatic inlining, but the same link errors are still present.
Can anyone point me in the direction of some compile and/or link settings that might resolve the issue? Settings that are commonly misconfigured in situations like this?
Perhaps there is a setting I missed that is causing the linker not to export these symbols when linking E? Perhaps there is a setting that forces the linker to export ALL symbols when linking E that I can try? Maybe a utility exists to help me inspect the lib symbols myself for a clue?
I feel like I've tried everything, but it never hurts to ask. Thanks all.
EDIT 1: snowdude requested an actual link error:
E.lib(PathArt.cpp.obj) : error LNK2001: unresolved external symbol "private: __thiscall E::PathSegPoint::PathSegPoint(struct D::PathSegPoint const &)" (??0PathSegPoint#E##AAE#ABU0D###Z)
I should add that E::PathSegPoint::PathSegPoint(const D::PathSegPoint&) is a private constructor for constructing an external/public consumable E::PathSegPoint object from an internal/private D::PathSegPoint object. Again, this is the "Pimpl" idiom. Some classes/functions are friends of E::PathSegPoint to enable this sort of construction.

I thought I'd post an answer in case anyone shows up to this page in the future.
For several reasons a few years ago, we started compiling these libraries with the Intel C++ compiler inside Visual Studio. Some of these reasons have changed, and we needed to switch back to the MSVC compiler. Upon switching to the MSVC compiler, these linker errors disappeared!
I don't know why or how the Intel C++ compiler developed these link problems, but it's entirely possible that this is a bug.

Related

Understanding and resolving the linker warning "ld: warning: direct access in function 'Foo' to global weak symbol 'Bar'

I'm working on multiple VST3 audio plugin projects for macOS. Technically, an audio plugin is a shared library (.dylib) loaded by a host application at runtime via dlopen. I'm linking both plugins against a self-built static version of protobuf 3.20.0 and I'm building my plugins using CMake.
I now had a bug where both plugins defined a protobuf message with the same name, so both plugins defined symbols with the same name but different content and as soon as I loaded the second one crashes occurred. The call stacks revealed that both protobuf messages interfered with each other, as e.g. destructors invoked in plugin a ended up calling the destructor symbol in plugin b.
Specifying CXX_VISIBILITY_PRESET hidden on my CMake target that encapsulates the protobuf library dependency and the plugin-specific protobuf messages, solves the problem, but leaves me with linker warnings like
ld: warning: direct access in function 'google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>* google::protobuf::Arena::Create<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet> >(google::protobuf::Arena*)' from file 'plugin_artefacts/Debug/libplugin_SharedCode.a(Message.pb.cc.o)' to global weak symbol 'typeinfo for google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>' from file '/path/to/lib/libprotobuf.a(descriptor.pb.o)' means the weak symbol cannot be overridden at runtime. This was likely caused by different translation units being compiled with different visibility settings.
I found a lot of posts that simply suggest to build everything with -fvisibility=hidden but none that actually has an in-depth explanation about the actual problem that this warning is about.
What I got so far is that libprotobuf.a defines the symbol in question as a weak symbol, that means a symbol that can be overridden at runtime. Right? This aligns with the output of
objdump --syms --demangle libprotobuf.a
which reveals something like
0000000000010470 w O __DATA,__const typeinfo for google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>
so, yes there is a weak symbol in there.
However, I don't quite get if and why this is problematic? As far as I get it, this symbol should only be relevant internally to my plugin and does not need to be exposed public anyway, so is there any need/benefit in it being declared weak? And why is it a weak symbol at all? If I get it right, this is a compiler generated symbol. Can I even alter the visibility of it? Should I?
I tried re-compiling libprotobuf.a with -fvisibility=hidden as additional entry in the CXXFLAGS environment variable before running the protobuf configure script, but inspecting the output still revealed the symbol being declared weak. Now I'm not sure if this is just because I passed the flag in a wrong way to the configure script (other flags handled the same way seem to have an effect though) or if this is just not the right thing to do.
In any case, after experiencing the bug described above, I would prefer to gain a deep understanding of the issue and then pick the right solution based on that understanding rather than just applying some compiler option to make it work without knowing what happened and what other unexpected side effects that could employ.
Links to blog posts etc. which discuss this topic in depth are also highly welcome – I rarely found anything like that during my own research.

Unresolved external symbol linking to a VS6 library

I've got an NIUSB8452 DAQ, with which the vendor thoughtfully provided ni845x.lib and ni845x.h so I could use C instead of LabView to do my data reading. However, I'm having some problems with getting the lib working in VisualStudio 2015. The first point of alarm is probably that their documentation says it is compatible with VS6, but I've seen other people on here successfully use libraries for VS6 on VS15, so, I hope I can also be so beautiful.
The problem that I am having right now is that on a build, I'm getting linker errors that read something like
unresolved external symbol #ni845xStatusToString#12 referenced in function (function name follows)
While googling around, I found this question which mentioned dumpbin /exports. To check that I wasn't running into a 32/64 bit error like the poster described (since I wasn't really sure how to diagnose this, it seemed as good a place to start as any), I ran dumpbin /exports on the external lib. I got a pile of public symbols, including
FF06 __imp__ni845xStatusToString#12
FF06 _ni845xStatusToString#12
I'm definitely not seeing #ni845xStatusToString#12, which is what VisualStudio is complaining about being unresolved.
What's the difference between #ni845xStatusToString#12 and _ni845xStatusToString12? What does the presence of the latter and the absence of the former indicate that I am doing wrong with this import?
Notes
The lib and header have been included in the file as described in this question, with the exception that I gave a full path to the lib for #4, which I think implies you only need the filename.
I'm using extern "C" { #include ni845x.h } in my cpp file, although ni845x.h does have the #ifdef __cplusplus boilerplate in there.

Linking to ARPACK from VS2010

I am trying to get the ARPACK library to run on VS2010.
I would like to use the C++ wrappers
provided by ARPACK++ (some background - i need to get eigenvalues and eigenvectors of huge matrices). There is a very good tutorial on the subject here.
Following the
tutorial i've managed to compile the fortran code using g77 on mingw, i successfully generated
the dll and lib as described. The problem arises when trying to link my visual studio project to the library.
The way i'm trying to link is as follows:
I've made a simple VS2010 C++ console app
i've added the the folder containing ARPACK++ libraries to my "additional include folders"
i've added the lib file to "Additional dependencies"
i've added the directory containg the lib file to my "Additional library directories"
Despite these settings when i try to compile this short test code:
#include "stdafx.h"
#include "arrsnsym.h"
int _tmain(int argc, _TCHAR* argv[])
{
ARrcNonSymStdEig<float> prob(100, 4L);
printf("Bok!");
return 0;
}
I get an error saying:
>arpackcpp.obj : error LNK2001: unresolved external symbol scopy_
1>arpackcpp.obj : error LNK2001: unresolved external symbol snaupd_
1>arpackcpp.obj : error LNK2001: unresolved external symbol sneupd_
I do not understand why the linker can't find the mentioned methods. Inspecting
the .def file generated by the dllwrap utility does indeed mention all these functions
so i am fairly sure they should be available. Still, i feel i'm missing something obvious.
UPDATE (got it working!):
It turns out that i was trying to link a 64 bit program to a 32 bit library, when switching
to x86 in the Configuration settings AND including the generated def file in Configuration Properties -> Linker -> Input -> Additional definition file, it worked for 32bit (however i needed 64). The final solution that worked for me was to cross compile it for Win64 using MinGW and gfortran on linux. That worked surprisingly well and produced a dll to which i could link from a 64bit C++ app in VS. I think i should now go write a tutorial on how to do this :)
My guess is that this is a name-mangling scheme issue. In fortran, it is not well defined what name the symbols will have in the object file's symbol table. For example, a routine named foo could end up in the symbol table as foo,FOO,foo_,foo__ and so on. These days, I don't know of too many compilers that use double underscores (with g77 being the exception). I'm assuming the ARPACK++ wrappers are assuming a single underscore. The solution here is to tell the compiler to use single underscores in the symbol names (with g77, that means using -fno-second-underscore). Note that gfortran is a newer (still supported) open-source fortran compiler which does single underscoring by default. You might want to try to build your code using that compiler as well. (It might produce more optimized output than g77.)

Getting FreeImage to work with Visual Studio 2010

I was advised by some of you not to long ago to use FreeImage as a library for image processing in C++.
I now have some trouble in getting the library to work (still relatively new here).
I've tried loading the various vcxproj and sln tiles and they gave me a blank project. Since there isn't any installation instructions provided for that, I gave up on making it a visual studio solution.
I next tried the old-fashion way of compiling the source code using the Makefile and then adding "FreeImage/Source" to the linker. While the IDE does not raise any red flags when I call functions declared in FreeImage.h, it gave me a bunch of "error LNK2019: unresolved external symbol" during compilation, as if the functions do not exist. What I suspect is that the IDE could not find the .cpp files that define the said functions, but I still get that same problem when I added FreeImage/Source/FreeImage to the linker.
Now when I directly included some of the .cpp files (i.e. Plugin.cpp and FreeImage.cpp) for a test, I get even more unresolved external symbol errors as well as things like "inconsistent dll linkage" for this within... for example FreeImage.cpp:
const char * DLL_CALLCONV
FreeImage_GetVersion() {
static char s_version[16];
sprintf(s_version, "%d.%d.%d", FREEIMAGE_MAJOR_VERSION, FREEIMAGE_MINOR_VERSION, FREEIMAGE_RELEASE_SERIAL);
return s_version;
}
So, I am totally stuck. What am I doing wrong? I felt I've followed the adequate steps in adding library dependencies, such as adding the specific folders that are immediate parents to the relevant .h and .cpp files in C/C++ -> General -> Additional Included Directories and Linker -> General -> Addition Library Directories.
Some help will be greatly appreciated!
Using FreeImage v3.15.3 I had no problems converting the VS2008 project to VS2010.
Also the building worked as expected. But when I linked to the static lib, I got some unresolved externals. First I tried al kinds of tricks setting /MT /MD linking, but that did not solve these linking problem.
After reading Some Newbie's comment I dug into freeimage.h. There I found a macro switch FREEIMAGE_LIB that controls the calling conventions of the function.
Use a #define FREEIMAGE_LIB before including the freeimage.h file. That way you can easily static link to FreeImage.lib

how to avoid "already defined error" in C++

I am gettings these type of errors in a MFC VS6 project while linking the application:
msvcrt.lib(MSVCRT.dll) : error LNK2005: _atoi already defined in LIBC.lib(atox.obj)
I know what it means (a function exists in 2 different libraries); to solve it I should have to exclude one of the 2 libraries (msvcrt.lib or libc.lib).
But if I do this there are all kinds of unresolved external errors. So I would like to keep using both libraries.
Is there any way to tell the linker that I want to use the _atoi function in libc.lib and not in msvcrt.lib (or the other way around)?
Any help or direction would be great.
This error certainly means that you're linking two pieces of codes that have been compiled using distinct runtime libraries. MSVCRT.dll is the dynamic version, while LIBC.lib is the static one. If you do this, all hell break loose. Try finding which parts of your code use which version, and sort this out.
You have a runtime clash. Using multiple runtime libraries is generally a bad thing.
You can use /nodefaultlib:msvcrt (or /nodefaultlib:libc) in your linker options to exclude one or the other.
Actually, before resorting to that, check your project settings. If I recall correctly, libc is the single-threaded runtime in VS6, and msvcrt is the multi-threaded runtime. If you have multiple projects in your solution, make sure they're all using one or the other.
There seems to be an option which you can use to ignore errors like this: in projectsettings > link > check 'Force file output'. This will generate the program even if there are linkerrors.
The Build output gives something like this:
msvcrt.lib(MSVCRT.dll) : warning LNK4006: _atoi already defined in LIBC.lib(atox.obj); second definition ignored
Of course you will need to use this option with care as it can generate an application which won't work in some cases, but here it probably doesn't do any harm (I hope).
Thank you for the other replies, but that didn't seem to be an option in my particular case.