Seite 1 von 1

Dynamisch geladene Objekte

Verfasst: 4. Januar 2011 18:36
von dazedly
Hi... ich kaue mir langsam die Zähne aus... Gibt es unter c++ eine Möglichkeit, Objekte dynamisch zu laden? So wie ich es jetzt hin bekommen habe, funktioniert es, aber gibt es auch einen sauberen Weg?

Vater-Klasse Pure Virtual (hart im Code)

Code: Alles auswählen


#ifndef FUNCTIONHANDLER_H
#define FUNCTIONHANDLER_H

class FunctionHandler: public QObject
{
		Q_OBJECT

	public:
		virtual RonsPacket* execute ( p ) = 0;
		virtual ~FunctionHandler() {}

	signals:
		void appointmentChanged ( ConnectionHandler*, QByteArray );
};

typedef FunctionHandler* create_t();
typedef void destroy_t(FunctionHandler*);

#endif // FUNCTIONHANDLER_H
Kindklasse (externe lib)

Code: Alles auswählen


class login : public FunctionHandler
{

	public:
		RonsPacket* execute(ConnectionHandler*,RonsPacket* );
		virtual ~login();
};

RonsPacket* login::execute(p)
{
	
	//viel code

	return p;
}
extern "C"
{
	login* create() {
		return new login;
	}

	void destroy ( login* p ) {
		delete p;  
	}
}
PluginLoader:

Code: Alles auswählen


QDir directory;
	qDebug() << directory.currentPath();
	 directory.setCurrent("Functions");
	QStringList filters;
	filters << "lib*.so";
	directory.setNameFilters(filters);
	qDebug() << directory.entryList();
	
	
	foreach(QString str, directory.entryList())
	{
		QString pluginPath = str;
		QString pluginName = str.replace("lib", "").replace(".so", "");
		qDebug() << "Load Plugin: "<< pluginName;

		void* handle = dlopen ( directory.absoluteFilePath(pluginPath).toAscii() , RTLD_NOW );

		if ( !handle ) {
			qDebug() << "Cannot load library: " << dlerror() << '\n';
		} else {

			dlerror();
			void * sym = dlsym ( handle, "create" );

			create_t *plugin = (create_t *) sym;
			FunctionHandler* poly = plugin();
			functions.insert(pluginName,poly);
		}
	}
Das funktioniert so weit, aber das gecaste ist ja nicht wirklich sauber und das mischen von c und c++ auch nicht. Außerdem kann ich durch den einen cast nicht mehr mit pedantic compilen...

Re: Dynamisch geladene Objekte

