Linking to a C library compiled as C++ - c++

I'm in linker paradise now. I have a C library which only compiles in Visual C++ (it probably works in gcc) if:
I compile it as C++ code
Define __cplusplus which results in all the declarations being enclosed in extern "C" { }
So, by doing this I have a static library called, say, bsbs.lib
Now, I have a C++ project called Tester which would like to call function barbar in declared in bsbs.h. All goes fine, until I try to link to bsbs.lib where I get the all-too-familiar:
Tester.obj : error LNK2001: unresolved external symbol _foofoo
And it always seems to be foofoo which cannot be resolved regardless of which function I call in Tester (barbar or anything else).
Update: I've expanded on Point 2 as requested. Thanks a lot for the help guys!
#ifndef _BSBS_H
#define _BSBS_H
/* Prevent C++ programs from name mangling these definitions. */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <setjmp.h>
.......
.......
#ifdef __cplusplus
}
#endif
#endif /* _BSBS_H */
This is the "main" header file, so to speak. All the important functions are here. But there are other header files called by the bsbs.c file which are not enclosed in extern "C" {}.
Solved:
OK, this is quite weird, but I removed the extern C bit from the header file in bsbs, compiled it as a C++ project (even though all the files are .c and removed the __cplusplus define) and it worked! I got the idea after looking at the symbol list. Everything was mangled except the ones enclosed in extern C (doh) and it was asking for an unmangled symbol so I figured something was amiss.

