C++ MinGW shared libraries problem (Windows only,works on Linux)? - c++

Greetings all,
I use MinGW,QT and CMake for my project.
As shown in the figure, my project has two modules.
libRinzoCore.DLL - a shared library which define some abstract classes and interfaces and some core functionality of the application.This module is used to implement dynamic Plugins (which are also shared libraries which automatically loaded by the application) .
Rinzo.exe - the main application.This uses "libRinzoCore" classes.
"libRinzoCore" mainly developed using QT objects and link against the QT library.
"Rinzo.exe" also uses QT library objects,some are not being used in "libRinzoCore".So I have to link QT Library and "libRinzoCore" with this executable.
I can compile "libRinzoCore" without problems and it generated two files "libRinzoCore.DLL" and "libRinzoCore.DLL.a"
But during compiling "Rinzo.exe" it gives the following output :
Linking CXX executable Rinzo.exe
Info: resolving IRzPlugin::staticMetaObject by linking to __imp___ZN9IRzPlugin16staticMetaObjectE (auto-import)
Info: resolving IRzViewerPlugin::staticMetaObject by linking to __imp___ZN15IRzViewerPlugin16staticMetaObjectE (auto-import)
Info: resolving IRzLayeringPlugin::staticMetaObject by linking to __imp___ZN17IRzLayeringPlugin16staticMetaObjectE (auto-import)
C:\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\..\mingw32\bin\ld.exe: warning: auto-importing has been activated without --enable-auto-import specified on the command line.
This should work unless it involves constant data structures referencing symbols
from auto-imported DLLs.
[100%] Built target Rinzo
And when executing "Rinzo.exe" it crashes with the message (this is a translation from Japanese error message)
" Application cannot performe
correctly (0xc0000005). Click [OK] to
cancel "
Here are my CMake files for
libRinzoCore :
http://www.keepandshare.com/doc/2199086/rinzocore-txt-august-31-2010-12-10-pm-2k?da=y
Rinzo.exe :
http://www.keepandshare.com/doc/2199085/rinzo-txt-august-31-2010-12-10-pm-5k?da=y
It works fine,If I compile "libRinzoCore" as a static-library.
And works fine on Linux.
Any tips?

On windows you need to declare "export" part of dynamic library to make it work.
#ifdef Q_WS_WIN
#ifdef RINZO_EXPORT
#define RINZO_LIB __declspec(dllexport)
#else
#define RINZO_LIB __declspec(dllimport)
#endif
#else
#define RINZO_LIB
#endif
Then you need to put RINZO_LIB in front of your class declaration inside of lib (only classess you want to "export", use in external code)
class RINZO_LIB YourExportedClass
{
...
}
Last part is to add preprocessor macro while compiling your library. As you can see it's RINZO_EXPORT
Remember, don't add this preprocessor macro, when "importing" (using code outside library).
Also all functions require RINZO_LIB macro to be visible outside library:
RINZO_LIB void yourExportedFunction()
{
...
}

Related

Is it possible to make CMake link against a dll directly on Windows?

