PDA

View Full Version : Extending a plugin in a static library



ultim8
4th March 2009, 16:25
Hello,

I needed to extend the QPSQLDriver class do to slightly more then what the original class does. My new derived class is called PPSQLDriver (do not ask on the naming... I'm horrible at class naming). I defined this class in a static library (it does not need to be static... but it is right now). I then use this new class in several applications.

When building QT, if I specify to *not* build the PSQL driver as a plugin (but as a library instead) everything works great.

However if I build QT to have the PSQL driver built as a plugin I get a link error when linking to my library to my application (the library is built successfully and the application compiles successfully... it fails during linking however).

Here are the linker errors:


...
...
../../lib/libpcccommond.a(ppsqldriver.o): In function `PPSQLDriver::commitTransaction(bool)':
/home/jason/PCC/cvs/ehr/src/pcccommon/src/ppsqldriver.cpp:45: undefined reference to `QPSQLDriver::commitTransaction()'
../../lib/libpcccommond.a(ppsqldriver.o): In function `PPSQLDriver::beginTransaction()':
/home/jason/PCC/cvs/ehr/src/pcccommon/src/ppsqldriver.cpp:32: undefined reference to `QPSQLDriver::beginTransaction()'
../../lib/libpcccommond.a(ppsqldriver.o): In function `PPSQLDriver::close()':
/home/jason/PCC/cvs/ehr/src/pcccommon/src/ppsqldriver.cpp:25: undefined reference to `QPSQLDriver::close()'
../../lib/libpcccommond.a(ppsqldriver.o): In function `PPSQLDriver':
/home/jason/PCC/cvs/ehr/src/pcccommon/src/ppsqldriver.cpp:7: undefined reference to `QPSQLDriver::QPSQLDriver(QObject*)'
/home/jason/PCC/cvs/ehr/src/pcccommon/src/ppsqldriver.cpp:7: undefined reference to `QPSQLDriver::QPSQLDriver(QObject*)'
../../lib/libpcccommond.a(moc_ppsqldriver.o): In function `PPSQLDriver::qt_metacall(QMetaObject::Call, int, void**)':
/home/jason/PCC/cvs/ehr/src/pcccommon/build/moc_ppsqldriver.cpp:68: undefined reference to `QPSQLDriver::qt_metacall(QMetaObject::Call, int, void**)'
../../lib/libpcccommond.a(moc_ppsqldriver.o): In function `PPSQLDriver::qt_metacast(char const*)':
/home/jason/PCC/cvs/ehr/src/pcccommon/build/moc_ppsqldriver.cpp:63: undefined reference to `QPSQLDriver::qt_metacast(char const*)'
../../lib/libpcccommond.a(moc_ppsqldriver.o): In function `~PPSQLDriver':
/home/jason/PCC/cvs/ehr/src/pcccommon/build/../src/ppsqldriver.h:15: undefined reference to `QPSQLDriver::~QPSQLDriver()'
/home/jason/PCC/cvs/ehr/src/pcccommon/build/../src/ppsqldriver.h:15: undefined reference to `QPSQLDriver::~QPSQLDriver()'
/home/jason/PCC/cvs/ehr/src/pcccommon/build/../src/ppsqldriver.h:15: undefined reference to `QPSQLDriver::~QPSQLDriver()'
/home/jason/PCC/cvs/ehr/src/pcccommon/build/../src/ppsqldriver.h:15: undefined reference to `QPSQLDriver::~QPSQLDriver()'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro+0 x0): undefined reference to `QPSQLDriver::staticMetaObject'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x38): undefined reference to `QPSQLDriver::isOpen() const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x40): undefined reference to `QPSQLDriver::commitTransaction()'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x44): undefined reference to `QPSQLDriver::rollbackTransaction()'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x48): undefined reference to `QPSQLDriver::tables(QSql::TableType) const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x4c): undefined reference to `QPSQLDriver::primaryIndex(QString const&) const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x50): undefined reference to `QPSQLDriver::record(QString const&) const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x54): undefined reference to `QPSQLDriver::formatValue(QSqlField const&, bool) const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x58): undefined reference to `QPSQLDriver::escapeIdentifier(QString const&, QSqlDriver::IdentifierType) const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x60): undefined reference to `QPSQLDriver::handle() const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x64): undefined reference to `QPSQLDriver::hasFeature(QSqlDriver::DriverFeature ) const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x6c): undefined reference to `QPSQLDriver::createResult() const'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTV11PPSQLDriver[vtable for PPSQLDriver]+0x70): undefined reference to `QPSQLDriver::open(QString const&, QString const&, QString const&, QString const&, int, QString const&)'
../../lib/libpcccommond.a(moc_ppsqldriver.o):(.data.rel.ro._ ZTI11PPSQLDriver[typeinfo for PPSQLDriver]+0x8): undefined reference to `typeinfo for QPSQLDriver'
collect2: ld returned 1 exit status
...
...


I'm sure the reason this isn't working correctly is because I never actually load the PSQLDriver plugin, but I'm not really sure how to do that.

So:

How do I load the qsqlpsql plugin successfully?
Do I load the plugin in the library the defines the derived class? Or the application that uses my library?
Is there a way to make it "just work" transparently no matter if I build QT with the qsql_psql as a plugin or a library?
Does my scheme (deriving off of a plugin and putting that derived class in a library) even work when using the plugin architecture?


Thanks for any insight.

-Jason

fullmetalcoder
4th March 2009, 19:02
How do I load the qsqlpsql plugin successfully?
Do I load the plugin in the library the defines the derived class? Or the application that uses my library?


It's not "loading" that is required here (which refers to a run-tile action) but linking against the plugin (which is a shared lib but not one of the "regular" Qt libs you are used to linkin against).

When the "base" plugin is built as a "real" plugin (not embedded in QtSql lib but placed in its own shared lib) linking gets WAY trickier. You got to figure out where plugins are located, what is the actual name of the plugin and you have to adjust the LIBS veriable accordingly as follows :



LIBS += -L$$[QT_INSTALL_PLUGINS]/sqldrivers -lqsqlpsql

Please note that I haven't tested this trick but it should work with a vanilla Qt install if qsql_psql plugin is available.

A somewhat "safer", though more restrictive way to do what you want is to compile Qt in static mode and to use static plugins (http://doc.trolltech.com/4.5/plugins-howto.html#static-plugins).




Is there a way to make it "just work" transparently no matter if I build QT with the qsql_psql as a plugin or a library?


You'll need some dark qmake magic to figure whether the sql plugin exists as a plugin but it is doable :



exists( $$[QT_INSTALL_PLUGINS]/sqldrivers/libqsqlpsql* ) {
# plugin found do tricky linking
LIBS += -L$$[QT_INSTALL_PLUGINS]/sqldrivers -lqsqlpsql
} else {
# plugin not found, QT += sql should do
# unless of course the psql plugin is simply not built at all
}






Does my scheme (deriving off of a plugin and putting that derived class in a library) even work when using the plugin architecture?


As long as the class you want to subclass is exported (only matters under Win though, AFAIK) by the shared library, linking will work so your scheme should work.

ultim8
4th March 2009, 19:43
Thanks, this looks promising (and not all that hard). I'll get back to you once I try it out (probably later on tomorrow).

Davor
25th March 2010, 07:30
Thanks, this looks promising (and not all that hard). I'll get back to you once I try it out (probably later on tomorrow).

Hello ultim8,

I am haven a similar issue, and I found your post. So I wanted to ask you how you eventually solved it?

Regards,
Davor

ultim8
25th March 2010, 13:08
Hello ultim8,

I am haven a similar issue, and I found your post. So I wanted to ask you how you eventually solved it?

Regards,
Davor

Davor,

I decided to go with my original method of compiling the QPSQL Driver as a library. I can't remember the road blocks that got in my way, but I could not find a suitable way of transparently making it "just work" no matter if the Driver was a plugin or a library.

Really though, it has not been an issue to compile the QPSQL Driver as a library... the only downside is I have not been able to use the pre-built SDK's... but have had to compile Qt myself.

If you end up coming up with a method that works for you, I would love to hear about it.

Davor
25th March 2010, 15:10
Ultim8,

Good to know that at least the library version works!

I gave up and worked around it: QSqlDatabase::driver() will give you QPSQLDriver. With the handle you can extract PGconn, and PGconn you can use with functions from pglib.dll. This way you can implement extra functionality.


Here some brainstorming to make subclassing work with QPSQLDriver as plugin for those interested:

If you compiled the driver as a plugin, then QPSQLDriver* drv = new QPSQLDriver(); or any subclass of QPSQLDriver will give you “undefined reference” errors. But you can initialize one with the following code:



QPluginLoader l("W:/dev/Qt/4.6.0/plugins/sqldrivers/qsqlpsqld4.dll");
QSqlDriverPlugin *o = qobject_cast<QSqlDriverPlugin*>(l.instance());
QPSQLDriver *d = dynamic_cast<QPSQLDriver*>(o->create("QPSQL"));


Trolls use a factory pattern throughout the driver creation code as far as I see. So QPSQLDriverPlugin::create() is called to produce an instance of QPSQLDriver. Now if one could use the output of QPSQLDriverPlugin::create() as a base class, then one could extend QPSQLDriver, no?

Currently, I don't see a way to do it. But then again, wouldn't something like this be farfetched? Creating a custom plugin, based on QPSQLDriver seems a better approach to me.

Regards,
Davor