Verfasst: 4. Januar 2011 19:30
von solarix
dazedly hat geschrieben:Hi... ich kaue mir langsam die Zähne aus... Gibt es unter c++ eine Möglichkeit, Objekte dynamisch zu laden?
...
aber das gecaste ist ja nicht wirklich sauber und das mischen von c und c++ auch nicht.
Anstelle von "dlopen" sollte man bei Qt eher QLibrary (http://doc.qt.nokia.com/latest/qlibrary.html) verwenden, aber das ist (wie du selbst bemerkt hast) nur für C.

Was du suchst ist im Grunde ein "Plugin":
http://doc.trolltech.com/latest/qplugin ... ml#details

hth..

Verfasst: 4. Januar 2011 19:36
von dazedly
Qplugin ist ja auch nicht wirklich was, da ich in den plugins kein QObject verwenden kann :(

Verfasst: 4. Januar 2011 19:46
von solarix
hä? Was liefert den QPluginLoader::instance()...?

http://doc.trolltech.com/latest/qplugin ... l#instance

Verfasst: 4. Januar 2011 20:03
von dazedly
Ich sehe jetzt nicht, wie mir das weiter helfen soll. http://doc.trolltech.com/latest/plugins-howto.html Auf dieser Seite sieht das alles danach aus, dass damit nur für Qt plugins geschrieben werden kann (Painter und Styles etc) Ich möchte aber selbst damit arbeiten können. Oder verstehe ich da etwas falsch?

Verfasst: 4. Januar 2011 20:11
von solarix
Das steht doch auf deinem Link gleich als erstes:
Qt provides two APIs for creating plugins:

* A higher-level API for writing extensions to Qt itself: custom database drivers, image formats, text codecs, custom styles, etc.
* A lower-level API for extending Qt applications.

For example, if you want to write a custom QStyle subclass and have Qt applications load it dynamically, you would use the higher-level API.
Du brauchst also die "lower-level API", den QPluginLoader.

hth..

Verfasst: 10. Januar 2011 09:45
von RHBaum
Du kannst es auch selber machen, alles ... dann lernst auch mehr dabei.
Das QT Plugin System, also die lower level API z.b. find ich ned so prall.
Hat fuer meinen geschmack zu wenig und zu restriktive verwaltung.
Den weg statt ueber den dynamic cast ueber den object_cast find ich auch ned viel eleganter.
Aber ist viel Geschmackssache, wenn man sowieso ueberall scho QT drinne hat.

1. Frage, warum tust du dir das mit lib*.so an ? Das brauchst nur wenn du ueber den linker scho was zulinken willst und deine IDE / Makefile ned verbiegen willst :-) Wenn dein Plugin(deine Datei) nen richtigen shared Object Header hat und gueltiger Maschinencode ist, wird es loadLibrary/dlopen auch laden, wenn der Dateiname "xyz.txt" lautet :-)
Nenn deine Plugins lieber intuitiver :-) .so als Endung kannst ja lassen.

2. Um C und mindestens 1 Cast, meist auch mehrere, wirst bei Plugins ned herumkommen. Machs nur richtig. C++ -> meide C-Casts ! reinterpret_cast ist mehr c++ like.

Ciao ...

Verfasst: 10. Januar 2011 10:56
von dazedly
Zu Frage 1: Wenn du mir sagen kannst, wie ich cmake eintrichtern soll, dass er ein anderes Schema zur Benennung nutzen soll, dann nehme ich auch gerne andere Namen :)

Code: Alles auswählen

FILE(GLOB plugins . "*.cpp")
foreach(plugin ${plugins})
	string(REGEX REPLACE ".cpp" "" pluginname ${plugin})
	string(REGEX REPLACE ".*/" "" pluginname ${pluginname})
	qt4_automoc(${plugin})
	qt4_wrap_cpp(${pluginname}moc_SRCS ${pluginname}.h )
	add_library (${pluginname} MODULE  ${plugin} ${${pluginname}moc_SRCS})
endforeach(plugin)
Zu 2.: Ich habe jetzt alle meine Plugins so angepasst, dass sie über den QPluginLoader geladen werden können. Es funktioniert ganz gut und ich lass das jetzt einfach mal so. Ich schreib jetzt noch ein kleines //FIXME in den Code und es wird später geändert, wenn Zeit da sein sollte.

Code: Alles auswählen

qDebug() << "==================  Loading Plugins ==================";
	QDir directory;
	directory.setCurrent("Plugins");
	qDebug() << directory.currentPath();
	QStringList filters;
	filters << "lib*.so";
	directory.setNameFilters(filters);
	
	
	foreach(QString str, directory.entryList())
	{
		QString pluginPath = str;		

		QPluginLoader loader(str);
		QObject *plugin = loader.instance();
		if(!loader.isLoaded())
		{
			qDebug() << "Error: " << loader.errorString();
		} else {
			FunctionHandler *fh = qobject_cast<FunctionHandler *>(plugin);
			functions.insert(fh->pluginName(),fh);
			qDebug() << "Load Plugin: "<< fh->pluginName();
		}
	}
	qDebug() << "==================  Plugins Loaded ==================";

Verfasst: 11. Januar 2011 09:02
von dazedly
So geht das mit dem prefix

Code: Alles auswählen

add_library (${pluginname} MODULE  ${plugin} ${${pluginname}moc_SRCS})
	SET_TARGET_PROPERTIES(${pluginname} PROPERTIES PREFIX "mod")