Link a MSVC compiled DLL in a MinGW-built project - c++

Given two C++ projects:
a Win32 C++ project compiled as a x86 DLL under Visual Studio 2015
a Qt GUI application using Desktop Qt 5.5.1 MinGW 32 bit Kit.
What I'm trying to do is to link the first one in the second one. A MWE follows.
DLL header file: libxspectra.h
namespace XSpectra
{
#define LIBXSPECTRA_EXPORTS // already defined into Project Properties
#ifdef LIBXSPECTRA_EXPORTS
#define LIBXSPECTRA_API __declspec(dllexport)
#else
#define LIBXSPECTRA_API __declspec(dllimport)
#endif
LIBXSPECTRA_API int fnlibxspectra(void);
LIBXSPECTRA_API int gnara(void) { return 7; };
int foo() { return 1; };
int bar();
}
DLL source file: libxspectra.cpp
#include "libxspectra.h"
namespace XSpectra
{
LIBXSPECTRA_API int fnlibxspectra(void)
{
return 42;
}
int bar()
{
return 6;
}
}
Qt source file: main.cpp
#include "libxspectra.h"
int main(int argc, char *argv[])
{
XSpectra::foo();
XSpectra::bar();
XSpectra::gnara();
XSpectra::fnlibxspectra();
return 0;
}
Qt application build log
error: undefined reference to XSpectra::bar()
error: undefined reference to _imp___ZN8XSpectra13fnlibxspectraEv
While foo() and gnara() links correctly.
A few notes
I know the problem is not strictly Qt-related, but it's a matter of different compilation toolchains, a field where I'm a real novice. I'm actually asking for advices on this way.
If I comment the #define LIBXSPECTRA_EXPORTS, Visual Studio's Intellisense still marks it as defined, dll compiles, but the behaviour of external application's build process changes. The following error arises:
error: function 'int XSpectra::gnara()' definition is marked dllimport

You can only link MSVC compiled C DLLs with MinGW, and only on 32-bit Windows. The MinGW linker can link directly to the DLL (if the functions are properly exported and not only available through an import library) or the usual import library. See here and here for how to generate a MinGW import library from a DLL.
You'll do it just like with MSVC (compile the dll with the functions marked dllexport, and compile the code using the dll with the functions marked dllimport, or use a .def file or something). Remember you need to export C functions, which means they need to be marked extern "C".
I would strongly suggest though, making the code compatible with MinGW, and just compile everything with that. Or use the MSVC version of Qt.

Related

Contradictory unresolved external symbol + unused library altogether with VS2017 and FFMPEG 4

I'm having a small c++ project in Windows with FFmpeg 4.0.2. However, I have weird problem: I'm compiling in x64, having x64 libraries, and having correct link input, but I got the LNK2019 error AND at the same time "unused libraries" in the linker output /VERBOSE:
1>Unused libraries:
1> I:\lib\ffmpeg-4.0.2-win64\lib\\avcodec.lib
1> I:\lib\ffmpeg-4.0.2-win64\lib\\avutil.lib
I checked manually that lib files are x64. I:\lib\ffmpeg-4.0.2-win64\lib\ is in the LIBPATH.
Same symptoms with ICC.
How could this happen ?
To include the headers of ffmpeg in a C++ program you have to take in account that ffmpeg uses the C calling conventions. Otherwise your linker will expect C++ name mangling on the function names. However, since ffmpeg is straight C, you'll have to tell you compiler this.
For example if you include avformat.h in your program do it as follows.
#ifdef __cplusplus
extern "C" {
#endif
#include <avformat.h>
#include <avcodec.h>
#include <avutil.h>
#ifdef __cplusplus
}
#endif
The same goes for the other ffmpeg headers.

How can I check #ifdef in a DLL project, when the #define is in the executable project using the dll?

I have a C++ Visual Studio 2015 project consisting of
1 Windows API executable, 1 windows console executable, and 1 dll shared by both executables.
I have a #define USEWINDOWS in the Windows API main.cpp file
I don't have this defined in the console app
In the DLL, I would like to do an #ifdef USEWINDOWS statement, but the scope of the #define seems to be only valid to the Win32 executable, not in the dll.
How can I extend this #define to the DLL without having it affect the undefined USEWINDOWS in the console app?
Thanks
The DLL is shared by both executables, hence there is only one implementation available and therefore you can't use implementation specific compilation flags.
You'll need a runtime flag, i.e. some API parameter which tells the DLL code that it is OK to use "windows stuff". E.g.
api.h
void someAPI(...., bool useWindows);
dll.c
#include "api.h"
void someAPI(...., bool useWindows) {
...
if (useWindows) {
// do "windows stuff" here
}
...
}
app.c
#include "api.h"
...
someAPI(...., true);
console.c
#include "api.h"
...
someAPI(...., false);
(not tested by compilation, but you should get the drift...)

