[PATCH v2 wayland 3/3] doc: generate doxygen html output from the scanner
Peter Hutterer
peter.hutterer at who-t.net
Mon Nov 16 16:17:23 PST 2015
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>
---
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
More information about the wayland-devel
mailing list