[PATCH v2 wayland 3/3] doc: generate doxygen html output from the scanner

Bryce Harrington bryce at osg.samsung.com
Sat Feb 20 03:24:36 UTC 2016


On Mon, Dec 07, 2015 at 02:41:58PM -0800, Bryce Harrington wrote:
> On Tue, Nov 17, 2015 at 10:17:23AM +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.
> > 
> > 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. WARN_IF_DOC_ERROR is required to silence the warnings when
> > some parameters are documented but others aren't.
> > 
> > Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> 
> LGTM,
> Reviewed-by: Bryce Harrington <bryce at osg.samsung.com>
> 
> Anyone else care to comment on this?
> Else, this seems pretty low risk for me to go ahead and land.

Hi Peter,

Looks like we overlooked this one for the release, but it seems the
codebase has moved along a bit.  Would you mind respinning this against
the current tree, and I'll go ahead and land it.

Thanks,
Bryce

> > ---
> > Changes to v1:
> > - rebase to master (c7bada036db1b)
> > - add EXTRACT_STATIC doxygen command, otherwise we'll miss most of the
> >   actual functions in the protocol API.
> > 
> >  doc/doxygen/Makefile.am        |  27 +++++-
> >  doc/doxygen/mainpage.dox       |  13 +++
> >  doc/doxygen/wayland.doxygen.in |   5 +-
> >  src/scanner.c                  | 207 +++++++++++++++++++++++++++--------------
> >  4 files changed, 177 insertions(+), 75 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..bf188cb 100644
> > --- a/doc/doxygen/wayland.doxygen.in
> > +++ b/doc/doxygen/wayland.doxygen.in
> > @@ -13,4 +13,7 @@ MACRO_EXPANSION        = YES
> >  EXPAND_ONLY_PREDEF     = YES
> >  DOT_MULTI_TARGETS      = YES
> >  ALIASES                += comment{1}="/* \1 *<!-- -->/"
> > -GENERATE_HTML          = NO
> > +OPTIMIZE_OUTPUT_FOR_C  = YES
> > +EXTRACT_ALL            = YES
> > +EXTRACT_STATIC         = YES
> > +WARN_IF_DOC_ERROR      = NO
> > diff --git a/src/scanner.c b/src/scanner.c
> > index 8ecdd56..71fcdf2 100644
> > --- a/src/scanner.c
> > +++ b/src/scanner.c
> > @@ -831,9 +831,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");
> >  }
> > @@ -873,6 +875,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"
> > @@ -881,6 +884,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"
> > @@ -906,7 +910,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"
> > @@ -915,6 +920,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;
> > @@ -934,6 +940,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
> >  				ret = a;
> >  		}
> >  
> > +		printf("/** @ingroup iface_%s */\n", interface->name);
> >  		if (ret && ret->interface_name == NULL)
> >  			printf("static inline void *\n");
> >  		else if (ret)
> > @@ -1019,6 +1026,16 @@ 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);
> > +		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);
> > @@ -1050,6 +1067,31 @@ emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
> >  }
> >  
> >  static void
> > +format_text_to_comment(const char *text, bool standalone_comment)
> > +{
> > +	int bol = 1, start = 0, i;
> > +
> > +	for (i = 0; text[i]; i++) {
> > +		if (bol && (text[i] == ' ' || text[i] == '\t')) {
> > +			continue;
> > +		} else if (bol) {
> > +			bol = 0;
> > +			start = i;
> > +		}
> > +
> > +		if (text[i] == '\n' || text[i] == '\0') {
> > +			printf("%s%s%.*s\n",
> > +			       i == 0 && standalone_comment ? "/*" : " *",
> > +			       i > start ? " " : "",
> > +			       i - start, text + start);
> > +			bol = 1;
> > +		}
> > +	}
> > +	if (standalone_comment)
> > +		printf(" */\n\n");
> > +}
> > +
> > +static void
> >  emit_enumerations(struct interface *interface)
> >  {
> >  	struct enumeration *e;
> > @@ -1065,28 +1107,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);
> > @@ -1103,20 +1140,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");
> >  
> > @@ -1124,24 +1152,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);
> > @@ -1181,6 +1209,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"
> > @@ -1197,30 +1228,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;
> > -
> > -	for (i = 0; copyright[i]; i++) {
> > -		if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
> > -			continue;
> > -		} else if (bol) {
> > -			bol = 0;
> > -			start = i;
> > -		}
> > -
> > -		if (copyright[i] == '\n' || copyright[i] == '\0') {
> > -			printf("%s%s%.*s\n",
> > -			       i == 0 ? "/*" : " *",
> > -			       i > start ? " " : "",
> > -			       i - start, copyright + start);
> > -			bol = 1;
> > -		}
> > -	}
> > -	printf(" */\n\n");
> > -}
> > -
> > -static void
> >  emit_types_forward_declarations(struct protocol *protocol,
> >  				struct wl_list *message_list,
> >  				struct wl_array *types)
> > @@ -1273,6 +1280,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;
> > @@ -1280,9 +1327,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"
> > @@ -1299,6 +1343,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);
> > @@ -1322,6 +1368,23 @@ 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",
> > +		       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);
> >  	}
> > @@ -1465,7 +1528,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
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list