I'm porting a shared library from CMake to QMake (for better integration with the rest of our codebase), and am having trouble in Windows with having qmake generate both the .lib and .dll files. I have ported this over to Linux and MacOS (easier with Unix shared library formats), but am having trouble with Windows.
Please note that I am not using the Mingw compiler, but the MSVC 2015 compiler. Unfortunately, I can't use the Mingw compiler for various reasons.
Relevant code in my .pro file:
Qt -= core gui #not using the qt library
CONFIG += c++14 warn_on
TEMPLATE = lib
TARGET = MyLibrary
With CMake, I was able to set certain .h files as PUBLIC_HEADER
files, and after running make install
, it generated the proper .lib and .dll files.
But with qmake, it only generated a very tiny .dll file (<15kb). I tried adding CONFIG += static
but that created a .lib file with all the symbols there, not the shared library files I am looking for.
Edit: After looking more into it, a better question could be: Is there a qmake equivalent (or workaround) of CMake's PUBLIC_HEADER property?
In a nutshell: @Matt is right, you need to take active action in your source code to export classes, functions and other symbols. This is mandatory in Windows, but it is also a recommended practice in Unix. When the MSVC++ compiler sees exported symbols, it automatically creates both the .DLL and the .LIB import library.
To do this in a cross-platform way with qmake, a nice guide is following the pattern of the Qt Creator wizard: Welcome -> New Project -> Library -> C++ library. Project location..., name: 'testlib' (for instance). Next, next, choose your kit, next and finish. The files created by the wizard in the project directory are:
testlib.cpp
testlib_global.h
testlib.h
testlib.pro
testlib.pro.user
The interesting bits are in testlib.pro:
TEMPLATE = lib
DEFINES += TESTLIB_LIBRARY
And the header "testlib_global.h"
#ifndef TESTLIB_GLOBAL_H
#define TESTLIB_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(TESTLIB_LIBRARY)
# define TESTLIB_EXPORT Q_DECL_EXPORT
#else
# define TESTLIB_EXPORT Q_DECL_IMPORT
#endif
#endif // TESTLIB_GLOBAL_H
This header should be included in other headers, that would be using the TESTLIB_EXPORT macro like this (testlib.h):
#ifndef TESTLIB_H
#define TESTLIB_H
#include "testlib_global.h"
class TESTLIB_EXPORT Testlib
{
public:
Testlib();
// ...
};
The key is to define TESTLIB_LIBRARY in the project .pro that builds the library, so the TESTLIB_EXPORT macro is defined as Q_DECL_EXPORT, which in Windows is defined as __declspec(dllexport)
, and avoid defining TESTLIB_LIBRARY in the projects using the library. More about this here.
Now, the second part of your question. In CMake documentation, it says:
PUBLIC_HEADER
Specify public header files in a FRAMEWORK shared library target.
Shared library targets marked with the FRAMEWORK property generate frameworks on macOS, iOS and normal shared libraries on other platforms. This property may be set to a list of header files to be placed in the Headers directory inside the framework folder. On non-Apple platforms these headers may be installed using the PUBLIC_HEADER option to the install(TARGETS) command.
So the PUBLIC_HEADER attribute is only about installing the public headers. To do so in qmake, you need to use INSTALLS in testlib.pro, for instance:
unix {
target.path = /usr/local/lib
headers.path = /usr/local/include
}
!isEmpty(target.path) {
INSTALLS += target
}
headers.files = $$HEADERS
!isEmpty(headers.path) {
INSTALLS += headers
}