Build non-QT C++ static library using QT
-
Hi,
I've been trying to create a C++ library using QT. Optimally, the library should be deployed as a static library (one .a file) without any dependencies.
The reason to use QT is to make use of the platform independent implementations of QUdpSocket, QThread, QMutex, QEventLoop for iOS, Android, Linux, Mac, Windows.
It should be possible to use the library as a plain C++ library in iOS and Android without having to worry about QT dependencies.
What have I tried until now:
- Compiled QT5.7 as static
- Compile the library as staticlib using qmake from the static build. This creates mylib.a.
- Try to make a separate non-QT application which links to mylib.a, this fails because there are numerous undefined references to QT symbols.
One way to fix this is to link the C++ app to libQt5Core.a, libQt5Network.a as well as mylib.a, however I would prefer not having this additional dependency.
Another way to fix it is to copy libQt5Core.a and libQt5Network.a into the build folder of the library and do the following after building:
ar -x libQt5Core.a ar -x libQt5Network.a ar cg mylib.a *.o
This creates a huge (over 200MB) library and includes a lot more than needed. Once you link an application to it, the filesize reduces to around 50MB, however, the linking to it still requires a lot of dependencies on Linux such as:
pthread z icuio icuuc icutu icule iculx icudata icutest icui18n dl glib-2.0 pcre16 proxy
This makes deployment on other platforms very hard again.
I've been wondering and reading if it was possible to either:
- Use linking to get Core/Network into mylib but only the needed symbols.
- Or stripping the file containing mylib, Core, Network to just the mylib functions and it's dependencies.
From what I've found that's not easily possible, but I keep hoping that somebody must have had (and solved) this problem before.
Thanks in advance for any pointers or ideas.
Julian -
Hi and welcome to devnet,
Are you sure you linked your library to your custom static build of Qt ?
In any case, if you don't want any dependencies, then you have to get the static version of all of them.
-
Thanks @SGaist for your response.
I'll add a minimal example to make this more concrete. I basically created a C++ static library in QtCreator:QT -= gui QT += network TARGET = TestLib TEMPLATE = lib CONFIG += staticlib SOURCES += testlib.cpp HEADERS += testlib.h unix { target.path = /usr/lib INSTALLS += target }
testlib.h:
#ifndef TESTLIB_H #define TESTLIB_H class TestLib { public: TestLib(); }; #endif // TESTLIB_H
testlib.cpp:
#include "testlib.h" #include <QUdpSocket> TestLib::TestLib() { QUdpSocket *socket = new QUdpSocket(); (void)socket; }
Compile output (using the Kit which is qt5.7 statically compiled):
15:29:30: Starting: "/usr/bin/make" g++ -c -pipe -O2 -fPIC -std=gnu++11 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_NETWORK_LIB -DQT_CORE_LIB -I../TestLib -I. -I../qt5/qtbase/include -I../qt5/qtbase/include/QtNetwork -I../qt5/qtbase/include/QtCore -I. -I../qt5/qtbase/mkspecs/linux-g++ -o testlib.o ../TestLib/testlib.cpp rm -f libTestLib.a ar cqs libTestLib.a testlib.o 15:29:31: The process "/usr/bin/make" exited normally.
And the result library:
nm libTestLib.a | c++filt testlib.o: 0000000000000000 V DW.ref.__gxx_personality_v0 U _GLOBAL_OFFSET_TABLE_ U __gxx_personality_v0 U qt_version_tag U _Unwind_Resume U operator delete(void*) U QUdpSocket::QUdpSocket(QObject*) 0000000000000000 T TestLib::TestLib() 0000000000000000 T TestLib::TestLib() U operator new(unsigned long)
You can see that the QT symbols are undefined, and not pulled in. Is this how it's supposed to be? How should this static library be deployed without the developer having to worry about QT dependencies?
-
@julianoes said in Build non-QT C++ static library using QT:
- Try to make a separate non-QT application which links to mylib.a, this fails because there are numerous undefined references to QT symbols.
because the static lib only contains your symbols. The target binary has to be linked against It's dependencies.
This creates a huge (over 200MB) library and includes a lot more than needed. Once you link an application to it, the filesize reduces to around 50MB,
but this what you actually want. It contains all the infos needed. And as you already noticed the size reduces dramatically when linked into the final binary.
however, the linking to it still requires a lot of dependencies on Linux such as:
pthread z icuio icuuc icutu icule iculx icudata icutest icui18n dl glib-2.0 pcre16 proxy
again just because Qt itself is compiled statically it doesn't mean it has no dependencies. You would need to link against those also statically and "combine" them again.
Actually this is all normal "behavior" of static libs. If you want an all-in-solution you would have to go with one big static lib. But i doubt that it will be possible and able to use it successfully with all Qt dependencies included statically.
There are some Qt macros available to disable unneeded features though to reduce the file size though.Also note that some Qt stuff requires an event loop running!
-
Thanks @raven-worx.
@raven-worx said in Build non-QT C++ static library using QT:
again just because Qt itself is compiled statically it doesn't mean it has no dependencies.
Right I understand that but I really don't want that users of my library need to worry about all dependencies like pcre16 or proxy that I doubt are needed for the functions that I use.
@raven-worx said in Build non-QT C++ static library using QT:
There are some Qt macros available to disable unneeded features though to reduce the file size though.
Can you give me a pointer to these? What am I looking for?
@raven-worx said in Build non-QT C++ static library using QT:
Also note that some Qt stuff requires an event loop running!
My library starts a QThread and uses
exec
in there which seems to work for the things I'm trying to do. -
Then I suggested before, you'll have to get all dependencies of Qt also statically linked.
But before looking to do that, what exactly do you need for your application ?
You're looking for the Qt Lite project. More information here. Note that you can already build a feature reduced version of Qt but the Qt Lite project offers an easier alternative to do it.
-
@SGaist said in Build non-QT C++ static library using QT:
Then I suggested before, you'll have to get all dependencies of Qt also statically linked.
I don't understand how I would do that. There is no linking happing if you look at my minimal example.
@SGaist said in Build non-QT C++ static library using QT:
But before looking to do that, what exactly do you need for your application ?
I only really need: QUdpSocket, QThread, QMutex, QEventLoop (and in the future serial support and QTcpSocket).
Thanks for the link to Qt Lite. I have heard of this before and it's definitely exciting. Does it make these static linking issues easier? Or does it just make things leaner with less baggage?
-
It will limit the number of Qt dependencies.
AFAIK, when you link to a static library, you should only get the symbols you are currently using pulled in your application/library. You shouldn't have to pack everything as you do now.
-
@SGaist said in Build non-QT C++ static library using QT:
AFAIK, when you link to a static library, you should only get the symbols you are currently using pulled in your application/library. You shouldn't have to pack everything as you do now.
I think they get pulled in an application but it seems not into a library. There is no linking taking place as far as I can tell. It's just an
ar
call that merges the objects but without core and network.
Presumably, the linking itself happens later when you use the library for an application.If anyone knows an easy way like a script or tool to determine which .o files that I need from Qt5Core.a to resolve all dependencies, that would be great.
-
Then there might be something I'm missing about your current setup.
In any case, take a look at this excellent blog article about that subject. That should give you the clues needed to solve your situation.