Unresolved external link errors with generated DLL in Embarcadero C++ Builder - c++

I am trying to use the AWS Iot SDK in Embarcadero C++ Builder which I am using the Embedded C Version of the SDK. I was trying to use a generated DLL in the RAD Studio IDE but wasn't able to input the functions needed as it was all under namespaces and classes.
Hence why I have resolved to using the Embedded C version of the SDK as talked about in this question because of it's portability. Calling DLL Functions under a namespace in RAD Studio
With the Embedded C version of the SDK, I have again generated it to be a DLL file where I have used the code below to export the data structures and functions with this example below:
#ifdef PUBSNUB_EXPORTS
#define PUBSNUB_API __declspec(dllexport)
#else
#define PUBSNUB_API __declspec(dllimport)
#endif
PUBSNUB_API IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client* pClient, const char* pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params* pParams);
PUBSNUB_API IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);
When I try to call these functions in RAD studio, I get the following errors, even with the generated lib file as instructed copied in the project folder. If I call these functions in a Visual Studio project, it will work completely fine.
[ilink32 Error] Error: Unresolved external '_iotClientConnectParamsDefault' referenced from C:\MICRO PLUS\RELEASE\MAINFORM.OBJ
[ilink32 Error] Error: Unresolved external '_iotClientInitParamsDefault' referenced from C:\MICRO PLUS\RELEASE\MAINFORM.OBJ
[ilink32 Error] Error: Unresolved external '_aws_iot_mqtt_publish' referenced from C:\MICRO PLUS\RELEASE\MAINFORM.OBJ
[ilink32 Error] Error: Unable to perform link

mangling
for static linking you need to use correct combination of switches of implib because your DLL was not created by BCC it contains most likely different name mangling ... try :
implib.exe -c -f -a winusb.lib winusb.dll
or any of the 8 combinations of the switches (rename the winusb with your file).
DLL must match the platform
so if you got 32 bit executable your DLL must be also 32 bit ... otherwise you need a bridge DLL ... In case of windows drivers beware that 32 bit EXE/DLLs on 64bit OS will run in WOW64 which might be problematic accessing real HW insteead of emulated one.
beware older implib versions do not handle 64bit DLLs (create empty 1024 byte libs)
if nothing works use dynamic DLL linkign
see Builder C++ calling VC++ class

Related

Unresolve external symbols when using v8.dll in my project

