All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrei Ziureaev <andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
To: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	devicetree-compiler-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [RFC PATCH 2/4] dtc: Add plugin documentation and examples
Date: Mon, 3 Aug 2020 15:09:01 +0100	[thread overview]
Message-ID: <b2f04d65-736a-802a-7e49-648ed6784a09@arm.com> (raw)
In-Reply-To: <20200803080808.GD7553-l+x2Y8Cxqc4e6aEkudXLsA@public.gmane.org>


On 8/3/20 9:08 AM, David Gibson wrote:
> On Tue, Jul 21, 2020 at 04:58:58PM +0100, Andrei Ziureaev wrote:
>> Document the plugin API in Documentation/manual.txt and provide an
>> example plugin.
>>
>> Signed-off-by: Andrei Ziureaev <andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
> So, thanks for starting out with some docs.  However, I don't think
> these docs cover the most important things for them to cover: what the
> API is for the plugin - what information goes in, what information
> goes out, and what all the supported entry points are.  Understanding
> the data model of the plugin would make reviewing the rest of the
> details much easier.
OK, so I'll add some documentation to dtc-plugin.h and duplicate that in
the manual. That will look something like this:

/*
  * Function types that plugins can export.
  * DTC calls each type exactly once for each plugin.
  */

/**
  * Called right after the plugin is loaded.
  *
  * Every plugin must export a function of this type.
  *
  * @param dtc_ver    DTC's plugin API version
  * @param argc       Length of argv
  * @param argv       Array of plugin arguments
  * @return 0 on success, or 1 on failure
  */
typedef int (*init_fn_t)(struct plugin_version dtc_ver, int argc,
                          struct plugin_arg *argv);

/**
  * Called after DTC's parsing stage, but before the output stage.
  *
  * @param dti    DTC's internal live tree. Implementations can modify
  *               the live tree and "pass it back" to DTC and to
  *               subsequent plugins.
  */
typedef void (*validate_fn_t)(struct dt_info *dti);

