[Interest] Problem creating a dll that loads static Qt libraries (in mingw) -> final chapter

185 views
Skip to first unread message

erick oliveira da silva

unread,
Jan 19, 2012, 7:51:03 AM1/19/12
to inte...@qt-project.org
Hi Folks,

Just a last update about my problem:
 
1) With mingw at windows, I can't build a shared library exporting a function, using a Qt library statically built ( -static option in configure ). It is strange: if I export a class, the .dll is built suscessfully, and works. If I write and export just a c++ function that contains/uses Qt classes, I get "undefined reference" when I try to link the shared library.

2) The same .pro file and functions build a shared library susccessfully in linux (gcc), and at Windows with MSVC compiler.

3) It works in mingw only if I use Qt dinamic libraries(-shared option in configure).

I think it is a Qt bug.

I am using Qt 4.7.4 commercial and compiler gcc 4.4.0 from mingw.

To test it, I just created and exported a function that creates a QString object and prints its content in the screen using "printf()".

Best Regards,
Erick





---------- Forwarded message ----------
From: erick oliveira da silva <eosil...@ig.com.br>
Date: 2012/1/17
Subject: Re: [Interest] Problem creating a dll that uses Qt (mingw)
To: inte...@qt-project.org


Thanks Lincoln,

I installed again mingw and Qt and nothing changes.

I think my problem is a bug from Qt 4.7.4.

Best Regards,
Erick


2012/1/17 Lincoln Ramsay <lincoln...@nokia.com>
On 01/17/2012 04:54 AM, ext Till Oliver Knoll wrote:
> I don't know what the *= operator is supposed to do, even though I think
> it exists.

It means "add these values to this variable unless they are already
there". In pseudocode:

for each value (list) {
  if (!variable.contains(value))
    variable.append(value)
}

Or for an example:

FOO = bar # FOO contains (bar)
FOO += bar # FOO contains (bar, bar)
FOO *= foo bar # FOO contains (bar, bar, foo)

> On another note, Qt provides some "cross-platform" macros which expands
> to that __declspec stuff on Windows and to "nothing" on most other
> platforms. Can't remember its name right now, but I thing it's defined
> in the global namespace in qt.h or qt_global.h or something...

What you want is something like this (replace XXX with your library's name):

#include <QtCore/qglobal.h>

#if defined(Q_OS_WIN)
#  if defined(QT_NODLL)
#    undef QT_MAKEDLL
#    undef QT_DLL
#  elif defined(QT_MAKEDLL)
#    if defined(QT_DLL)
#      undef QT_DLL
#    endif
#    if defined(QT_BUILD_XXX_LIB)
#      define Q_XXX_EXPORT Q_DECL_EXPORT
#    else
#      define Q_XXX_EXPORT Q_DECL_IMPORT
#    endif
#  elif defined(QT_DLL)
#    define Q_XXX_EXPORT Q_DECL_IMPORT
#  endif
#endif

#if !defined(Q_XXX_EXPORT)
#  if defined(QT_SHARED)
#    define Q_XXX_EXPORT Q_DECL_EXPORT
#  else
#    define Q_XXX_EXPORT
#  endif
#endif



Then you define QT_BUILD_XXX_LIB when building your library.


--
Lincoln Ramsay - Senior Software Engineer
Qt Development Frameworks, Nokia - http://qt.nokia.com/
_______________________________________________
Interest mailing list
Inte...@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Till Oliver Knoll

unread,
Jan 19, 2012, 8:13:04 AM1/19/12
to inte...@qt-project.org


Am 19.01.2012 um 10:51 schrieb erick oliveira da silva <eosil...@ig.com.br>:

Hi Folks,

Just a last update about my problem:
 
1) With mingw at windows, I can't build a shared library exporting a function, using a Qt library statically built ( -static option in configure ). It is strange: if I export a class, the .dll is built suscessfully, and works. If I write and export just a c++ function that contains/uses Qt classes, I get "undefined reference" when I try to link the shared library.

Depending on your code it *might* be necessary (and hence correct behaviour) to export the /entire/ class!

This might be due to the generated code by moc, which needs also to be exported (and this can only be done by exporting the /entire/ class).

However, this should actually only be "effective" when you actually link /against/ your shared library, not when you try to link your library itself... but I understand your build process already fails at the later point, trying to build the shared lib itself.

