[Libguestfs] [PATCH] Add internal documentation to C files.

Richard W.M. Jones rjones at redhat.com
Tue Apr 12 10:46:41 UTC 2016


As in libvirt, allow internal documentation comments in C files.
These are marked using '/**' comments.  Unlike libvirt which has an
ill-defined and inconsistent markup, the markup we use is Perl POD.

These comments are added to guestfs-internals(1), but are most likely
to be read in-place.

This commit changes some existing comments in src/launch.c to
demonstrate how this can be used.
---
 .gitignore                          |   1 +
 docs/Makefile.am                    |  15 ++-
 docs/guestfs-internals.pod          |   9 ++
 docs/make-internal-documentation.pl | 234 ++++++++++++++++++++++++++++++++++++
 po/POTFILES                         |   1 +
 src/launch.c                        |  70 +++++++----
 6 files changed, 305 insertions(+), 25 deletions(-)
 create mode 100755 docs/make-internal-documentation.pl

diff --git a/.gitignore b/.gitignore
index ca4e89c..ff5f2de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -153,6 +153,7 @@ Makefile.in
 /docs/guestfs-release-notes.1
 /docs/guestfs-security.1
 /docs/guestfs-testing.1
+/docs/internal-documentation.pod
 /docs/stamp-guestfs-building.pod
 /docs/stamp-guestfs-faq.pod
 /docs/stamp-guestfs-hacking.pod
diff --git a/docs/Makefile.am b/docs/Makefile.am
index f880e72..f765966 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -27,6 +27,7 @@ EXTRA_DIST = \
 	guestfs-release-notes.pod \
 	guestfs-security.pod \
 	guestfs-testing.pod \
+	make-internal-documentation.pl \
 	README
 
 CLEANFILES = \
@@ -39,6 +40,7 @@ CLEANFILES = \
 	guestfs-release-notes.1 \
 	guestfs-security.1 \
 	guestfs-testing.1 \
+	internal-documentation.pod \
 	stamp-guestfs-building.pod \
 	stamp-guestfs-faq.pod \
 	stamp-guestfs-hacking.pod \
@@ -105,15 +107,26 @@ stamp-guestfs-hacking.pod: guestfs-hacking.pod
 
 guestfs-internals.1 $(top_builddir)/website/guestfs-internals.1.html: stamp-guestfs-internals.pod
 
-stamp-guestfs-internals.pod: guestfs-internals.pod
+stamp-guestfs-internals.pod: guestfs-internals.pod internal-documentation.pod
 	$(PODWRAPPER) \
 	  --section 1 \
 	  --man guestfs-internals.1 \
 	  --html $(top_builddir)/website/guestfs-internals.1.html \
+	  --insert internal-documentation.pod:__INTERNAL_DOCUMENTATION__ \
 	  --license LGPLv2+ \
 	  $<
 	touch $@
 
+source_files := $(shell grep -Ev '^(gobject/|builder/index-scan.c)' $(top_srcdir)/po/POTFILES)
+
+internal-documentation.pod: $(source_files:%=$(top_srcdir)/%)
+	rm -f $@ $@-t
+	./make-internal-documentation.pl \
+	    --srcdir $(top_srcdir) \
+	    -o $@-t \
+	    $(source_files)
+	mv $@-t $@
+
 guestfs-performance.1 $(top_builddir)/website/guestfs-performance.1.html: stamp-guestfs-performance.pod
 
 stamp-guestfs-performance.pod: guestfs-performance.pod
diff --git a/docs/guestfs-internals.pod b/docs/guestfs-internals.pod
index a554b13..bbb278d 100644
--- a/docs/guestfs-internals.pod
+++ b/docs/guestfs-internals.pod
@@ -397,6 +397,15 @@ on a platform that does support supermin using
 L<libguestfs-make-fixed-appliance(1)>, copy it over, and use that
 to run libguestfs.
 
+=head1 INTERNAL DOCUMENTATION
+
+This section documents internal functions inside libguestfs and
+various utilities.  It is intended for libguestfs developers only.
+These functions are not publicly exported, and may change or be
+removed at any time.
+
+__INTERNAL_DOCUMENTATION__
+
 =head1 SEE ALSO
 
 L<guestfs(3)>,