When target_link_library(foo bar) is called with bar as a target of a SHARED library, CMake will use a static lib libbar.dll.a or bar.lib as an input on Windows. However, MinGW, for example, is capable of linking to a binary file like on Ubuntu. Is it possible to tell cmake to use a dll directly when target_link_library is called?
The obvious workaround is to use generator expressions:
target_link_libraries(foo PRIVATE $<TARGET_FILE:bar>)
Clearly, it has its shortcomings. When you link against a target, you also add its PUBLIC and INTERFACE included directories and linked libraries.
So, in order to fully link in that manner one would have to write something like:
get_target_property(INCLUDE_DIRS bar INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(LINK_LIBS bar INTERFACE_LINK_LIBRARIES)
target_include_directories(foo PRIVATE ${INCLUDE_DIRS})
target_link_libraries(foo PRIVATE ${LINK_LIBS} $<TARGET_FILE:bar>)
So the question is about the possibility to override CMake's default target_link_libraries behavior.
Windows shared object creation works quite differently to on Linux. On Linux, all symbols (functions, classes, etc) are visible to consumers of a shared library by default. On Windows, the opposite is true - nothing is visible by default. This feeds in to shared library creation, because Visual C++ will generate two files per shared library - a .dll and a .lib file. The consumer still links against the lib - not directly against the dll. If you're not explicitly exporting any symbols in your source code, then linking will fail, because no .lib file is generated.
In order to do this, you should basically (on a per-library basis) create a file called "library_api.h" which contains the following:
#ifndef LIBRARY_API_H
#define LIBRARY_API_H
#if defined(WIN32)
#if defined(MYAPI)
#define LIBRARY_API __declspec(dllexport)
#else
#define LIBRARY_API __declspec(dllimport)
#endif
#else
#define LIBRARY_API
#endif
#endif
Then, include that in your header files in which your functions are defined for that library, and prefix them like:
#included "library_api.h"
LIBRARY_API int myfunction();
and in the source file where the definition is, do the same.
Then in CMake, you need to add where the library is made:
add_library(library SHARED source.cpp)
target_compile_definitons(library PUBLIC LIBRARY_API)
Now, the lib file should be generated, and CMake will be able to find it, and hence everything should work.
Note that you can do something similar to the Windows default behaviour on Linux to also hide symbol visibility. You can pass the flag -fvisibility=hidden to GCC, and modify the header slightly using __attribute__ ((visibility ("default"))), and then the behaviour is the same as on Windows. That can be quite useful if your primary development environment is on Linux but you need to build on Windows, because you get the same sort of behaviour and so don't end up with something that works on it but not cross-platform.

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

GCC: Specifying static/dynamic libraries to build against

I have a simple C++ project that is structured as following:
-A base project (ie: contains main() ), and links against everything else
--A few custom libraries that are all built as static libs (ie: .a files)
---One of these static libraries uses features in a shared objective file (ie: a .so file)
So, for example, this is how the project would appear (in a a tree view) at link time, after all the initial compiling has completed:
-myApp (the main application)
--libaudio.a (the audio library I made)
--libnetwork.a (the networking library I made)
--libvideo.a (the video library I made)
--libboost.a (boost library)
Initially, this project build just fine. I just had to make sure I had a simple line in my makefile like this:
LIBS+=audio network video
Recently, I had to change how my audio library works. I now am required to use a third-party library, and all I have is the header file (.h) and the shared object (.so) files. So the new structure at link time looks like so:
-myApp (the main application)
--libaudio.a (the audio library I made)
---libthirdparty.so (contains third-party audio handling functions)
--libnetwork.a (the networking library I made)
--libvideo.a (the video library I made)
--libboost.a (boost library)
This, in effect, means that I have an application with a static library linked in which makes calls to an external shared object. So, I put the header file in the appropriate location so I don't have any build errors when compiling libaudio.a, and put the libthirdparty.so file in a location where the linker searches for all my installed libraries.
At this point, I cannot get the thing to build. It just doesn't see libthirdparty.so file, even though I know it is in a location that the linker searches by default. For some reason, wrapping my libaudio code, as in the example below (borrowed from www.cplusplus.com) fixes the build error:
my_C_CPP_Header.h:
#ifndef MY_C_CPP_HEADER
#define MY_C_CPP_HEADER
/*check if the compiler is of C++*/
#ifdef __cplusplus
extern "C" {
int myOtherCfunc(int arg1, int arg2); /* a C function */
}
#endif
void myCppFunction1(); /* C++ function */
void myCppFunction2(); /* C++ function */
/*check if the compiler is of C++ */
#ifdef __cplusplus
}
#endif
#endif
Now, I have a new problem though. Now that it's building, it no longer statically links in libboost.a, and instead is crashing at startup due to libboost.so not being present. So, somehow this setup breaks how libboost is compiled in if I manage to get it to build at all.
Any suggestions are welcome. Thank you all in advance.
In the end, there was a "LIBPATH=" instead of a "LIBPATH+=" statement overriding the library include paths. Resolved.
Thank you all for your help.

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.

Forcing symbol export with MSVC