You say that it seems to work when using the MS compiler, right? IIRC depending on compiler switches the linker actually might /ignore/ missing symbols and your DLL seems to link fine - unless you actually try to use it (unless you link against another DLL /first/ which provides the missing symbols).

So in the MSVC case: did you actually try to link against your DLL and call the exported method/function from a simple *.exe?

Also as to rule out the very obvious: you DO use two /different/ static Qt versions, one compiled with an MSVC compiler (same version and compiler switches as your DLL, where applicable) and the other compiled with the gcc/MinGW environment (dito for switches) - right? ;)

(Well, you say it works when you export the entire class, so I strongly assume you do.)


Personally I have never used a static Qt lib, so what you observe might indeed be a glitch somewhere (maybe even in the MinGW/gcc).


Cheers, Oliver

erick oliveira da silva

unread,
Jan 19, 2012, 11:18:05 AM1/19/12
to inte...@qt-project.org
Hi Till,


Depending on your code it *might* be necessary (and hence correct behaviour) to export the /entire/ class!

In my case, I unfortunatelly really need to export functions, not classes. And the same program works in Linux with gcc.
 

This might be due to the generated code by moc, which needs also to be exported (and this can only be done by exporting the /entire/ class).

But a very simple dll function, that just creates o QString object with default content "Hello World" and print in screen (with printf() function), doesn't link either.
 
However, this should actually only be "effective" when you actually link /against/ your shared library, not when you try to link your library itself... but I understand your build process already fails at the later point, trying to build the shared lib itself.

You say that it seems to work when using the MS compiler, right? IIRC depending on compiler switches the linker actually might /ignore/ missing symbols and your DLL seems to link fine - unless you actually try to use it (unless you link against another DLL /first/ which provides the missing symbols).

So in the MSVC case: did you actually try to link against your DLL and call the exported method/function from a simple *.exe?
 
Yes, I tested. The shared libray works at windows Vista(.dll), when compiled with visual studio and also works at Linux(*.so), compiled with gcc. I also tested both shared libraries calling functions from them and both work fine.
 

Also as to rule out the very obvious: you DO use two /different/ static Qt versions, one compiled with an MSVC compiler (same version and compiler switches as your DLL, where applicable) and the other compiled with the gcc/MinGW environment (dito for switches) - right? ;)
 
Yes, I have different Qt libraries in different computers(and virtual machines). Here in this laptop I installed qt only using mingw.
 

(Well, you say it works when you export the entire class, so I strongly assume you do.)


Personally I have never used a static Qt lib, so what you observe might indeed be a glitch somewhere (maybe even in the MinGW/gcc).


Thanks for your help,Till!


Best Regards,

Erick



 

Andreas Pakulat

unread,
Jan 19, 2012, 12:41:45 PM1/19/12
to inte...@qt-project.org
On 19.01.12 17:18:05, erick oliveira da silva wrote:
> > Depending on your code it *might* be necessary (and hence correct
> > behaviour) to export the /entire/ class!
>
> In my case, I unfortunatelly really need to export functions, not classes.
> And the same program works in Linux with gcc.

So you're talking about functions in a namespace or global ones I guess?
Since it sounds like you already have a stripped-down example, how about
posting the code and your .pro file (or whatever else you're using for
building)? Maybe we can point you to your error directly.

Andreas

Till Oliver Knoll

unread,
Jan 19, 2012, 3:19:37 PM1/19/12
to inte...@qt-project.org

Am 19.01.2012 um 14:18 schrieb erick oliveira da silva <eosil...@ig.com.br>:

Hi Till,


Depending on your code it *might* be necessary (and hence correct behaviour) to export the /entire/ class!

In my case, I unfortunatelly really need to export functions, not classes. And the same program works in Linux with gcc.

First off, the fact that it works with gcc on Linux doesn't give us any confirmation whether your code/build instructions/compiler switches are correct on Windows! Why? Because that "__declspec(dll_export/import)" stuff is very Windows-specific and has no effect on any other platform with regards to whether a given symbol is exported from a DLL, or in other words: by default (*) on Linux (and any other platform that I know of) ALL symbols are exported from a given .so/.dynlib shared library - only on Windows you have to explicitly tell which symbols to export. 

(Side-note: there is another, I think older mechanism besides the "__declspec" approach: to provide an explicit "export table" (*.def ?). Refer to the MSDN documentation. But I prefer the __declspec approach, as it is "closer tied with the actual code", IMHO easier to maintain.)

