[Geany-Devel] New plugin loader mechanisms

Thomas Martitz kugel at xxxxx
Thu Mar 19 21:40:07 UTC 2015

Am 19.03.2015 um 01:19 schrieb Matthew Brush:
> On 15-03-18 03:55 PM, Thomas Martitz wrote:
>> Am 18.03.2015 um 23:21 schrieb Matthew Brush:
>>> On 15-03-18 03:05 PM, Thomas Martitz wrote:
>>>> Am 18.03.2015 um 22:15 schrieb Matthew Brush:
>>>>>>> [...]
>>>>>>> void (*init) (GeanyPlugin *plugin, gpointer pdata);
>>>>>> Please make this gboolean. A plugin may have the correct API and 
>>>>>> ABI,
>>>>>> but be unable to startup / initialize for some reason. For example,
>>>>>> Scope requires scope.glade in the plugin data directory).
>>>> Thinking about it, if the plugin can't run because it's missing 
>>>> resource
>>>> files required for its operation, then I think it should be treaded 
>>>> like
>>>> incompatible plugins. This has the benefit that they will be attempted
>>>> to be loaded on the next startup if the user had previously 
>>>> selected it.
>>> For resource files like say a GtkBuilder UI file, I'd agree, but there
>>> may be some other cases, for example if a plugin dynamically loaded
>>> some particular library (or variant of a library) based on user
>>> configuration, it'd be useful to report to the user that the library
>>> is wrong, or no longer available, or whatever.
>> Based on user configuration implies that it's a decision that is made
>> after the plugin's init(). If it allows the user to configure it without
>> this dependency then the plugin is considered operational, and init()
>> should not fail. Remember that a init() == FALSE would imply that the
>> plugin cannot be activated, and therefore not configured (i.e. you
>> cannot configure back so that it doesn't need the missing dependency).
>> Such custom requirements & errors are better placed in the plugin code
>> itself.
>>>> I'm thinking if the plugin loaded successfully, then it should be
>>>> operational too. Meaning that init() should not fail, but simply
>>>> activate the plugin. As outlined above, my proposal already covers the
>>>> case "compatible but not operational due to missing runtime
>>>> dependencies" you described.
>>> For cases like GeanyPy which loads arbitrary Python scripts (which are
>>> even fully executed on import), and in a language where Exceptions are
>>> common (especially during development), it would probably be useful to
>>> signal that the plugin script couldn't be loaded and maybe even be
>>> able to provide a formatted traceback of the Python exception or such.
>> In my roadmap geanypy does not load scripts in its init(), but through a
>> separate API (so that the scripts integrate into the main plugin
>> manager). Anyway, geanypy init() isn't the right place because geanypy
>> can load multiple scripts, and which scripts can change afterwards after
>> init has run. And finally, all those scripts do not change the fact that
>> geanypy itself is operational, and this is what we're talking about.
> I think I misunderstood the purpose of your `init()` function. I 
> thought it was a hook to allow the plugin manager/geany to be able to 
> initialize multiple plugins from the same .dll/module (ex. 
> sub-plugins, etc). If that's not the case, isn't the `init()` pointer 
> in the struct basically redundant as plugins could do their 
> initialization in the roughly equivalent `geany_load_module()` that is 
> also called once per .dll?

I haven't changed the semantics of init function (it is the same 
plugin_init() that already exists), and there is no support for pluxies 
or sub-plugins yet. My new loader doesn't do that, it only changes how 
the plugin is registered and the parameters plugins receive in the hooks.

The difference between the geany_load_module() and init() is that the 
former is always called, even if the plugin is not enabled by the user. 
And it can fail (e.g. if the ABI check fails) which prints warnings and 
hides it from the PM GUI.

geany_load_module() doesn't have an equivalent, therefore plugins with 
runtime hard-dependencies could previously only fail in init somehow (as 
a hack). Now geany_load_module() can do that. I think init() is 
generally not the right place for that. When it is called then the 
plugin was enabled by the user, i.e. it is expected to function somehow 
from here on. Proper plugins will allocate resources and hook into the 
GUI in this function that are not needed when the plugin is disabled. At 
last, I do not want to change the semantics of the existing hooks if 
possible because that makes merging my patch harder.

> For that matter, why not just leave the hooks all as loose functions 
> (as opposed to set into a structure), and just fix the prototypes to 
> pass around GeanyPlugin* and/or user_data, or whatever improvements? 
> AFAIK there's no issue with symbols/collisions if Geany just uses 
> RTLD_LOCAL when dlopen-ing the plugin module.

Well it was determined that we want new functions instead of adding or 
changing the parameters of the existing hooks. And I think it is 
desirable to minimize the amount of globals in the plugin while at it. 
Besides, the new geany_load_module() provides some true benefits, such 
as ABI/API verification in the core instead of in the plugin.

Best regards

More information about the Devel mailing list