I'm new to making C++ project. I may be not sure prerequisite knowledge of C++ project.
[My environment]
Windows 10
Python 2.7.18
Developer Command Prompt for VS 2022
Visual Studio 2022 Community
I'm currently straggling with making V8 engine as a DLL and using it.
I've built V8 engine as a DLL successfly but using it I'm facing "Unresolve exteranl symbols" error.
Details:
error LNK2019: unresolved external symbol "class std::unique_ptr<class v8::Platform,struct std::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::unique_ptr<class v8::TracingController,struct std::default_delete<class v8::TracingController> >)" (?NewDefaultPlatform#platform#v8##YA?AV?$unique_ptr#VPlatform#v8##U?$default_delete#VPlatform#v8###std###std##HW4IdleTaskSupport#12#W4InProcessStackDumping#12#V?$unique_ptr#VTracingController#v8##U?$default_delete#VTracingController#v8###std###4##Z) referenced in function "public: __cdecl ezv8::Platform::Impl::Impl(void)" (??0Impl#Platform#ezv8##QEAA#XZ)
I've researched some thing that C++ mangling and compailer behaviours are.
I've noticed that the v8_libplatform.dll.lib file contains other type of mangled symbols like below.
?NewDefaultPlatform#platform#v8##YA?AV?$unique_ptr#VPlatform#v8##U?$default_delete#VPlatform#v8###__1#std###__1#std##HW4IdleTaskSupport#12#W4InProcessStackDumping#12#V?$unique_ptr#VTracingController#v8##U?$default_delete#VTracingController#v8###__1#std###45##Z = ?NewDefaultPlatform#platform#v8##YA?AV?$unique_ptr#VPlatform#v8##U?$default_delete#VPlatform#v8###__1#std###__1#std##HW4IdleTaskSupport#12#W4InProcessStackDumping#12#V?$unique_ptr#VTracingController#v8##U?$default_delete#VTracingController#v8###__1#std###45##Z (class std::__1::unique_ptr<class v8::Platform,struct std::__1::default_delete<class v8::Platform> > __cdecl v8::platform::NewDefaultPlatform(int,enum v8::platform::IdleTaskSupport,enum v8::platform::InProcessStackDumping,class std::__1::unique_ptr<class v8::TracingController,struct std::__1::default_delete<class v8::TracingController> >))
As you can see, the .lib file contains the symbol with __1 namespace.
I found out why the file contains that. A bundled clang compiler compiles std namespace with inline namespace __1 but I'm not sure that how I can change compililng without __1 inline namespace.
Does anyone know how to change the compiler behaviour?
I resolved this problem myself. (But I get still other erros in building.)
What the problem is that I have to add a flag "is_clang = false" to gn args because the clang that is bound v8 will compile other type of manglings to MSVS.
If I added the flag then v8 tools will compile these code with cl.exe you installed.
I had exactly the same linking issue with v8::platform::NewDefaultPlatform() function, as well as some other methods like v8::Context::Scope::Scope(), v8::Context::Scope::~Scope() and so on. And the cause wasn't related with name mangling, it looks like clang-cl (used in v8/chromium by default on Windows platforms) uses the same name mangling as cl does. All these methods are defined in header files so they're effectively inlines, and clang-cl uses /Zc:DllexportInlines- compiler option which doesn't export inlines from DLLs (see https://reviews.llvm.org/D51340?id=172304 for details).
A request for adding /Zc:DllexportInlines option to cl compiler was raised a long time ago: https://developercommunity.visualstudio.com/t/implement-zcdllexportinlines-aka-fvisibility-inlin/374754 , but as of now, cl version 19.34.31937 still doesn't support it.
So I can see no way using v8 DLLs with Microsoft's cl compiler without modifying v8/chromium header files (which is never good). One can build v8 as static libraries, or use clang-cl as a custom build tool.
As for building v8 without clang using is_clang=false gn argument, I wonder if it's actually possible. There are many compiler options like -Wno-unused-const-variable or -Wno-unused-function which aren't supported by cl but added unconditionally in gn build files. I remember years ago it was possible to build chromium using cl, but is it now?

lld-link error compiling chromium with ffmpeg additional calls

After adding some calls to ffmpeg from the ffmpeg_decoding_loop, I have errors when compiling on Windows (both directly on Windows and when cross-compiling from linux).
What I don't understand is that it works without an issue on linux/macos.
I have multiple calls to ffmpeg code but let's boil it down to a representative example.
I call this :
const AVFilter *buffer_src = avfilter_get_by_name("buffer");
On linux/macos : no problems.
On windows :
lld-link: error: undefined symbol: avfilter_get_by_name
>>> referenced by .\..\..\media\ffmpeg\ffmpeg_decoding_loop.cc:111
>>> obj/media/ffmpeg/ffmpeg/ffmpeg_decoding_loop.obj:(public: void __cdecl media::FFmpegDecodingLoop::InitFilterGraph(struct AVFrame *))
>>> referenced by .\..\..\media\ffmpeg\ffmpeg_decoding_loop.cc:112
>>> obj/media/ffmpeg/ffmpeg/ffmpeg_decoding_loop.obj:(public: void __cdecl media::FFmpegDecodingLoop::InitFilterGraph(struct AVFrame *))
Is there some additional configuration to be made on windows ?
I use visual studio 2019, windows 10.0.19041.0 sdk, llvm 10.0.0.
For those who may stumble on this : if you use functions from third_party/ffmpeg in your chromium code make sure those functions are specified in third_party/ffmpeg/chromium/ffmpeg.sigs.
It is only used when compiling for windows (that's why my mac/linux builds where succeeding).

"Shared" linkage works on Linux, not on Windows

Given a big project, which generates an executable on both Linux and Windows architectures, I would like to take some classes (name it BigProjectClassA, BigProjectClassB and BigProjectClassC) to make a kind of plugin and modify the state of objects created from these three classes.
Hence, my tiny own project has code like this:
class TinyProjectExampleClass
{
void modifyA(BigProjectClassA& a) {(...)}
void modifyB(BigProjectClassB& b) {(...)}
void modifyC(BigProjectClassC& c) {(...)}
(...)
};
I'm building this code in order to generate a shared library (I'm coming from Linux background, so I don't know if this is the proper term for a DLL) which will be used within the big project.
When I try to build this on Linux, it is not necessary to link this code against the BigProjectClasses' object code and the big project gets correctly the expected state; however, Windows MSVC2013 linker complains with this error:
error LNK2001: unresolved external symbol "public: void __cdecl BigProjectClassX (...)"
How can I sort this out?

Python in C++: Unresolved external

I try to embed Python in my C++ application, but the linker keeps saying this error:
[ILINK32 Error] Error: Unresolved external '_PyModule_Create2TraceRefs' referenced from E:\CPP PROJECTS\ANDERLICHT\WIN32\DEBUG\ANDERLICHT.OBJ
I'm using Embarcadero C++ Builder XE2, so I converted the python33.lib with coff2omf.exe.
This is my code in main.cpp:
#include "anderlicht.c"
#pragma comment(lib, "python33_omf.lib")
// In main():
PyImport_AppendInittab("anderlicht",PyInit_anderlicht);
Py_SetProgramName(programName.w_str());
Py_Initialize();
In anderlicht.c the Python.h is included. What do I have to do to fix this error?
I had the same problem, but I found a solution that doesn't need rebuild.
If you are developing a new application, you are in debug mode: the compiler defines _DEBUG. In the file "pyconfig.h" (near line 336 for python 3.6.3) you can find:
#ifdef _DEBUG
#define Py_DEBUG
#endif
=> Remove this code.
If you leave that code,you are in Py_Debug mode, so in object.h triggers this:
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif
That in modsupport.h defines this alias:
#ifdef Py_TRACE_REFS
/* When we are tracing reference counts, rename module creation functions so
modules compiled with incompatible settings will generate a
link-time error. */
#define PyModule_Create2 PyModule_Create2TraceRefs
#define PyModule_FromDefAndSpec2 PyModule_FromDefAndSpec2TraceRefs
#endif
So your compiler needs a custom version of Python.
Now enjoy your standard embedded python.
The problem is most likely that you're using different compiler flags in building your code than were used in building the Python DLL. In particular, PyModule_Create2TraceRefs is only defined if you have -DPy_TRACE_REFS (which usually passed in via EXTRA_CFLAGS in the make command on Unix; I have no idea how you do it with Embarcadero C++ Builder on Windows). Usually, this isn't defined—in particular, if you're using a DLL from a pre-build Python binary, it won't have it defined.
So, if you want to have custom flags in building your code, you need to rebuild Python itself with the same flags. Otherwise, you need to get the flags that were used to build Python, and use the same ones when building your code.
On Unix, this is trivial: Just call python3.3-config --cflags and python3.3-config --ldflags to get the flags to pass to your compile and link steps. On Windows, it's less trivial. The Building C and C++ Extensions on Windows chapter in the docs explains how to do it when you're using the same toolchain used to build Python itself (usually MSVC), and if you're using mingw with its MSVC-compat features there's documentation elsewhere on how to do that… but if you're using a different toolchain, you will need to figure some of it out yourself.

Getting "error LNK2001: unresolved external symbol _gnutls_free" when using GnuTLS 3.1.6 from Visual Studio 2012

I am attempting to build a project in Visual Studio 2012 that uses GnuTLS. I downloaded the latest official Windows build from the website, and created a link library by running lib /def:libgnutls-28.def in the bin directory form a Visual Studio command prompt.
After adding a typedef long ssize_t, the code compiles fine, but linking fails with the following error:
source_file.obj : error LNK2001: unresolved external symbol _gnutls_free
C:\Path\to\executable.exe : fatal error LNK1120: 1 unresolved externals
I am calling gnutls_free to free some memory allocated and returned by the library. If I remove the call to gnutls_free, the project links successfully. Given that gnutls_free is just a global variable (containing a function pointer) exported by the library, I'm not sure why accessing it results in an unresolved reference to a different symbol. I have verified that gnutls_free is not #defineed to anything.
As a test, I tried doing gnutls_free_function test = gnutls_free; which also resulting in the link error. Running grep -w -r _gnutls_free . on the GnuTLS source code returns nothing, so I am at a loss.
Any ideas for getting this working would be greatly appreciated.
EDIT:
Adding __declspec(dllimport) to the declaration of gnutls_free in gnutls.h allows the link to succeed. Is there any way to accomplish this without maintaining a custom version of the header file?
There doesn't seem to be a way to have the linker or import library automatically dereference the IAT's pointer to the data item the same way that is done for functions (via a small trampoline function that is statically linked into the module importing the function). The __declspec(dllimport) attribute tells that compiler that this dereferencing needs to be done so it can insert code to perform the dereferencing of the IAT pointer implicitly. This allows exported data to be accessed and for functions allows the compiler to call the imported function via an indirect call through the IAT pointer rather than by calling the trampoline function.
See a couple of Raymond Chen's articles about dllimport for a good explanation of what goes on for function calls (he didn't discuss importing data, unfortunately):
Calling an imported function, the naive way
How a less naive compiler calls an imported function
The MS linker or import library doesn't have a mechanism to help the compiler get imported data in a 'naive' way - the compiler needs the the __delcspec(dllimport) hint that an extra dereference through the IAT is needed. Anyway, the point of all this is that it seems there's no way to import data except by using the __declspec(dllimport) attribute.
If you want to avoid modifying the gnutls distribution (which I can understand), here's one rather imperfect workaround:
You can create a small object file that contains nothing but a simple wrapper for gnutls_free(); since gnutls_free() has an interface with no real dependencies, you can have the necessary declarations 'hardcoded' instead of including gnutls.h:
typedef void (*gnutls_free_function) (void *);
__declspec(dllimport) extern gnutls_free_function gnutls_free;
void xgnutls_free(void* p)
{
gnutls_free(p);
}
Have your code call xgnutls_free() instead of gnutls_free().
Not a great solution - it requires your code to call a wrapper (so it's particularly not great if you'll be incorporating 3rd party code that might depend on gnutls_free()), but it might be good enough.