Templates and name lookup with `stdio.h` functions

I'm trying to build the PCL library in a 32 bit Windows 7 with MinGW. When building the outofcore module I got several error messages about _fseeki64:
error: there are no arguments to '_fseeki64' that depend on a template parameter, so a declaration of '_fseeki64' must be available
In the octree_disk_container.h file, there is a
#ifndef WIN32
#define _fseeki64 fseeko
#endif
I have tested(generating an #error) and WIN32 is defined at the moment of processing the file. _fseeki64 seems to be available for the compiler as this little test program compiles:
#include "stdio.h"
int main(int argc, char** argv) {
FILE* f = fopen("C:/a.txt","r");
if(!f) printf("NOPE");
int seekret = _fseeki64(f,4,SEEK_SET);
(void)seekret;
return 0;
}
If I define _fseeki64 as fseeko64 the errors disappear and the module compiles, but I'm not sure if the behaviour will be the same with fseeko as was intended to be with fseeki.
So, what can I do in order to use _fseeki64 in this context? Maybe declaring a new base class, putting the #define in there and then calling it like Base<T>::_fseeki64? (got the idea from here)
What are your thoughts?
So the problem seems to be that your MinGW system does #define WIN32, yet _fseeki64 is a Microsoft-ism, not a POSIX thing that MinGW knows about. I think you should use the POSIX behavior on MinGW, which means using fseeko.

Exporting constants from a DLL

I'm working with VC9 on Windows.
I have a library (lets call it libfoo) which is made of the following files ("include guards" and "#include" directives omited for clarity's sake):
// foo.hpp
class Foo
{
public:
static const std::string SOME_CONST;
};
And:
// foo.cpp
#include "foo.hpp"
const std::string Foo::SOME_CONST = "hello";
Foo::SOME_CONST is exported using a .def file.
The library compiles fine: a libfoo.lib file and a libfoo.dll file are generated.
I used this library in a sample program, like:
// main.cpp
#include <foo.hpp>
int main()
{
std::cout << Foo::SOME_CONST << std::endl; // std::bad_alloc here
return EXIT_SUCCESS;
}
A std::bad_alloc is thrown whenever I attempt to use Foo::SOME_CONST.
This only happens if I link dynamically to libfoo. Linking statically results in a perfectly working program.
What could possibly be going on here ? Is it legal to export a std::string constant that way ?
Check if dll actually does dynamic initialization, because it might not, standard has no requirements for dynamic libraries. Wrapping globals in static functions can be the solution.
Use __declspec(dllexport) and __declspec(dllimport). Stop worrying about .def files and all of that rubbish- let the compiler do the work.
Are the library and the main application linking to the same version of the standard library and/or CRT and/or MFC, with exactly the same settings? I've seen allocation issues when using different versions of the CRT, and also fought bugs caused by different iterator debugging settings between a library and its including application.

How do you get a minimal SDL program to compile and link in visual studio 2008 express?

I'm trying to use SDL in C++ with Visual Studio 2008 Express. The following program compiles but does not link:
#include <SDL.h>
int main(int argc, char *argv[])
{
return 0;
}
The link error is:
LINK : fatal error LNK1561: entry point must be defined
I get this regardless of how or if I link with SDL.lib and SDLmain.lib. Defining main as main() or SDL_main() gives the same error, with or without extern "C".
Edit: I solved this by not including SDL.h in main.cpp - a refactoring I did independent of the problem. A similar solution would be to #undef main right before defining the function.
I don't have VC++ available at the moment, but I have seen this issue several times.
You need to create a Win32 project as opposed to a console project. A Win32 project expects a WinMain function as a program entry point. SDLmain.lib contains this entry point and the SDL_main.h header file has a macro that remaps your main function to SDL_main. This function is called by the entry point in the SDLmain library.
The main function must have the following signature:
int main(int argc, char *argv[])
It is also required to include SDL.h before the declaration of your main function, and you need to link to both SDL.lib and SDLmain.lib.
It looks like you are doing this. So, my guess is that you have a console project setup. Therefore, the linker is looking for a main function to call, but it is getting remapped to SDL_main by the macro SDL_main.h. So, the linker can't find an entry point and gives up!
To me it helped to add the following lines before main():
#ifdef _WIN32
#undef main
#endif
German Wikipedia also suggests to add these lines instead:
#ifdef _WIN32
#pragma comment(lib, "SDL.lib")
#pragma comment(lib, "SDLmain.lib")
#endif
Though I still had link errors when I tried second solution.
The linker can't find the entry point. Which means your main() function is not recognized as the entry point.
If you have a .def file, remove it.
Also, if you've set up your project to compile with unicode and not as mbcs, you have to use wmain() instead of main().