diff --git a/docs/make-internal-documentation.pl b/docs/make-internal-documentation.pl
new file mode 100755
index 0000000..4edb5bc
--- /dev/null
+++ b/docs/make-internal-documentation.pl
@@ -0,0 +1,234 @@
+#!/usr/bin/env perl
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use warnings;
+use strict;
+
+use Getopt::Long;
+
+=head1 NAME
+
+make-internal-documentation.pl - Generate internal documentation from C files
+
+=head1 SYNOPSIS
+
+ make-internal-documentation.pl --output internal-documentation.pod
+   [C source files ...]
+
+=head1 DESCRIPTION
+
+C<make-internal-documentation.pl> is a script that generates
+L<guestfs-internals(1)/INTERNAL DOCUMENTATION>.
+
+You must specify the name of the output file using the I<-o> or
+I<--output> option, and a list of the C source files in the project.
+
+Internal documentation is added to the C source files using special
+comments which look like this:
+
+ /**
+  * Returns true if C<foo> equals C<bar>.
+  */
+ bool
+ is_equal (const char *foo, const char *bar)
+   ...
+
+The comment is written in POD format (see L<perlpod(1)>).  It may be
+on several lines, and be split into paragraphs using blank lines.
+
+The function being documented should appear immediately after the
+special comment, and is also copied into the documentation.
+
+In addition, each C file may have a special comment at the top of the
+file (before any C<#include> lines) which outlines what the file does.
+
+=head1 OPTIONS
+
+=over 4
+
+=cut
+
+my $help;
+
+=item B<--help>
+
+Display brief help.
+
+=cut
+
+my $output;
+
+=item B<-o output.pod>
+
+=item B<--output output.pod>
+
+Set the name of the output file (required).
+
+=cut
+
+my $srcdir = ".";
+
+=item B<--srcdir top_srcdir>
+
+Path to the top source directory.  Input filenames are
+located relative to this path.
+
+=back
+
+=cut
+
+# Clean up the program name.
+my $progname = $0;
+$progname =~ s{.*/}{};
+
+# Parse options.
+GetOptions ("help|?" => \$help,
+            "output=s" => \$output,
+            "srcdir=s" => \$srcdir,
+    ) or pod2usage (2);
+pod2usage (1) if $help;
+
+die "$progname: missing -o/--output parameter\n" unless defined $output;
+
+die "$progname: missing argument: make-internal-documentation [C source files ...]\n" unless @ARGV >= 1;
+
+# Only consider input files which
+#  - are C source files
+#  - exist
+#  - contain /** comments.
+
+my @inputs = ();
+my $input;
+my $path;
+foreach $input (@ARGV) {
+    if ($input =~ /\.c$/) {
+        $path = "$srcdir/$input";
+        if (-r $path) {
+            my @cmd = ("grep", "-q", "^/\\*\\*", $path);
+            if (system (@cmd) == 0) {
+                push @inputs, $input
+            }
+        }
+    }
+}
+ at inputs = sort @inputs;
+
+open OUTPUT, ">$output" or die "$progname: $output: $!";
+
+foreach $input (@inputs) {
+    $path = "$srcdir/$input";
+
+    print OUTPUT ("=head2 F<$input>\n\n");
+
+    open INPUT, $path or die "$progname: $input: $!";
+
+    # A single special comment seen before any #includes can be used
+    # to outline the purpose of the source file.
+    my $seen_includes = 0;
+    my $lineno = 0;
+
+    while (<INPUT>) {
+        chomp;
+        $lineno++;
+        $seen_includes = 1 if /^#include/;
+
+        if (m{^/\*\*$}) {
+            # Found a special comment.  Read the whole comment.
+            my @comment = ();
+            my $found_end = 0;
+            my $start_lineno = $lineno;
+            while (<INPUT>) {
+                chomp;
+                $lineno++;
+
+                if (m{^ \*/$}) {
+                    $found_end = 1;
+                    last;
+                }
+                elsif (m{^ \* (.*)}) {
+                    push @comment, $1;
+                }
+                elsif (m{^ \*$}) {
+                    push @comment, "";
+                }
+                else {
+                    die "$progname: $input: $lineno: special comment with incorrect format\n";
+                }
+            }
+            die "$progname: $input: $start_lineno: unterminated special comment"
+                unless $found_end;
+
+            unless ($seen_includes) {
+                # If we've not seen the includes yet, then this is the
+                # top of file special comment, so we just write it out.
+                print OUTPUT join("\n", @comment), "\n";
+                print OUTPUT "\n";
+            }
+            else {
+                # Otherwise it's a function description, so now we
+                # need to read in the function definition.
+                my @function = ();
+                $found_end = 0;
+                $start_lineno = $lineno;
+                while (<INPUT>) {
+                    chomp;
+                    $lineno++;
+
+                    if (m/^{/) {
+                        $found_end = 1;
+                        last;
+                    }
+                    else {
+                        push @function, $_;
+                    }
+                }
+
+                die "$progname: $input: $start_lineno: unterminated function definition"
+                    unless $found_end;
+
+                # Print the function definition, followed by the comment.
+                print OUTPUT " ", join ("\n ", @function), "\n";
+                print OUTPUT "\n";
+                print OUTPUT join("\n", @comment), "\n";
+                print OUTPUT "\n";
+            }
+        }
+        elsif (m{^/\*\*}) {
+            die "$progname: $input: $lineno: special comment with incorrect format\n";
+        }
+    }
+
+
+    close INPUT;
+}
+
+close OUTPUT or die "$progname: $output: close: $!";
+
+exit 0;
+
+=head1 SEE ALSO
+
+L<perlpod(1)>,
+libguestfs.git/README.
+
+=head1 AUTHOR
+
+Richard W.M. Jones.
+
+=head1 COPYRIGHT
+
+Copyright (C) 2012-2016 Red Hat Inc.
diff --git a/po/POTFILES b/po/POTFILES
index 20a330e..9e4d9cc 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -126,6 +126,7 @@ df/main.c
 df/output.c
 df/parallel.c
 diff/diff.c
+docs/make-internal-documentation.pl
 edit/edit.c
 erlang/erl-guestfs-proto.c
 erlang/erl-guestfs.c
diff --git a/src/launch.c b/src/launch.c
index 7bc9cf9..32f725b 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -16,6 +16,15 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/**
+ * This file implements L<guestfs(3)/guestfs_launch>.
+ *
+ * Most of the work is done by the backends (see
+ * L<guestfs(3)/BACKEND>), which are implemented in
+ * F<src/launch-direct.c>, F<src/launch-libvirt.c> etc, so this file
+ * mostly passes calls through to the current backend.
+ */
+
 #include <config.h>
 
 #include <stdio.h>
@@ -119,9 +128,11 @@ guestfs_int_launch_send_progress (guestfs_h *g, int perdozen)
   }
 }
 