So the fact that something works on any other platform than Windows with regards to linking doesn't assure you that you are doing it right on Windows ;)


So we can limit the discussion on the MS compiler/build environment vs gcc on MinGW (and since that's also building DLLs the same "Windows DLL rules" apply here).


That said, I understand you have something like:

// FooLib.h

// The macro being defined properly
FOOLIB_EXPORT void myFunction();

// FooLib.cpp

#include <QtCore/QString>
#include "FooLib.h"

void myFunction() {
  QString msg = "Hello";
  qDebug(qPrintable(msg));
}

and you link that with a static build of Qt 4.7.4 (did you compile it yourself? Or is that provided from Nokia/
"Digia"?), which works with MSVC, but fails on gcc/MinGW. Is that about right?

btw: do you use the same *.pro/qmake/nmake build approach with MSVC, or do you setup your project "from scratch" within Visual Studio (with the help of the "Qt AddOn" - or whatever it is called these days)?


So as Andreas already pointed out at this point it might be helpful to see the actual (example) code and *.pro files which reproduces the problem. 


Cheers, Oliver

(*) "By default" meaning "the compiler switches you get with the proper QMAKESPEC and qmake approach" - IIRC you can also have gcc (or was it the native compiler on AIX?) explicitly export given symbols and have everythink else "hidden" (not exported - reducing the file size by a couple of Bytes and possibly speeds up dynamic linking by a couple of %-fractions). But this again would become compiler/platform-specific, just as this __declspec stuff on Windows. So for the sake of simplicity of this discussion let's just say "everything is exported on any platform other than Windows".

Thiago Macieira

unread,
Jan 19, 2012, 7:20:45 PM1/19/12
to inte...@qt-project.org
On Thursday, 19 de January de 2012 18.19.37, Till Oliver Knoll wrote:
> First off, the fact that it works with gcc on Linux doesn't give us any
> confirmation whether your code/build instructions/compiler switches are
> correct on Windows! Why? Because that "__declspec(dll_export/import)" stuff
> is very Windows-specific and has no effect on any other platform with
> regards to whether a given symbol is exported from a DLL, or in other
> words: by default (*) on Linux (and any other platform that I know of) ALL
> symbols are exported from a given .so/.dynlib shared library - only on
> Windows you have to explicitly tell which symbols to export.

Count yourself lucky. There is one more such platform, which has taken the
worst of what Windows had to offer, namely this:

> (Side-note: there is another, I think older mechanism besides the
> "__declspec" approach: to provide an explicit "export table" (*.def ?).
> Refer to the MSDN documentation. But I prefer the __declspec approach, as
> it is "closer tied with the actual code", IMHO easier to maintain.)

That platform is called Symbian.

See
https://qt.gitorious.org/qt/qt/blobs/master/src/s60installs/bwins/QtCoreu.def
and
https://qt.gitorious.org/qt/qt/blobs/master/src/s60installs/eabi/QtCoreu.def
(and others).

On the other hand, there are certain advantages of doing it the Windows way.
I've just posted two blogs asking for some of those advantages to be brought
over to Linux.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

signature.asc

erick oliveira da silva

unread,
Jan 20, 2012, 4:14:09 AM1/20/12
to inte...@qt-project.org
Hi Till,

Thanks for your reply. I learned a lot with it.

I compiled qt library by myself. I download the sources and compiled with gcc-mingw, the same compiler I am trying to build my simple qt shared library now.

The function that I would like to export:

--- Header : dllfct.h ---------------------------------

#ifndef DLLFCT_H
#define DLLFCT_H

#include <QtCore/qglobal.h>
#include <QtGlobal>

#if defined(MY_DLL)
#define EXPORT  Q_DECL_EXPORT
#else
#define EXPORT  Q_DECL_IMPORT
#endif

// function to be imported/exported
EXPORT void tstfunc (void);

#endif //DLLFCT_H

-----------------------------------------------------
 
-- Source File : dllfct.cpp ---------------

#include <QString>
#include <QDebug>
#include "dllfct.h"

void tstfunc (void)

{
QString msg = "Hello";
  qDebug(qPrintable(msg));   
}

---------------------------------------------------------

-- Pro file:

QT -= gui
TEMPLATE = lib
CONFIG += qt dll release 

SOURCES = dllfct.cpp

MAKEFILE = Make_QDECL

DEFINES += MY_DLL

INCLUDEPATH += ./dllQDECL
DEPENDPATH += ./dllQDECL

HEADERS = dllfct.h

--------------------------------

and here my output:

D:\dllmingw\qt>mingw32-make -f Make_QDECL.Release
g++ -c -O2 -frtti -fno-exceptions -Wall -DUNICODE -DQT_LARGEFILE_SUPPORT -DMY_DL
L -DQT_DLL -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_S
SE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -I"..\..\qt_static_4.7.4\
include\QtCore" -I"..\..\qt_static_4.7.4\include" -I"dllQDECL" -I"..\..\qt_stati
c_4.7.4\include\ActiveQt" -I"release" -I"..\..\qt_static_4.7.4\mkspecs\win32-g++
" -o release\dllfct.o dllQDECL\dllfct.cpp
g++ -Wl,-s -shared -Wl,--out-implib,release\libqtdll.a -o release\qtdll.dll rele
ase/dllfct.o  -L"d:\qt_static_4.7.4\lib" -lQtCore -lole32 -luuid -lws2_32 -ladva
pi32 -lshell32 -luser32 -lkernel32
Creating library file: release\libqtdll.a
release/dllfct.o:dllfct.cpp:(.text+0x18): undefined reference to `_imp___ZN7QStr
ing16fromAscii_helperEPKci'
release/dllfct.o:dllfct.cpp:(.text+0x2e): undefined reference to `_imp___ZNK7QSt
ring11toLocal8BitEv'
release/dllfct.o:dllfct.cpp:(.text+0x3e): undefined reference to `_imp___Z6qDebu
gPKcz'
release/dllfct.o:dllfct.cpp:(.text+0x61): undefined reference to `_imp___ZN7QStr
ing4freeEPNS_4DataE'
release/dllfct.o:dllfct.cpp:(.text+0x71): undefined reference to `_imp___Z5qFree
Pv'
collect2: ld returned 1 exit status
mingw32-make: *** [release\qtdll.dll] Error 1

------------------------------------------------------------------------------

Just to remind, if I change the pro file to build a static library(*.a) and remove , I can link suscessfully a static library and also build suscessfully a executable file that calls this function. My problem is really just with dlls.

Using the directive __declspec( dllexport ) instead of Q_DECL_EXPORT didn't change my output.

Thank you very much all of you for the replies.

Best Regards,
Erick


2012/1/19 Till Oliver Knoll <till.oli...@gmail.com>

Till Oliver Knoll

unread,
Jan 20, 2012, 4:23:43 AM1/20/12
to inte...@qt-project.org

Am 20.01.2012 um 07:14 schrieb erick oliveira da silva <eosil...@ig.com.br>:

> Hi Till,
>
> ...


> CONFIG += qt dll release

Oops, not sure, but I think that's the bugger: can't remember right now the exact meaning of 'dll', but I think this refers to how *Qt* was built (and not how your code is to be build - that is controlled via the TEMPLATE variable) - I think this let's you choose which Qt version to link against, the static or the dynamic one (which off course must both be available, in the proper PATH etc.).

So refer to the qmake docs again and try without 'dll' (followed by a 'make distclean' etc.).

Cheers, Oliver

Andreas Pakulat

unread,
Jan 20, 2012, 5:11:54 AM1/20/12
to inte...@qt-project.org
On 20.01.12 07:23:43, Till Oliver Knoll wrote:
>
>
> Am 20.01.2012 um 07:14 schrieb erick oliveira da silva <eosil...@ig.com.br>:
>
> > Hi Till,
> >
> > ...
> > CONFIG += qt dll release
>
> Oops, not sure, but I think that's the bugger: can't remember right now the exact meaning of 'dll', but I think this refers to how *Qt* was built (and not how your code is to be build - that is controlled via the TEMPLATE variable) - I think this let's you choose which Qt version to link against, the static or the dynamic one (which off course must both be available, in the proper PATH etc.).
>
> So refer to the qmake docs again and try without 'dll' (followed by a 'make distclean' etc.).

Maybe you should do so before posting comments that you're not quite
sure of ;) The template only tells you wether to build an app or a
library (or a subdir), the CONFIG += dll or CONFIG += static tells qmake
wether you want a shared lib or a dll.

That being said, it might still be the cause of the problems, since not
all linkers might support linking a static library into a shared one
IIRC (Thiago please correct me if I'm talking nonsense here).
And even those that do will only take the symbols that the shared
library uses, so if you then link an app against the shared lib and
expect it to automatically get all Qt symbols from the shared lib that
won't work either.

Andreas

Andreas Pakulat

unread,
Jan 20, 2012, 5:16:14 AM1/20/12
to inte...@qt-project.org

IIRC the correct linker-command for linking a static library needs to be
the absolute path of the .a file. -L/-l are only used by gcc for shared
libs. So it seems that qmake generates the wrong Makefile contents, you
could verify that by copying the line, removing the -L and -lQtCore
arguments and replace that with something like
d:\qt_static_4.7.4\lib\libQtCore.a (provided that this file actually
exists). If that works, you'd have to dive into qmake code or file a
report with the bugtracker to find out (or have someone else find out)
why qmake generates these incorrect linker arguments.

Andreas

Thiago Macieira

unread,
Jan 20, 2012, 7:08:25 AM1/20/12
to inte...@qt-project.org
On Friday, 20 de January de 2012 11.11.54, Andreas Pakulat wrote:
> That being said, it might still be the cause of the problems, since not
> all linkers might support linking a static library into a shared one
> IIRC (Thiago please correct me if I'm talking nonsense here).

We're talking about Windows here, why would I know? :-)

signature.asc

erick oliveira da silva

unread,
Jan 20, 2012, 5:04:03 PM1/20/12
to Andreas Pakulat, inte...@qt-project.org
Hi Andreas,

I changed the makefile but it didn't work.

Thanks anyway for all of you. I learnt a lot from you guys.

Best Regards,
Erick

2012/1/20 Andreas Pakulat <ap...@gmx.de>

Till Oliver Knoll

unread,
Jan 21, 2012, 9:31:10 AM1/21/12
to inte...@qt-project.org


Am Freitag, 20. Januar 2012 schrieb Andreas Pakulat <ap...@gmx.de>:
> On 20.01.12 07:23:43, Till Oliver Knoll wrote:
>>
>>
>> Am 20.01.2012 um 07:14 schrieb erick oliveira da silva <eosil...@ig.com.br>:
>>
>> > Hi Till,
>> >
>> > ...
>> > CONFIG += qt dll release
>>
>> Oops, not sure, but I think that's the bugger: can't remember right now the exact meaning of 'dll',
> Maybe you should do so before posting comments that you're not quite
> sure of ;)

Eeeh! Yes, sorry, it just occured to my mind an hour later or so that what I wrote is bogus info! So please ignore that and "delete it from the Internet" ;)

Yes, off course 'dll' refers to how /your/ code is to be linked (another option being 'plugin'), that is, a DLL (shared library) is to be produced.

(But I have a good excuse: I'm on holidays in lovely Brasil, and am typing this on some tiny mobile screen where it is absolutely no fun to do docu research - you know, the heat, Caipirinha and such ;))



> That being said, it might still be the cause of the problems, since not
> all linkers might support linking a static library into a shared one
> ...

> And even those that do will only take the symbols that the shared
> library uses, so if you then link an app against the shared lib and
> expect it to automatically get all Qt symbols from the shared lib that
> won't work either.

I think that's the answer! Off course, it must be: When you link against a static library only those symbols which are actually used are linked into your binary. And depending on how good the linker is able to optimise (or how the compiler creates dependencies maybe as well) you get a few symbols more or less linked into your binary - but for sure not the entire library!

That would explain why it might work with one linker A, whereas it might not work with another linker B.


On the other hand: the example code did not expose (export) any Qt API, so as long as such a dynamic library would use Qt only /internally/ (with no references to any Qt classes in its headers), then in theory that should work to link such a dynamic lib with a static Qt one.

But Andreas might be right: some compilers/linkers might simply not support that (correctly).


Cheers, Oliver

erick oliveira da silva

unread,
Jan 21, 2012, 5:01:40 PM1/21/12
to inte...@qt-project.org
Thanks, Till.

Muito Obrigado pela resposta, Till.

P.S.: rolou um pouco de inveja de minha parte agora. Só poderei visitar o Brasil no natal. :-(

Best Regards,
Erick

2012/1/21 Till Oliver Knoll <till.oli...@gmail.com>
Reply all
Reply to author
Forward
0 new messages