One other point: we could pass validate_fn_t a copy of the live tree.
Then plugins won't be able to "pass back" the live tree. The external
live tree could then be a completely separate struct from the internal
one. So, less flexibility for plugins, but a better, more stable API.
>
>> ---
>>   Documentation/manual.txt         | 74 ++++++++++++++++++++++++++++++++
>>   plugins/example/Makefile.example | 19 ++++++++
>>   plugins/example/example.c        | 29 +++++++++++++
>>   3 files changed, 122 insertions(+)
>>   create mode 100644 plugins/example/Makefile.example
>>   create mode 100644 plugins/example/example.c
>>
>> diff --git a/Documentation/manual.txt b/Documentation/manual.txt
>> index adf5ccb..18624aa 100644
>> --- a/Documentation/manual.txt
>> +++ b/Documentation/manual.txt
>> @@ -10,6 +10,10 @@ I - "dtc", the device tree compiler
>>       4.1) Overview
>>       4.2) Properties
>>       4.3) Labels and References
>> +    5) Plugins
>> +    5.1) Loading plugins
>> +    5.2) Exporting Functionality
>> +    5.3) Building Plugins
>>
>>   II - The DT block format
>>       1) Header
>> @@ -115,6 +119,16 @@ Options:
>>       -d <dependency_filename>
>>      Generate a dependency file during compilation.
>>
>> +    -l, --plugin <plugin name>[,key][,value]
>> +    Load a plugin and, optionally, pass it an argument.
>> +            plugin name - the name of the shared object without the extension (can contain a path)
>> +            key         - the name of the argument
>> +            value       - can be omitted
>> +    Example: dtc -lsome-plugin,o,out.dts -lsome-plugin,help -l path/to/another-plugin [...]
>> +
>> +    -L, --plugin-dir <arg>
>> +    The directory in which to search for plugins
>> +
>>       -q
>>      Quiet: -q suppress warnings, -qq errors, -qqq all
>>
>> @@ -272,6 +286,66 @@ And used in properties, labels may appear before or after any value:
>>       };
>>
>>
>> +5) Plugins
>> +
>> +Plugins are shared libraries that DTC loads at runtime using
>> +
>> +    dlopen(path, RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND)
>> +
>> +RTLD_NOW means they are loaded immediately (right before the parsing
>> +stage).
>> +
>> +RTLD_GLOBAL means their symbols can be used by other plugins.
>> +
>> +RTLD_DEEPBIND means the dynamic linker will look for symbols within the
>> +plugin first, before searching in the main program and other plugins.
>> +
>> +All plugins must include the "dtc-plugin.h" header.
>> +
>> +
>> +5.1) Loading plugins
>> +
>> +Please, refer to the -l and -L options in the "Command Line" section.
>> +
>> +
>> +5.2) Exporting Functionality
>> +
>> +Plugins export functionality through the "EXPORT_FUNCTION(type, fn)"
>> +macro, where "type" is one of the typedefs from "dtc-plugin.h", and
>> +"fn" is the function that will be called by DTC. Each type of function
>> +gets called once for each plugin.
>> +
>> +Every plugin must export a function of type "init_fn_t".
>> +
>> +"plugins/example/example.c" shows how an init function can be used.
>> +
>> +
>> +5.3) Building Plugins
>> +
>> +The command "make plugins" infers the names of the shared library files
>> +from the names of directories under "plugins/". For example, the
>> +presence of a
>> +
>> +    plugins/example/
>> +
>> +directory means that make will try to build
>> +
>> +    plugins/example/example.so
>> +
>> +from
>> +
>> +    plugins/example/example.c
>> +
>> +It will then make a symlink
>> +
>> +    plugins/example.so
>> +
>> +for convenience.
>> +
>> +Please, see "plugins/example/Makefile.example" for how to override the
>> +defaut behavior.
>> +
>> +
>>
>>   II - The DT block format
>>   ========================
>> diff --git a/plugins/example/Makefile.example b/plugins/example/Makefile.example
>> new file mode 100644
>> index 0000000..56d4e17
>> --- /dev/null
>> +++ b/plugins/example/Makefile.example
>> @@ -0,0 +1,19 @@
>> +# Optional per-plugin makefile
>> +#
>> +# Here you can add gcc flags:
>> +# PLUGIN_CFLAGS_example = -some-flag
>> +#
>> +# Add libraries:
>> +# PLUGIN_LDLIBS_example = -lsome-lib
>> +#
>> +# Add files to clean:
>> +# PLUGIN_CLEANFILES += $(PLUGIN_dir)/example/*.tmp
>> +#
>> +# Or override the default rules:
>> +# $(PLUGIN_dir)/example/example.$(SHAREDLIB_EXT): $(PLUGIN_dir)/example/example.o
>> +#   @$(VECHO) LD $@
>> +#   ...
>> +#
>> +# $(PLUGIN_dir)/example/example.o: $(PLUGIN_dir)/example/example.c
>> +#   @$(VECHO) CC $@
>> +#   ...
>> diff --git a/plugins/example/example.c b/plugins/example/example.c
>> new file mode 100644
>> index 0000000..3bbf9ea
>> --- /dev/null
>> +++ b/plugins/example/example.c
>> @@ -0,0 +1,29 @@
>> +#include <stdio.h>
>> +#include <string.h>
>> +
>> +#include "dtc-plugin.h"
>> +
>> +#define NAME "example: "
>> +
>> +static int init_example(struct plugin_version v, int argc, struct plugin_arg *argv)
>> +{
>> +    if (!dtc_plugin_default_version_check(v)) {
>> +            fprintf(stderr, NAME"Plugin is incompatible with this version of DTC\n");
>> +            return 1;
>> +    }
>> +
>> +    for (int i = 0; i < argc; i++) {
>> +            if (strcmp(argv[i].key, "h") == 0
>> +             || strcmp(argv[i].key, "help") == 0) {
>> +                    printf(NAME"This is an example plugin. It prints its arguments.\n");
>> +                    return 1;
>> +            } else {
>> +                    printf(NAME"%s: %s\n", argv[i].key,
>> +                           argv[i].value ? argv[i].value : "");
>> +            }
>> +    }
>> +
>> +    printf(NAME"Loaded plugin 'example'\n");
>> +    return 0;
>> +}
>> +EXPORT_FUNCTION(init_fn_t, init_example);
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

  parent reply	other threads:[~2020-08-03 14:09 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-21 15:58 [RFC PATCH 0/4] dtc: Add a plugin interface Andrei Ziureaev
     [not found] ` <20200721155900.9147-1-andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
2020-07-21 15:58   ` [RFC PATCH 1/4] dtc: Include stdlib.h in util.h Andrei Ziureaev
     [not found]     ` <20200721155900.9147-2-andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
2020-07-22  6:41       ` David Gibson
2020-07-21 15:58   ` [RFC PATCH 2/4] dtc: Add plugin documentation and examples Andrei Ziureaev
     [not found]     ` <20200721155900.9147-3-andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
2020-08-03  8:08       ` David Gibson
     [not found]         ` <20200803080808.GD7553-l+x2Y8Cxqc4e6aEkudXLsA@public.gmane.org>
2020-08-03 14:09           ` Andrei Ziureaev [this message]
     [not found]             ` <b2f04d65-736a-802a-7e49-648ed6784a09-5wv7dgnIgG8@public.gmane.org>
2020-08-03 14:23               ` Andrei Ziureaev
2020-07-21 15:58   ` [RFC PATCH 3/4] dtc: Move some definitions into dtc-plugin.h Andrei Ziureaev
     [not found]     ` <20200721155900.9147-4-andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
2020-07-23 14:16       ` Rob Herring
2020-07-21 15:59   ` [RFC PATCH 4/4] dtc: Add a plugin interface Andrei Ziureaev
     [not found]     ` <20200721155900.9147-5-andrei.ziureaev-5wv7dgnIgG8@public.gmane.org>
2020-07-23 14:46       ` Rob Herring
     [not found]         ` <CAL_JsqL47ykA82LdeXV0ZkfC9s=-aBJ0mkmJqB-t4+Jpeev7Pg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2020-07-23 18:22           ` Andrei Ziureaev
     [not found]             ` <9b0a289f-fd39-9ed7-0866-03390f7188c2-5wv7dgnIgG8@public.gmane.org>
2020-07-24 21:26               ` Rob Herring

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b2f04d65-736a-802a-7e49-648ed6784a09@arm.com \
    --to=andrei.ziureaev-5wv7dgnigg8@public.gmane.org \
    --cc=david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org \
    --cc=devicetree-compiler-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.