On Tue, Mar 01, 2016 at 09:26:21AM +1000, Peter Hutterer wrote:
> This switches the scanner to generate doxygen-compatible tags for the
> generated protocol headers, and hooks up the doxygen build to generate server
> and client-side API documentation. That documentation is now in
> Client/ and Server/, respectively.
> 
> GENERATE_HTML is on by default and must be disabled for the xml/man targets to
> avoid messing up the new documentation. We disable all three three targets in
> the doxyfile (xml and man default to NO anyway) to make it obvious that they
> need to be set in the per-target instructions.
> 
> Each protocol is a separate doxygen @page, with each interface a @subpage.
> Wayland only has one protocol, wayland-protocols will have these nested.
> Each protocol page has a list of interfaces and the copyright and description
> where available.
> All interfaces are grouped by doxygen @defgroup and @ingroups and appear in
> "Modules" in the generated output. Each interface subpage has the description
> and a link to the actual API doc.
> Function, struct and #defines are documented in doxygen style and associated
> with the matching interface.
> 
> Note that pages and groups have fixed HTML file names and are directly
> linkable/bookmark-able.
> 
> The @mainpage is a separate file that's included at build time. It doesn't
> contain much other than links to where the interesting bits are. It's a static
> file though that supports markdown, so we can extend it easily in the future.
> 
> For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so
> it scans C code properly. EXTRACT_STATIC is needed since most of the protocol
> hooks are static.
> 
> Signed-off-by: Peter Hutterer <[email protected]>

Reviewed-by: Bryce Harrington <[email protected]>