I have a application and several plugins in DLL files. The plugins use symbols from the
application via a export library. The application links in several static libraries and this is where most of the symbols come from. This works fine as long as the application uses a symbol. If the symbol is not used there, I get linker errors when compiling the DLL.
How can I force the export of the symbols only used in the plugins?
In order to trigger the export I've tried something like this:
class MyClassExporter
{
MyClass mInstance;
public:
MyClassExporter() {}
};
static MyClassExporter TheMyClassExporter;
in one of the static libs the application is made of to force the export, which didn't work.
In response to Greg (thanks for the answer) and to clarify: The class I want to force the export for is MyClass (which has __declspec(...) defined, depending on wether I want to export or import). MyClassExport was my attempt to force the inclusion of unused (in terms of the application) symbols into the app. I want to 'touch' the symbols so that the linker recognizes them as used and includes them into the application so that it can in turn export these to my plugins. Linking the static libs into the plugins is not an option, since they contain singletons which would be duplicated (app and DLLs each have their own copy of static variables).
The /INCLUDE directive can be used to force the MSVC linker to include a symbol. Alternatively, /OPT:NOREF can be used to disable removal of unused symbols in general.
A common approach is to create a single unused function that references all objects exported for your plugins. Then you only need a single /INCLUDE directive for that function.
You probably want to look at __declspec(export/import)
#ifdef DLL_EXPORTING
#define WHDLL __declspec(dllexport)
#else
#define WHDLL __declspec(dllimport)
#endif
When linking static module into a dll it will only bring in the code that is used. I've never imported stuff from a static lib to simply re export it.
Perhaps you just need to mark it as exportable in the dll when compiling the static lib.
But that reminds me of putting std containers into exported classes and using some trickery in msvc to export the 'instance' of the specialised container. the template code is similar to your static code (in my thinking)
for instance without the template you get warnings the template code is not exported to support the class - this is MSVC specific from my understanding
template class DLL_EXPORTING std::auto_ptr<wxCursor>;
class DLL_EXPORTING imageButton : public wxWindow
{
std::auto_ptr<wxCursor> m_Cursor;
};
What I tried out to solve this was this:
build a static library with function void afunction( int ).
build a dll, linked to static lib, exporting afunction.
build an exe, using the afunction symbol.
How? Since the linker can be told to export functions using the __declspec(dllexport) directive, a dll needs no more than declare a to-be-exported symbol thusly.
The lib has a header "afunction.h" and an accompanying cpp file containing the function body:
// stat/afunction.h
namespace static_lib { void afunction(int); }
// stat/afunction.cpp
#include "afunction.h"
namespace static_lib { void afunction(int){ } }
The dll has an include file "indirect.h", containing the declaration of the function to be exported. The dll has a link-time dependency to the static lib. (Linker options: Input/Additional Dependencies: "static_library.lib")
// dll/indirect.h
namespace static_lib {
__declspec( dllexport ) void afunction(int);
}
The executable has only the indirectly included file:
#include <dll/indirect.h>
int main() { static_lib::afunction(1); }
And guess what? It compiles, links and even runs!
The "Use Library Dependency Inputs" option does the trick in VS2005!
This option can be found under Configuration Properties -> Linker -> General -> Use Library Dependency Inputs. Set to "true" to force linking in ALL symbols & code declared in every LIB specified as input to the project.
You can do the following to get the symbol to export from the DLL: define LIB_EXPORTS in the library project and nothing in either the DLL project or the DLL client project.
#ifdef LIB_EXPORTS
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif
Turns out there is no need #include any headers from the LIB project when compiling the DLL project; just specify the LIB as a linker input. However, if you need to make use of the LIB code from within the DLL, you will need to #define DLLAPI as an empty macro; setting the symbol(s) to either dllexport or dllimport will generate an error or a warning, respectively.
There is some discussion of this problem on MSDN which was pretty useful. As it turns out, /OPT:NOREF is not particularly helpful in this case. /INCLUDE can work but it can be hard to automatically figure out what needs to be /INCLUDEd. There's unfortunately no silver bullet.
http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/2aa2e1b7-6677-4986-99cc-62f463c94ef3