> On Sep 11, 2017, at 09:54, Elvis Stansvik <[email protected]> wrote:
> 
> 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?

To avoid an actual link time dependency, the dependency has to also be declared 
as “optional”, i.e.
QTC_PLUGIN_RECOMMENDS instead of  QTC_PLUGIN_DEPENDS

Br, Eike

> 
>> 
>> 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

-- 
Eike Ziller
Principal Software Engineer

The Qt Company GmbH
Rudower Chaussee 13
D-12489 Berlin
[email protected]
http://qt.io
Geschäftsführer: Mika Pälsi,
Juha Varelius, Mika Harjuaho
Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, HRB 
144331 B

_______________________________________________
Qt-creator mailing list
[email protected]
http://lists.qt-project.org/mailman/listinfo/qt-creator

Reply via email to