2017-09-11 9:33 GMT+02:00 Eike Ziller <[email protected]>: > >> On Sep 10, 2017, at 13:09, Elvis Stansvik <[email protected]> wrote: >> >> Right, the two-phase plugin initialization and object pool is quite >> well described in the docs: >> >> https://doc-snapshots.qt.io/qtcreator-extending/plugin-lifecycle.html >> >> I think my question was a little vague, sorry about that. >> >> Consider an example: Some functionality "foo" is to be added to the >> core plugin, and a plugin Bar written to implement that functionality. >> >> Approach 1: >> >> - Add an interface IFoo to the core plugin. >> - Bar implements IFoo and add an instance of its implementation to the >> pool in its initialize(). >> - The core plugin get the object from the pool (in its >> extensionsInitialized()), and make use of it. >> >> Approach 2: >> >> - Add a singleton Foo to the core plugin. >> - Bar carries out its work using direct calls on Foo::instance(). >> >> I was just wondering if the second approach is ever used, or if the >> mechanism set up by the object pool + two-phase initialization is >> always used. If approach 2 is used, I was interested in what the >> deciding factor is between the two approaches. > > Many good things have already been said, I’m late :)
You're very welcome any time Eike :) > > Basically there is also > > Approach 3: > > - Add an interface IFoo to the core plugin > - Add a static method for registering instances of IFoo to core plugin > - Bar implements IFoo and registers an instance of its implementation via the > method above > - The core plugin gets the object(s) that have been registered through the > static method (in its extensionsInitialized or later) Ah yes of course. > > Approach 1 works when there should not be a hard runtime dependency between > the plugins (at compile time the interface header is needed). For making this > work without a link dependency, the interface must use Q_DECLARE_INTERFACE. I > think the only place where it actually used this way is with > CodePaster::Service, to avoid a runtime dependency between CodePaster and > DiffEditor plugins. Historically we used that a lot also when there actually > already was a hard runtime dependency between the plugins, which is > problematic because of the performance issue that André hinted at. Aha, I was actually going to ask if plugin dependencies (as declared in their metadata) always implies a link time dependency as well, because when I looked at qtcreator.pri (the loops at the bottom that add to LIBS), it looked to me like it does. But you're saying that if Q_DECLARE_INTERFACE is used in the depended-upon plugin's interface class, then there will be no link time dependency introduced, despite -l<dep> being always being added to the link line for the depending plugin? > > In Approach 2 we actually moved towards using mostly classes with static > methods, only using the instance() when we actually need an instance (e.g. > for connecting to signals). It works well when a hard runtime dependency is > ok and Bar is the driving force for the work to be done. I would say that we > do this a lot, e.g. ActionManager, EditorManager, …, but I don’t know if you > meant that kind of interaction ;) Yes, my description of 2 was a bit vague, but this was what I meant I think. Having static methods that delegate to the instance() does make the calls more readable, so I like that. > > Approach 3 works well if a hard runtime dependency between the plugins is ok. > We still experiment with ways for avoiding the monotonous work of adding > add/registerXXX, remove/unregisterXXX, methods for managing the list of > implementations. One experiment is Utils::ObjectPool. One could add a public > static instance of that to the core plugin in your example, and then call > Core::foos.addObject(myIFooImpl) from Bar plugin. Ah, I hadn't seen that one. That makes sense. I see that it also defaults to destroying the objects when the pool destructs, which makes sense since looking at the number of IPlugin::addObject calls vs IPlugin::addAutoReleasedObject, it looks like most of the time you want the auto-destruction behavior. > > I’d also prefer having fewer hard runtime dependencies, but it is a struggle… > Qt helps a bit, but it is still not nice. > There is the Q_DECLARE_INTERFACE/Q_INTERFACES combo + object pool, there is > invokeMethod + object pool, and the other thing that we also use is custom > QObject properties (e.g. CodePaster looks for a custom property “plainText” > in the current IEditor, as a fallback for finding pasteable text). Alright, thanks for the insight! Elvis > > Br, Eike > _______________________________________________ Qt-creator mailing list [email protected] http://lists.qt-project.org/mailman/listinfo/qt-creator
