MSVC name mangling - c++

I am trying to build Lua and QtLua with MSVC 2015 x86 and I have encountered an issue with exported/imported symbols.
Here is what I do forbuilding Lua 5.3.2 (source):
cl /MD /O2 /c /DLUA_BUILD_AS_DLL *.c
ren lua.obj lua.o
ren luac.obj luac.o
link /DLL /IMPLIB:lua5.3.2.lib /OUT:lua5.3.2.dll *.obj
link /OUT:lua.exe lua.o lua5.3.2.lib
lib /OUT:lua5.3.2-static.lib *.obj
link /OUT:luac.exe luac.o lua5.3.2-static.lib
So far it works and dependancy walker shows that functions are exported without any mangling.
Then I build QtLua using cmake and I'v got about 100 errors like:
error LNK2019: unresolved external symbol _lua_close referenced in function "public: virtual __thiscall QtLua::State::~State(void)" (??1State#QtLua##UAE#XZ)
So basically my issue is that the DLL exports lua_close and the linker looks for _lua_close.
After a bit of searching the _lua_close format seems legit as Microsoft documentation states that C symbols called with __cdecl are mangled with a '_' prefix.
However I don't get why the DLL exports unmangled names.
Function declaration when compiled in Lua (C files)
__declspec(dllexport) void (lua_close) (lua_State *L);
Function declaration when compiled in QtLua (C++ files)
extern "C" {
extern void (lua_close) (lua_State *L);
}

Quick answer
MSVC did not found the lua DLL (or lib).
Long answer
Exported C functions called using __cdecl are not mangled, whereas internal C functions called using __cdecl are mangled with a '_' prefix.
Source: http://wyw.dcweb.cn/stdcall.htm
To fix my issue I took all source files from QtLua and created a qmake project from them. And tadaa! It works! (Well, it doesn't because QtLua doesn't seem to be tested on anything else than gcc, but I got rid of this linker problem).
My conclusion is that:
MSVC complains about not finding _function and is in fact looking for function (or maybe both).
CMake, even if it found the lua library at config time, failed to pass the proper options to the linker at build time.

Related

Tensorflow 2.3 unresolved external symbols in machine-generated files when building C++ project on Windows

I was wondering if anyone has had success linking against Tensorflow 2.3 DLL on Windows.
I am trying to integrate some tensorflow functionality in a tiny VS2019 test project to see if I can use tensorflow C++ API at all.
I managed to build tensorflow with MSVC 14.16.27023 and followed the instructions given in the official links:
https://docs.bazel.build/versions/master/windows.html#build-c
https://www.tensorflow.org/install/source_windows
I built .dll and .lib using the following Bazel commands:
bazel build --config=opt //tensorflow:tensorflow.dll
bazel build --config=opt //tensorflow:tensorflow.lib
VS2019 project properties:
add relevant Additional Include Directories
add Additional Library Directories, which is only path-to-tensorflow-source\bazel-bin\tensorflow, where bazel-bin directory is generated by the build system (ie Bazel)
in Linker->Input->Additional Dependencies add generated tensorflow.lib
The source code is tiny and is comprised of a few lines I looked up in Joe Antognini's example:
#pragma once
#define NOMINMAX
#include "tensorflow/core/public/session.h"
#include "tensorflow/cc/ops/standard_ops.h"
int main()
{
tensorflow::Scope root = tensorflow::Scope::NewRootScope();
auto X = tensorflow::ops::Placeholder(root.WithOpName("x"), tensorflow::DT_FLOAT,
tensorflow::ops::Placeholder::Shape({ -1, 2 }));
}
As explained in Ashley Tharp's guide, building right away results in linker errors complaining about unresolved external symbols:
LNK2001 unresolved external symbol "private: class tensorflow::Scope __cdecl tensorflow::Scope::WithOpNameImpl(...
LNK2001 unresolved external symbol "public: static class tensorflow::Scope __cdecl tensorflow::Scope::NewRootScope(void)"...
LNK2001 unresolved external symbol "public: __cdecl tensorflow::Scope::~Scope(void)"...
LNK2001 unresolved external symbol "public: __cdecl tensorflow::ops::Placeholder::Placeholder(...
Here is the explanation from her guide:
The reason this is happening is because you can only expose 60,000 symbols in a dll. This is just some limitation of the dll format. The tensorflow library code has more than 60000 symbols, so as the programmer building this dll (a dll is just a binary file for accessing a library at runtime) you will have to manually indicate which symbols you want exposed if they are not already. Google has chosen some default set, but it may not work for everyone.
And, as suggested in the guide, I went into tensorflow headers and prepended relevant symbols with TF_EXPORT macro, which is your usual DLL import-export pattern:
#ifdef TF_COMPILE_LIBRARY
#define TF_EXPORT __declspec(dllexport)
#else
#define TF_EXPORT __declspec(dllimport)
#endif // TF_COMPILE_LIBRARY
The above-mentioned workaround works for the first 3 errors:
// scope.h
~Scope(); // change to: TF_EXPORT ~Scope();
...
static Scope NewRootScope(); // change to: TF_EXPORT static Scope NewRootScope();
...
Scope WithOpNameImpl(const string& op_name) const; // change to TF_EXPORT Scope...
After I am done editing, I re-run bazel like so bazel build --config=opt //tensorflow:tensorflow.lib, and errors are gone.
However, the issue arises when I try to perform similar manipulation to fix the last remaining unresolved symbol, namely Placeholder. The symbol is located inarray_ops.h, which is a machine-generated file. So whatever I edit inside the file is overwritten and lost as soon as I try to build .lib.
Question: How can I expose symbols that appear in machine-generated files? Pointers in the right direction would be much appreciated, perhaps I'm missing something obvious.
The folder containing dynamic library tensorflow_cc.dll and import library tensorflow_cc.dll.if.lib has also two files:
tensorflow_filtered_def_file.def : contains import symbols
tensorflow_cc.dll-2.params : has all built libraries
now if you have some unresolved symbols when building your app, all you have to do is to rebuild dynamic-library with updated tensorflow_filtered_def_file.def file. To this file you have to add missing symbols, for your sample code, it is:
EXPORTS
??1Scope#tensorflow##QEAA#XZ
?NewRootScope#Scope#tensorflow##SA?AV12#XZ
??0Placeholder#ops#tensorflow##QEAA#AEBVScope#2#W4DataType#2#AEBUAttrs#012##Z
?WithOpNameImpl#Scope#tensorflow##AEBA?AV12#AEBV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z
the rest symbols ...
After you updated .def file, you rebuild dll by calling the following command:
link.exe /nologo /DLL /SUBSYSTEM:CONSOLE -defaultlib:advapi32.lib -DEFAULTLIB:advapi32.lib
-ignore:4221 /FORCE:MULTIPLE /MACHINE:X64
#bazel-out/x64_windows-opt/bin/tensorflow/tensorflow_cc.dll-2.params /OPT:ICF /OPT:REF
/DEF:bazel-out/x64_windows-opt/bin/tensorflow/tensorflow_filtered_def_file.def /ignore:4070
before rebuilding dll/lib remove these files (they are only read-only).
More info here , see rafix07 comment.

Difference in linker-generated name (C++/C) ($$FYZAXXZ - $$J0YAXXZ)

I am having trouble linking my project. I get this error message:
error LNK2019: unresolved external symbol "void __cdecl TimerInit(void)" (?TimerInit##$$FYAXXZ)
The function TimerInit is in a different .CPP file in the same project. When I use DUMPBIN to look at the contents of the corresponding .OBJ file, I see that the compiler generated this symbol:
?TimerInit##$$J0YAXXZ
I can't figure out why that is - 'J0' instead of 'F'. Must be something with calling conventions.
This is with Visual Studio 2008, if that makes a difference.
Using the undname command line tool, we can see that the symbol in the .obj is
Undecoration of :- "?TimerInit##$$J0YAXXZ"
is :- "extern "C" void __cdecl TimerInit(void)"
while the one the linker is looking for is not extern "C".
I don't have access to VS 2008 to check this, but it appears that wherever you define the TimerInit function, it is in an extern "C" declaration of some kind. Newer versions of Visual Studio do not export mangled extern "C" names (TimerInit would be _TimerInit or just TimerInit, depending on the compiler version), and I am unsure what your declarations look like to produce this since you do not show them in the question.
Either remove the extern "C" in the definition of TimerInit, or consider upgrading to a more recent version of Visual Studio.

MSVC Unresolved Eternal Symbols in DLL

Can someone help me understand why MSVC 12 2013 reports these symbols are unresolved?
Error 239 error LNK2019: unresolved external symbol "public: static double const Wm3::Math<double>::DEG_TO_RAD" (?DEG_TO_RAD#?$Math#N#Wm3##2NB) referenced in function "protected: void __cdecl Matt::ExternalNavConverter::CExternalNavConverter::DoProcessExternalNav(void)" (? DoProcessExternalNav#CExternalNavConverter#ExternalNavConverter#Matt##IEAAXXZ) C:\Users\mrussell\workspace\Matt\build-conan-Release\Libraries\MattClient\ExternalNavConverter.lib(ExternalNavConverter.obj) MattClient
The symbol DEG_TO_RAD is defined in my Wml.dll file, which I'm quite sure is in my %PATH% when I start MSVC.
The output from dumpbin for the DLL is:
dumpbin /exports C:\Users\mrussell\.conan\data\wml\3.x\ntc\stable\package\a4501f33ae09df332b76b4d6f0e5cebffbe83874\bin\Wml3.dll | grep -i DEG_TO_RAD
143 8E 00031A64 ?DEG_TO_RAD#?$Math#M#Wm3##2MB
144 8F 00031A98 ?DEG_TO_RAD#?$Math#N#Wm3##2NB
And for the LIB:
dumpbin /exports C:\Users\mrussell\.conan\data\wml\3.x\ntc\stable\package\a4501f33ae09df332b76b4d6f0e5cebffbe83874\lib\Wml3.lib | grep DEG_TO_RAD
?DEG_TO_RAD#?$Math#M#Wm3##2MB (public: static float const Wm3::Math<float>::DEG_TO_RAD)
?DEG_TO_RAD#?$Math#N#Wm3##2NB (public: static double const Wm3::Math<double>::DEG_TO_RAD)
I set up a minimal example showing the failed linking here, unfortunately I'm not sure I can put the headers or .lib file.
I'm not that familiar with dumpbin, I'm more accustomed to nm with c++filt.. But to me, this suggests that the symbol DEG_TO_RAD is exported in the DLL.
In the Linker command line window, I can see that by bin path (path the to DLL) is provided as a /LIBPATH, and the full path to the .lib is provided as well (provided in "Additional Dependencies".)
Could this be because I might be mixing up shared and static libs together? Or a sign that despite me thinking the DLL is in my path, somehow it isn't? Or the symbols in the DLL aren't actually there? (the equivalent of a non-T for the symbol type in nm)
I'm going through the list given in this answer, but so far am just confused as to why it is not working.
The issue was that while the WML symbols were exported properly with __declspec(dllexport), they weren't being imported properly by my app.
In the minimal working example I added a snippit of Wm3Platforms.h where dllexport and dllimport are declared. Typically (in my experience) at least, these are controlled by a single preprocessor definition (if on, do dll_export, if off, do dll_import), but this code demands WM3_DLL_IMPORT is declared to make it importable.
Declaring WM3_DLL_IMPORT fixed my issue.
So, turns out my issue was specific to this lib's source code....

c++ visual studio, unresolved external symbol using .lib file [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
I have inherited a legacy project which utilizes some external functions from a *.lib. From what I was told, the syntax for using the *.lib was correct and this
was buildable in whatever visual studio version they used. (ie, there is an extern "C" prototype file, and all the function signatures are correct).
When building, I get "error LNK2019: unresolved external symbol _A86_ReadConfigReg#12 referenced in function ..."
I'm pretty confident that this is related to the *.lib file since the *.lib file has "A86" in the name...There is also a *.dll with the same name.
I went to project properties -> Linker -> Input and listed the *.lib file name in "Additional Dependencies", but no luck. I tried adding the include directories, copying the *.lib & *.dll to the executable location. But no luck.
How do I go about fixing this error?
First thing you should do is inspect the library to make sure the referenced function is there. Start an msvc developer command prompt, and run dumpbin.exe
Syntax:
dumpbin /exports <full path library name>
This will give you a listing of all exported symbols from the library.
You'll get a clearer idea of what to do from there.
[EDIT]
dumpbin told you that your lib exports a function called A86_ReadConfigReg, which is a __cdecl signature and not a __stdcall signature like _A86_ReadConfigReg#12 that your linker expects.... At least two things you should do/check in order of priority.
Your linker is looking for a pascal call signature and this is very odd. Does your project have __stdcall as a default for function calls? That's controlled by the /Gz switch in Project Properties->C/C++->Advanced->Calling Convention. Default should be set to __cdecl (/Gd)
You should check that your include files enclose all the function declarations in an extern "C" { } block. If they don't, you can place the block around the #include directive, so you do not have to modify the library's files.
Like so:
extern "C" {
#include <mylib.h>
}

DLL and Name Mangling

I have a third-party LIB which has symbols exported as plain C/cdecl, so for example dumpbin.exe /SYMBOLS reports that both __imp_nvmlInit and nvmlInit are exported.
However in Visual Studio 2010 when I try to import them, the header file will have
extern "C" nvmlReturn_t nvmlInit(...);
but when I try to compile, I get the following error:
main.obj : error LNK2019: unresolved external symbol _nvmlInit referenced in function _main
How can I stop Visual Studio from looking for that symbol with a leading underscore? __declspect(dllimport) doesn't work because then it decorates to __imp__nvmlInit (one underscore too many).
Thanks.
That is a linker error. You need to link with the .LIB file associated with DLL, which will give the linker a promise that the function will be available at run-time when the DLL itself is loaded.