[Geany-devel] Plugin Version control (explained?)

Lex Trotman elextr at xxxxx
Thu Aug 18 02:01:09 UTC 2011

On 18 August 2011 04:34, Matthew Brush <mbrush at codebrainz.ca> wrote:
> On 08/16/2011 10:37 PM, Lex Trotman wrote:
>> Hi All,
>> Given that the previous thread had moved way off topic, I started this
>> one.
>> After thinking about it a bit, considering Matthew's, Colomban's and
>> Thomas's comments and looking at other systems I came to the
>> understanding documented below.  Frank probably already knew all this,
>> but I have saved him writing lots of English.  If its right and you
>> think its worth using in the newsletter or anywhere else feel free to
>> copy it.
> Great information, this should most certainly go into the Wiki (as well as
> any other useful places).

Oh yeah the wiki, I forgot about that :-)

@Enrico, When will it be declared online, ie prominently pointed to
from the website?

> Actually, I think usually the checks end up being done by GModule/dlopen
> since they try to load the plugin and bail-out when they get undefined
> symbol errors.  Only after that is when the PLUGIN_VERSION_CHECK macro would
> have a chance to do it's checks.  I could be completely wrong on this, but I
> think it's what I've observed.

You are correct that the sentence above should say "done at runtime by"...

And my next sentence is only partly correct, you may get compile time
errors, unfortunately it is not guaranteed. See below for why.

>> Plugins that wish to use newer features but still support older
>> versions can only make the decision at compile time because the API
>> number of the Geany that the plugin is being loaded into isn't
>> available at runtime.  Making the API number available at runtime may
>> be a potential enhancement of the interface and allow plugins to
>> support a wider range of versions.
> Wouldn't run-time be too late anyway, since the undefined functions didn't
> have a chance to get pre-processed out according the version?
> Like:
>        void some_func(void)
>        {
>                if (geany_check_api_version(189))
>                        undefined_function_here(); /* dlopen error */
>        }

You may be using functions that are not in the API?  I see some more
detail is needed, the way I understand it is meant to work is:

geanyplugin.h includes geanyfunctions.h which defines a macro for each
function in the interface, thus hiding the actual function.  Those
macros map the function name to a call via a pointer member of the
geanyfunctions structure.  Since structure members are not checked by
dlopen this means it should not check for any Geany functions when
opened.  If it is telling you that there are undefined functions then
you are using functions directly not via the geanyfunctions structure.
 It may also be possible that there are functions documented as being
in the API that are not in geanyfunctions, but thats a bug (either
undocument or add to geanyfunctions).  The pointers in the geany
functions structure have full prototypes so the compiler can check

To get the structure declarations, geanyplugin.h includes Geany
headers, so functions that are not in the interface are unfortunately
made visible to the compiler. This is why the insistence on only using
the things documented (and so in geanyfunctions), even if others are
visible.  This can't be fixed until we remove access to structures eg
using getter/setter functions instead, and so remove the requirement
for the Geany headers.

This means that your plugin must be compiled against a version of
Geany that has the functions you use in the interface, so the compiler
can resolve the structure offsets.  But so long as it is ABI
compatible it can be loaded into any version of Geany with at least
your *minimum* API, which you set to not include those functions that
you can avoid using, based on the runtime version of the API.  If only
you could get the runtime version of the API.

>> The API and ABI number pair should be published (in release notes?)
>> when a release is made for use by plugin packagers.
> +1 ... Franks list on the Wiki is an great start!


> IMO, it's quite useful/important that each function/member's doc-comments be
> annotated with the API version number as well, as has been discussed.  This
> would let developers reading the API docs know *exactly* which API version
> they should check against to use a certain thing, even between releases.

I agree, I find that the "since" info in things like GTK is
invaluable, and I swear at any entries without it.

>> This means that:
>> 1. the interface should be as small as possible so that the least
>> possible changes impact the ABI.
>> 2. structures should not be visible in the interface, instead they
>> should be hidden behind getter/setter functions, and
> ++1 ... This would be great.
> Most importantly (I think) is that you could do whatever you want with the
> struct members without breaking API/ABI compatibility and such, since they
> would be opaque.

Yep, my argument exactly, in fact members could even go away so long
as the getter could calculate the value and the setter could change
whatever was needed to get the same effect.

>> 3. interface wrapper functions should be used to hide the
>> implementation and side effects.
> +1
>> The last two have not been Geany policy to date but I now propose that
>> they be.
> I agree wholeheartedly.
> A bit O/T, but it would also be great to get rid of the need for those pesky
> globals `geany_plugin`, `geany_data`, and `geany_functions` required to
> defined/included in each TU of the plugin.  At least for the first two, they
> could (one already is) be just passed into the plugin's entry-point
> (plugin_init()).  As for `geany_functions`, I'm not sure, since all those
> weird macros in `geanyfunctions.h` require it.

See above for geanyfunctions, all these names are needed for the
various re-direction macros to work.  It is a bit of a fragile part of
the interface, but it is compile time detected.

But perhaps they could be wrapped in a PLUGIN_DECLARE macro or similar.


More information about the Devel mailing list