-/* Compute Y - X and return the result in milliseconds.
+/**
+ * Compute C<y - x> and return the result in milliseconds.
+ *
  * Approximately the same as this code:
- * http://www.mpp.mpg.de/~huber/util/timevaldiff.c
+ * L<http://www.mpp.mpg.de/~huber/util/timevaldiff.c>
  */
 int64_t
 guestfs_int_timeval_diff (const struct timeval *x, const struct timeval *y)
@@ -148,7 +159,10 @@ guestfs_impl_get_pid (guestfs_h *g)
   return g->backend_ops->get_pid (g, g->backend_data);
 }
 
-/* Maximum number of disks. */
+/**
+ * Returns the maximum number of disks allowed to be added to the
+ * backend (backend dependent).
+ */
 int
 guestfs_impl_max_disks (guestfs_h *g)
 {
@@ -159,8 +173,10 @@ guestfs_impl_max_disks (guestfs_h *g)
   return g->backend_ops->max_disks (g, g->backend_data);
 }
 
-/* You had to call this function after launch in versions <= 1.0.70,
- * but it is now a no-op.
+/**
+ * Implementation of L<guestfs(3)/guestfs_wait_ready>.  You had to
+ * call this function after launch in versions E<le> 1.0.70, but it is
+ * now an (almost) no-op.
  */
 int
 guestfs_impl_wait_ready (guestfs_h *g)
@@ -251,25 +267,6 @@ guestfs_impl_config (guestfs_h *g,
   return 0;
 }
 
-/* Construct the Linux command line passed to the appliance.  This is
- * used by the 'direct' and 'libvirt' backends, and is simply
- * located in this file because it's a convenient place for this
- * common code.
- *
- * The 'appliance_dev' parameter must be the full device name of the
- * appliance disk and must have already been adjusted to take into
- * account virtio-blk or virtio-scsi; eg "/dev/sdb".
- *
- * The 'flags' parameter can contain the following flags logically
- * or'd together (or 0):
- *
- * GUESTFS___APPLIANCE_COMMAND_LINE_IS_TCG: If we are launching a qemu
- * TCG guest (ie. KVM is known to be disabled or unavailable).  If you
- * don't know, don't pass this flag.
- *
- * Note that this returns a newly allocated buffer which must be freed
- * by the caller.
- */
 #if defined(__powerpc64__)
 #define SERIAL_CONSOLE "console=hvc0 console=ttyS0"
 #elif defined(__arm__) || defined(__aarch64__)
@@ -284,6 +281,31 @@ guestfs_impl_config (guestfs_h *g,
 #define EARLYPRINTK ""
 #endif
 
+/**
+ * Construct the Linux command line passed to the appliance.  This is
+ * used by the C<direct> and C<libvirt> backends, and is simply
+ * located in this file because it's a convenient place for this
+ * common code.
+ *
+ * The C<appliance_dev> parameter must be the full device name of the
+ * appliance disk and must have already been adjusted to take into
+ * account virtio-blk or virtio-scsi; eg C</dev/sdb>.
+ *
+ * The C<flags> parameter can contain the following flags logically
+ * or'd together (or 0):
+ *
+ * =over 4
+ *
+ * =item C<GUESTFS___APPLIANCE_COMMAND_LINE_IS_TCG>
+ *
+ * If we are launching a qemu TCG guest (ie. KVM is known to be
+ * disabled or unavailable).  If you don't know, don't pass this flag.
+ *
+ * =back
+ *
+ * Note that this function returns a newly allocated buffer which must
+ * be freed by the caller.
+ */
 char *
 guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev,
 				    int flags)
-- 
2.7.4




More information about the Libguestfs mailing list