> ---
> Changes to v3:
> - disable GENERATE_HTML/XML/MAN in the doxyfile
> 
>  doc/doxygen/Makefile.am        |  27 ++++-
>  doc/doxygen/mainpage.dox       |  13 +++
>  doc/doxygen/wayland.doxygen.in |   6 ++
>  src/scanner.c                  | 220 
> +++++++++++++++++++++++++++--------------
>  4 files changed, 188 insertions(+), 78 deletions(-)
>  create mode 100644 doc/doxygen/mainpage.dox
> 
> diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
> index a8bb95f..e80c401 100644
> --- a/doc/doxygen/Makefile.am
> +++ b/doc/doxygen/Makefile.am
> @@ -1,7 +1,11 @@
>  
>  .SUFFIXES = .gv .png .map
>  
> -noinst_DATA = xml/Client/index.xml xml/Server/index.xml
> +noinst_DATA = \
> +              xml/Client/index.xml \
> +              xml/Server/index.xml \
> +              html/Client/index.html \
> +              html/Server/index.html
>  dist_noinst_DATA = wayland.doxygen.in
>  
>  scanned_src_files_shared =                           \
> @@ -27,6 +31,17 @@ scanned_src_files_man =                                    
> \
>       $(top_srcdir)/src/wayland-client.h      \
>       $(top_srcdir)/src/wayland-client-core.h
>  
> +extra_doxygen = \
> +     mainpage.dox
> +
> +extra_doxygen_Server = \
> +     $(top_builddir)/protocol/wayland-server-protocol.h \
> +     $(extra_doxygen)
> +
> +extra_doxygen_Client = \
> +     $(top_builddir)/protocol/wayland-client-protocol.h \
> +     $(extra_doxygen)
> +
>  diagramsdir := $(srcdir)/dot
>  diagramssrc := $(wildcard $(diagramsdir)/*.gv)
>  diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png))
> @@ -38,7 +53,7 @@ diagram_maps := $(patsubst 
> $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.map))
>  dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf 
> "man/man3/%P\n")
>  
>  # Listing various directories that might need to be created.
> -alldirs := xml xml/Client xml/Server man/man3
> +alldirs := xml xml/Client xml/Server man/man3 html/Client html/Server
>  
>  $(diagrams): $(diagramssrc)
>  
> @@ -51,6 +66,13 @@ xml/%/index.xml: $(top_srcdir)/src/scanner.c 
> $(scanned_src_files_%) wayland.doxy
>            echo "INPUT= $(scanned_src_files_$*)"; \
>            ) | $(DOXYGEN) -
>  
> +html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) 
> $(diagram_maps) | html/%
> +     $(AM_V_GEN)(cat wayland.doxygen; \
> +          echo "GENERATE_HTML=YES"; \
> +          echo "HTML_OUTPUT=html/$*"; \
> +          echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \
> +          ) | $(DOXYGEN) -
> +
>  man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) 
> wayland.doxygen | man/man3
>       $(AM_V_GEN)(cat wayland.doxygen; \
>            echo "GENERATE_MAN=YES"; \
> @@ -74,6 +96,7 @@ all-local: man/man3/wl_display.3
>  
>  clean-local:
>       rm -rf xml/
> +     rm -rf html/
>       rm -rf man/
>  
>  EXTRA_DIST = $(diagramssrc)
> diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox
> new file mode 100644
> index 0000000..8f9bf03
> --- /dev/null
> +++ b/doc/doxygen/mainpage.dox
> @@ -0,0 +1,13 @@
> +/**
> + * @mainpage
> + * Wayland protocol API documentation.
> + *
> + * @section ifaces Interfaces
> + * For the list of available interfaces, please see the
> + * <a href="modules.html">modules</a> list.
> + *
> + * @section protocols Protocols
> + * For the list of protocols, please see the
> + * <a href="pages.html">Related Pages</a>.
> + *
> + */
> diff --git a/doc/doxygen/wayland.doxygen.in b/doc/doxygen/wayland.doxygen.in
> index fb76b12..9d7fa0c 100644
> --- a/doc/doxygen/wayland.doxygen.in
> +++ b/doc/doxygen/wayland.doxygen.in
> @@ -13,4 +13,10 @@ MACRO_EXPANSION        = YES
>  EXPAND_ONLY_PREDEF     = YES
>  DOT_MULTI_TARGETS      = YES
>  ALIASES                += comment{1}="/* \1 *<!-- -->/"
> +OPTIMIZE_OUTPUT_FOR_C  = YES
> +EXTRACT_ALL            = YES
> +EXTRACT_STATIC         = YES
> +# These must be set in the Makefile
>  GENERATE_HTML          = NO
> +GENERATE_XML           = NO
> +GENERATE_MAN           = NO
> diff --git a/src/scanner.c b/src/scanner.c
> index d3e2328..5fbc2df 100644
> --- a/src/scanner.c
> +++ b/src/scanner.c
> @@ -877,6 +877,34 @@ character_data(void *data, const XML_Char *s, int len)
>  }
>  
>  static void
> +format_text_to_comment(const char *text, bool standalone_comment)
> +{
> +     int bol = 1, start = 0, i, length;
> +     bool comment_started = !standalone_comment;
> +
> +     length = strlen(text);
> +     for (i = 0; i <= length; i++) {
> +             if (bol && (text[i] == ' ' || text[i] == '\t')) {
> +                     continue;
> +             } else if (bol) {
> +                     bol = 0;
> +                     start = i;
> +             }
> +             if (text[i] == '\n' ||
> +                 (text[i] == '\0' && !(start == i))) {
> +                     printf("%s%s%.*s\n",
> +                            comment_started ? " *" : "/*",
> +                            i > start ? " " : "",
> +                            i - start, text + start);
> +                     bol = 1;
> +                     comment_started = true;
> +             }
> +     }
> +     if (comment_started && standalone_comment)
> +             printf(" */\n\n");
> +}
> +
> +static void
>  emit_opcodes(struct wl_list *message_list, struct interface *interface)
>  {
>       struct message *m;
> @@ -898,9 +926,11 @@ emit_opcode_versions(struct wl_list *message_list, 
> struct interface *interface)
>  {
>       struct message *m;
>  
> -     wl_list_for_each(m, message_list, link)
> +     wl_list_for_each(m, message_list, link) {
> +             printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
>               printf("#define %s_%s_SINCE_VERSION\t%d\n",
>                      interface->uppercase_name, m->uppercase_name, m->since);
> +     }
>  
>       printf("\n");
>  }
> @@ -940,6 +970,7 @@ emit_stubs(struct wl_list *message_list, struct interface 
> *interface)
>       struct arg *a, *ret;
>       int has_destructor, has_destroy;
>  
> +     printf("/** @ingroup iface_%s */\n", interface->name);
>       printf("static inline void\n"
>              "%s_set_user_data(struct %s *%s, void *user_data)\n"
>              "{\n"
> @@ -948,6 +979,7 @@ emit_stubs(struct wl_list *message_list, struct interface 
> *interface)
>              interface->name, interface->name, interface->name,
>              interface->name);
>  
> +     printf("/** @ingroup iface_%s */\n", interface->name);
>       printf("static inline void *\n"
>              "%s_get_user_data(struct %s *%s)\n"
>              "{\n"
> @@ -981,7 +1013,8 @@ emit_stubs(struct wl_list *message_list, struct 
> interface *interface)
>               exit(EXIT_FAILURE);
>       }
>  
> -     if (!has_destroy && strcmp(interface->name, "wl_display") != 0)
> +     if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
> +             printf("/** @ingroup iface_%s */\n", interface->name);
>               printf("static inline void\n"
>                      "%s_destroy(struct %s *%s)\n"
>                      "{\n"
> @@ -990,6 +1023,7 @@ emit_stubs(struct wl_list *message_list, struct 
> interface *interface)
>                      "}\n\n",
>                      interface->name, interface->name, interface->name,
>                      interface->name);
> +     }
>  
>       if (wl_list_empty(message_list))
>               return;
> @@ -1009,6 +1043,11 @@ emit_stubs(struct wl_list *message_list, struct 
> interface *interface)
>                               ret = a;
>               }
>  
> +             printf("/**\n"
> +                    " * @ingroup iface_%s\n", interface->name);
> +             if (m->description && m->description->text)
> +                     format_text_to_comment(m->description->text, false);
> +             printf(" */\n");
>               if (ret && ret->interface_name == NULL)
>                       printf("static inline void *\n");
>               else if (ret)
> @@ -1104,6 +1143,17 @@ emit_event_wrappers(struct wl_list *message_list, 
> struct interface *interface)
>               return;
>  
>       wl_list_for_each(m, message_list, link) {
> +             printf("/**\n"
> +                    " * @ingroup iface_%s\n"
> +                    " * Sends an %s event to the client owning the 
> resource.\n",
> +                    interface->name,
> +                    m->name);
> +             printf("* @param resource_ The client's resource\n");
> +             wl_list_for_each(a, &m->arg_list, link) {
> +                     if (a->summary)
> +                             printf(" * @param %s %s\n", a->name, 
> a->summary);
> +             }
> +             printf(" */\n");
>               printf("static inline void\n"
>                      "%s_send_%s(struct wl_resource *resource_",
>                      interface->name, m->name);
> @@ -1150,28 +1200,23 @@ emit_enumerations(struct interface *interface)
>  
>               if (desc) {
>                       printf("/**\n");
> -                     desc_dump(desc->summary,
> -                               " * %s_%s - ",
> -                               interface->name, e->name);
> -                     wl_list_for_each(entry, &e->entry_list, link) {
> -                             desc_dump(entry->summary,
> -                                       " * @%s_%s_%s: ",
> -                                       interface->uppercase_name,
> -                                       e->uppercase_name,
> -                                       entry->uppercase_name);
> -                     }
> -                     if (desc->text) {
> -                             printf(" *\n");
> -                             desc_dump(desc->text, " * ");
> -                     }
> +                     printf(" * @ingroup iface_%s\n", interface->name);
> +                     format_text_to_comment(desc->summary, false);
> +                     if (desc->text)
> +                             format_text_to_comment(desc->text, false);
>                       printf(" */\n");
>               }
>               printf("enum %s_%s {\n", interface->name, e->name);
> -             wl_list_for_each(entry, &e->entry_list, link)
> +             wl_list_for_each(entry, &e->entry_list, link) {
> +                     if (entry->summary)
> +                             printf("\t/**\n"
> +                                    "\t * %s\n"
> +                                    "\t */\n", entry->summary);
>                       printf("\t%s_%s_%s = %s,\n",
>                              interface->uppercase_name,
>                              e->uppercase_name,
>                              entry->uppercase_name, entry->value);
> +             }
>               printf("};\n");
>               printf("#endif /* %s_%s_ENUM */\n\n",
>                      interface->uppercase_name, e->uppercase_name);
> @@ -1188,20 +1233,11 @@ emit_structs(struct wl_list *message_list, struct 
> interface *interface, enum sid
>       if (wl_list_empty(message_list))
>               return;
>  
> -     if (interface->description) {
> -             struct description *desc = interface->description;
> -             printf("/**\n");
> -             desc_dump(desc->summary, " * %s - ", interface->name);
> -             wl_list_for_each(m, message_list, link) {
> -                     struct description *mdesc = m->description;
> -                     desc_dump(mdesc ? mdesc->summary : "(none)",
> -                               " * @%s: ",
> -                               m->name);
> -             }
> -             printf(" *\n");
> -             desc_dump(desc->text, " * ");
> -             printf(" */\n");
> -     }
> +     printf("/**\n");
> +     printf(" * @ingroup iface_%s\n", interface->name);
> +     printf(" * @struct %s_%s\n", interface->name,
> +            (side == SERVER) ? "interface" : "listener");
> +     printf(" */\n");
>       printf("struct %s_%s {\n", interface->name,
>              (side == SERVER) ? "interface" : "listener");
>  
> @@ -1209,24 +1245,24 @@ emit_structs(struct wl_list *message_list, struct 
> interface *interface, enum sid
>               struct description *mdesc = m->description;
>  
>               printf("\t/**\n");
> -             desc_dump(mdesc ? mdesc->summary : "(none)",
> -                       "\t * %s - ", m->name);
> -             wl_list_for_each(a, &m->arg_list, link) {
> -                     if (side == SERVER && a->type == NEW_ID &&
> -                         a->interface_name == NULL)
> -                             printf("\t * @interface: name of the objects 
> interface\n"
> -                                    "\t * @version: version of the objects 
> interface\n");
> -
> -
> -                     desc_dump(a->summary ? a->summary : "(none)",
> -                               "\t * @%s: ", a->name);
> -             }
>               if (mdesc) {
> +                     if (mdesc->summary)
> +                             printf("\t * %s\n", mdesc->summary);
>                       printf("\t *\n");
>                       desc_dump(mdesc->text, "\t * ");
>               }
> +             wl_list_for_each(a, &m->arg_list, link) {
> +                     if (side == SERVER && a->type == NEW_ID &&
> +                         a->interface_name == NULL)
> +                             printf("\t * @param interface name of the 
> objects interface\n"
> +                                    "\t * @param version version of the 
> objects interface\n");
> +
> +                     if (a->summary)
> +                             printf("\t * @param %s %s\n", a->name,
> +                                    a->summary);
> +             }
>               if (m->since > 1) {
> -                     printf("\t * @since: %d\n", m->since);
> +                     printf("\t * @since %d\n", m->since);
>               }
>               printf("\t */\n");
>               printf("\tvoid (*%s)(", m->name);
> @@ -1266,6 +1302,9 @@ emit_structs(struct wl_list *message_list, struct 
> interface *interface, enum sid
>       printf("};\n\n");
>  
>       if (side == CLIENT) {
> +         printf("/**\n"
> +                " * @ingroup %s_iface\n"
> +                " */\n", interface->name);
>           printf("static inline int\n"
>                  "%s_add_listener(struct %s *%s,\n"
>                  "%sconst struct %s_listener *listener, void *data)\n"
> @@ -1282,34 +1321,6 @@ emit_structs(struct wl_list *message_list, struct 
> interface *interface, enum sid
>  }
>  
>  static void
> -format_copyright(const char *copyright)
> -{
> -     int bol = 1, start = 0, i, length;
> -     bool comment_started = false;
> -
> -     length = strlen(copyright);
> -     for (i = 0; i <= length; i++) {
> -             if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
> -                     continue;
> -             } else if (bol) {
> -                     bol = 0;
> -                     start = i;
> -             }
> -             if (copyright[i] == '\n' ||
> -                 (copyright[i] == '\0' && !(start == i))) {
> -                     printf("%s%s%.*s\n",
> -                            comment_started ? " *" : "/*",
> -                            i > start ? " " : "",
> -                            i - start, copyright + start);
> -                     bol = 1;
> -                     comment_started = true;
> -             }
> -     }
> -     if (comment_started)
> -             printf(" */\n\n");
> -}
> -
> -static void
>  emit_types_forward_declarations(struct protocol *protocol,
>                               struct wl_list *message_list,
>                               struct wl_array *types)
> @@ -1362,6 +1373,46 @@ get_include_name(bool core, enum side side)
>  }
>  
>  static void
> +emit_mainpage_blurb(const struct protocol *protocol, enum side side)
> +{
> +     struct interface *i;
> +
> +     printf("/**\n"
> +            " * @page page_%s The %s protocol\n",
> +            protocol->name, protocol->name);
> +
> +     if (protocol->description) {
> +             if (protocol->description->summary) {
> +                     printf(" * %s\n"
> +                            " *\n", protocol->description->summary);
> +             }
> +
> +             if (protocol->description->text) {
> +                     printf(" * @section page_desc_%s Description\n", 
> protocol->name);
> +                     format_text_to_comment(protocol->description->text, 
> false);
> +                     printf(" *\n");
> +             }
> +     }
> +
> +     printf(" * @section page_ifaces_%s Interfaces\n", protocol->name);
> +     wl_list_for_each(i, &protocol->interface_list, link) {
> +             printf(" * - @subpage page_iface_%s - %s\n",
> +                    i->name,
> +                    i->description && i->description->summary ?  
> i->description->summary : "");
> +     }
> +
> +     if (protocol->copyright) {
> +             printf(" * @section page_copyright_%s Copyright\n",
> +                    protocol->name);
> +             printf(" * <pre>\n");
> +             format_text_to_comment(protocol->copyright, false);
> +             printf(" * </pre>\n");
> +     }
> +
> +     printf(" */\n");
> +}
> +
> +static void
>  emit_header(struct protocol *protocol, enum side side)
>  {
>       struct interface *i, *i_next;
> @@ -1369,9 +1420,6 @@ emit_header(struct protocol *protocol, enum side side)
>       const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
>       char **p, *prev;
>  
> -     if (protocol->copyright)
> -             format_copyright(protocol->copyright);
> -
>       printf("#ifndef %s_%s_PROTOCOL_H\n"
>              "#define %s_%s_PROTOCOL_H\n"
>              "\n"
> @@ -1388,6 +1436,8 @@ emit_header(struct protocol *protocol, enum side side)
>              protocol->uppercase_name, s,
>              get_include_name(protocol->core_headers, side));
>  
> +     emit_mainpage_blurb(protocol, side);
> +
>       wl_array_init(&types);
>       wl_list_for_each(i, &protocol->interface_list, link) {
>               emit_types_forward_declarations(protocol, &i->request_list, 
> &types);
> @@ -1411,6 +1461,24 @@ emit_header(struct protocol *protocol, enum side side)
>       printf("\n");
>  
>       wl_list_for_each(i, &protocol->interface_list, link) {
> +             printf("/**\n"
> +                    " * @page page_iface_%s %s\n",
> +                    i->name, i->name);
> +             if (i->description && i->description->text) {
> +                     printf(" * @section page_iface_%s_desc Description\n",
> +                            i->name);
> +                     format_text_to_comment(i->description->text, false);
> +             }
> +             printf(" * @section page_iface_%s_api API\n"
> +                    " * See @ref iface_%s.\n"
> +                    " */\n",
> +                    i->name, i->name);
> +             printf("/**\n"
> +                    " * @defgroup iface_%s The %s interface\n",
> +                    i->name, i->name);
> +             if (i->description && i->description->text)
> +                     format_text_to_comment(i->description->text, false);
> +             printf(" */\n");
>               printf("extern const struct wl_interface "
>                      "%s_interface;\n", i->name);
>       }
> @@ -1554,7 +1622,7 @@ emit_code(struct protocol *protocol)
>       char **p, *prev;
>  
>       if (protocol->copyright)
> -             format_copyright(protocol->copyright);
> +             format_text_to_comment(protocol->copyright, true);
>  
>       printf("#include <stdlib.h>\n"
>              "#include <stdint.h>\n"
> -- 
> 2.5.0
_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to