If you declare them as extern C in the lib (which is unnecessary, if you're calling them from C++), then they must be extern C in your headers.

There may be a dependency in the c library you're not including in your link. Does the c library you're including really a reference to a DLL? If so there's a program called 'depends' which will tell you what the other required DLL's are.

I'm assuming you've added a linker reference. E.g.:
#pragma comment(lib, "bsbs.lib")

Perhaps the compiler/linker combination needs to be made aware of which APIs are to be exported/imported? If so I'd try adding the appropriate __declspec (e.g., dllimport and/or dllexport) to the C++ library.

Does your lib file import any other lib files? You can compile a lib file to either explicity link lib files or implicitly. One way you get the lib files in a huge ball, the other you get them as separate libs that all need linked at compile time in the final app. If foofoo is imported in your lib file from another lib file, then include that lib file in your final project. This is my best guess from what you described, and is by far the most common thing I get asked when dealing with lib files thru co-workers..

Related

What are the reasons stopping me from correctly linking a static library in VS2010 to my .dll

I'm trying to link a static library in VS2010 to my .dll and for some reason it won't resolve the required symbols. I've added the library like you would any library, but still no go. I'm also calling the symbols exactly as they should be, I'm copying someone else's implementation that works so they can't be wrong. Is it some kind of setting that I'm missing maybe? I've done a lib.exe /dumpall and everything looks to be in order. Very frustrating.
After checking the link to the library, I see that the source are all C Source files, and none of the header have extern "C" for the function declarations.
That means if you include the header files into your project, the function declarations will have mangled names, names (symbols) that no longer matches the ones in the library.
Either you should declare the functions you use yourself with extern "C" or wrap the inclusion of the header files with extern "C" { ... }.

How do I fix an Unresolved External Symbol error in my C++ DLL?

I have a dll, which accesses some classes outside of its project (I'm using Visual Studio, so I have two projects). The thing is, in the header that the dll includes, which is outside of the dll's project, there are only bodies of functions, like this:
x.h
class x
{
void myFunc();
}
And in another cpp file, outside of the dll file:
#include "x.h"
x::myFunc()
{
//.....
}
The dll is only getting the bodies of the functions, so when I compile, I get lots of unresolved external symbols (I'm quite sure that this is the issue, because I tested with another class fully built in a .h file, in another project, and no errors). So how can I solve this mystery?
It is normal for the import headers to only have function signatures; the actual function bodies are already compiled into the DLL binary and are resolved at link time by linking into the actual DLL.
The first thing to try is to make sure you are actually linking to the said DLL. It isn't enough to just include the header, you also need to link to the binary. So in your project configuration, you need to add a link to (for example) the .lib file that gets created along-side the DLL when the DLL is compiled (if in MSVC). This lib file lets the linker know how to connect the function signatures you included via the import header to the actual implementations contained in the DLL. If you're on a different platform, the mechanics might be a little different, but the concepts will be similar.
Edits:
The next step is to make sure the binary is actually exporting the symbols you're trying to link against. Make sure that all interface signatures are being exported via __declspec(dll_export) prefixes. Normally this is wrapped up in an IFDEF so that the header is declared export while the DLL is being compiled, but not when that header is included in a client project. Next, you could use dumpbin to check the mangled export names, and see if there is anything unexpected.
Here's a modified version of your example that illustrates this style of export (note, I haven't tested if this compiles, apologies for any typos):
#ifdef BUILDING_MYDLL
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class MYDLL_API x
{
void myFunc();
}
You would then set your configuration to define BUILDING_MYDLL when compiling the dll, but not when compiling the executable. This way the functions are only marked export when compiling the library dll. Now you can mark your public API functions with MYDLL_API and they should get exported during build.
Please note that dll_export, dll_import, and declspec are all very MSVC-specific constructs. Other compilers/runtimes handle symbol export in different ways.
There's multiple ways to link DLL into your app on Windows, check out this existing question/answer:
https://stackoverflow.com/a/2060508/1701823

Apple Mach-O Linker Error, due to file extension

The dreaded typical linker error..
ld: symbol(s) not found for architecture armv6
collect2: ld returned 1 exit status
However, it is caused by filename? I use C++/Objective-C, so all of my Obj-C files are .mm, but I can never use any .c files. For example I've included the SFMT algorithm in my project, which was giving me these errors, but just changing the single .c file to .cpp made it go away and the code works just fine! I am only including the headers, so I'm not sure why this makes any difference.
The problem now is I'm trying to include Freetype2, giving me the same issue (pretty sure it's because it's .c), but that is far too large to rename every file, and I'm also using a linked binary, so unless I recompile it with new filenames, I can't change that. So now it's time to find the real reason behind this.
Any idea why this would happen? How can I stop linker errors for .c files?
Wrap your Freetype includes within an extern "C" directive:
// Non-C includes
#include <iostream>
extern "C"
{
#include <freetype/freetype.h>
// ... Other freetype includes
}
You can probably use #import instead of #include within an extern "C" directive. I've never tried, but I don't see why it wouldn't work.
Surround your c header file with this. This can also surround the include:
#ifdef __cplusplus
extern "C" {
#endif
// function declarations etc if this is your own header.
// OR you can use this in the .mm file to surround your include.
//...
#ifdef __cplusplus
};
#endif
This specifies external linkage for your c functions.
If you don't do this when you include your c .h files the C++ compiler will mangle in a different way from the C compiler, and cause problems for the linker.
By using extern "C", you are telling your C++ compiler to use C-style mangling of the functions.

How do I use C Headers in a C++ Program?

I am working on a project in Visual Studio 2010 which is to produce a win 32 dll file. The examples I have are C files and the compile and work well. I would like to incorporate some functionality from C++ function I've written but I have hit a bit of a wall.
If I attempt to link the C++ functions to the C program, it knows nothing about strings, etc and just doesn't work at all (of course).
So I am left with changing the example into a C++ program, then I can use my other files with impunity. When I attempt to do this I get a link error that I don't understand and am uncertain about how to resolve.
The examples use vendor provided headers, which include statements such as
typedef void ( __cdecl *BINDING_PROC_BEVNT)(WORD_T choice, INT_T * pStatus,
I_EVNT_T * pIn, O_EVNT_T * pOut);
In the body of the main code, following the examples:
extern BINDING_PROC_BEVNT b_evnt;
Which then allows you to write
b_evnt(choice, &status, &inpEvent, &outpEvent);
In a vendor provided C file, these are again referenced as:
BINDING_PROC_BEVNT b_evnt;
b_evnt = (BINDING_PROC_BEVNT)GetProcAddress(hCNCMod, "bevnt");
The linker error I am seeing is:
error LNK2001: unresolved external symbol "void (__cdecl* b_evnt)(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)" (?b_evnt##3P6AXGPAFPATI_EVNT_T##PATO_EVNT_T###ZA)
If I rename my main file and recompile as a C program, and omit my C++ functions, everything compiles perfectly. Even when the main file is processed as a C++ file, Intellisense seems to recognize the definitions (hovering over shows the correct definitions).
Additionally I attempted to add extern "C" to a few different locations but it didn't seem to make a difference in the C++ files, and generated a compile error in the C files (about not knowing about strings).
Any insight would be appreciated, I may have simply stared at this too long today to be picking up on something obvious, or it may be something I'm completely unaware of.
Thanks for the help!
If you are compiling against a library that has C-language bindings, you have to tell C++ explicitly that the header files for the library reference C-objects, not C++ objects, or C++ name mangling will prevent correct linking. Often you can do this like so:
extern "C" {
#include "vendor.h"
}
This will tell the C++ compiler that the symbols between the braces are C symbols, and should not have name mangling applied.
To include a C header file from C++, do something like this:
test.cpp
extern "C" {
#include "c_header_file.h"
}
It sounds like the above is what you might need to do to include the vendor header file in your C++ code.
Relatedly, to make a header file automatically work for both C and C++:
c_header_file.h
#ifdef __cplusplus
extern "C" {
#endif
void f(int);
// all declarations go here
#ifdef __cplusplus
}
#endif
Not all vendor-provided header files will contain the above __cplusplus detection, so you will have to wrap them manually in extern "C" as in the first example.
error LNK2001: unresolved external symbol "void (__cdecl* b_evnt)
(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)"
(?b_evnt##3P6AXGPAFPATI_EVNT_T##PATO_EVNT_T###ZA)
That means, the C++ mangled variable b_evnt can't be found. That's true, because it should've been C mangled (just an _ prefix). To fix that, tell it to the compiler in the header when compiling for C++:
#ifdef __cplusplus
extern "C" BINDING_PROC_BEVNT b_evnt;
#else
extern BINDING_PROC_BEVNT b_evnt;
#endif
If that's all, you're done. If there are more symbols you need, you might want to use Greg's solution instead - but be aware that that is also not a fixall.
Your vendor provided headers are being included in a C++ compilation unit, but they aren't prepared for C++. So the declarations of the functions are being compiled with name mangling the C++ compielr requires to support overloading.
The headers need to be wrapped in an extern "C" {} block to let the C++ compiler know that these declarations use a C linkage.
Probably the easiest way to do this it to use your own wrapper headers that do something like:
#ifndef FOO_WRAPPER_H
#define FOO_WRAPPER_H
#if __cplusplus
extern "C" {
#endif
#include "foo.h"
#if __cplusplus
}
#endif
#endif
And include yiour wrapper header instead of the vendor's header - the wrapper will work for wither C or C++ compiles.
Also, contact your library vendor and let them know they should make these changes - users of the library shouldn't have to do this workaround to use the library from C++.

About inconsistent dll linkage

How can I remove this link warning? You can see code segment that causes this warning.
static AFX_EXTENSION_MODULE GuiCtrlsDLL = { NULL, NULL };
//bla bla
// Exported DLL initialization is run in context of running application
extern "C" void WINAPI InitGuiCtrlsDLL()
{
// create a new CDynLinkLibrary for this app
new CDynLinkLibrary(GuiCtrlsDLL);
// nothing more to do
}
warning C4273: 'InitGuiCtrlsDLL' : inconsistent dll linkage
I have also export and import definitions, like:
#ifdef _GUICTRLS
#define GUI_CTRLS_EXPORT __declspec(dllexport)
#else
#define GUI_CTRLS_EXPORT __declspec(dllimport)
#endif
The purpose of the preprocessor statements:
#ifdef _GUICTRLS
#define GUI_CTRLS_EXPORT __declspec(dllexport)
#else
#define GUI_CTRLS_EXPORT __declspec(dllimport)
#endif
is to make sure that the header file declares the class or function as __declspec(dllexport) in the .dll where it is defined, and as __declspec(dllimport) for any other .dll that might want to use it.
For this to work, _GUICTRLS must be defined when compiling the exporting .dll, and not defined for any other .dll. Generally you would expect _GUICTRLS to be defined in the project properties, under C/C++ -> Preprocessor -> Preprocessor Definitions.
The compiler error you are seeing usually happens because either _GUICTRLS is not defined for the project that is doing the export, or it is defined for multiple projects, usually resulting from cutting an pasting from one project to another. You will also see this if _GUICTRLS is defined in a header file that is included in multiple projects.
There are multiple possibilities:
1) static AFX_EXTENSION_MODULE GuiCtrlsDLL = { NULL, NULL };
You use AFX_EXTENSION_MODULE. This means that you are implementing an MFC extension DLL. For such extension dlls you have to define the preprocessor _AFXEXT. Set this in the C++ compiler settings of your Visual C++ project
see:
How To Use _declspec(dllexport) in an MFC Extension DLL: http://support.microsoft.com/kb/128199
AFX_EXTENSION_MODULE Structure: http://msdn.microsoft.com/en-us/library/sxfyk0zk.aspx
TN033: DLL Version of MFC: http://msdn.microsoft.com/en-us/library/hw85e4bb.aspx
2) It is likely that you have a duplicated definiton/declaration.
In addition to reading the warning message, pay attention to where it occurs if you have multiple projects as part of a workspace.
I wasted time looking for a problem in my DLL which was compiling and linking correctly. The workspace was also building the main application and my error was that I had inadvertently included a new (DLL) source file into the build file list of the application itself.
The main program requires the DLL header mynewdll.h to import things but does not require the source file mynewdll.cpp. (The code is brought in at run time with a DLL.) I have a habit of including header and code files into projects as a pair, and this is where I had gone wrong.
I would have detected the error much sooner if I had been alert and noticed that the DLL project linked with no errors and it was the main program that complained!
My DLL source code and project was error free and it was only the way I tried to build my executable that was faulty.
That warning is usually caused by a duplicate definition of a function with different use of dllimport. Are you sure you didn't do this?
[ CMake inconsistent dll linkage ]
I encountered the following issue + solution with the __declspec(dllexport) + __declspec(dllimport) :
# # #CMakeLists.txt
add_defintions(-DMYLIB=1)
# The above was the solution...
# (MYLIB is used in the standard ifdef + define MYLIB_EXPORT syntax)
# Below: seems to get overruled by other directory's headers:
set_source_files_properties( file1.h file2.h COMPILE_FLAGS "-DMYLIB=1")
This was annoying because a number of sources say to use the 'set source file properties' command to get better granularity but the doc is not clear on what happens to file1.h's declares when included from a different directory... better stick with add_definitions( -DMYLIB=1 ) for now!
To catch this problem: in your Foo.cpp file:
#include "export.h"
#if defined(MYLIB)
#if defined(OTHERLIB)
static_assert(0,"error, check your definitions!");
// OTHER depends on MY; can't have both of these flags being set!
#endif
#endif
struct OTHER_EXPORT foo
{
};
See that you are not defining the exported symbols in a different project. Also clean all the intermediate files by hand and recompile.
To elaborate the answer of damian with an example. I read it but didn't understand at first glance.
You have a shared library with a source file compiled in that contains the function. In a new project you use the library and in addition you compile also the source file to use the function (I forgot that it is already in the library). Within the library the functions label is exported, within the additional compiled source file the functions label is marked to be imported. That's the conflict.
In my case, error C4273 was caused by trying linking to .lib file from a DLL dynamic load tester app in Qt5 by msvc2017_64 toolchain. Removing the reference to .lib file by changing LIBS setting in .pro file have the problem solved.