Writing documentation

Author(s): Manuel Hermenegildo, Jose F. Morales.

This section includes some details for writing proper documentation in lpdoc, improving the layout of manuals, usage tips, and troubleshooting advice.

Documenting source files

While lpdoc can produce useful documentation from the interface of the source file, the quality of the documentation generated can be greatly enhanced by including within the program text:

  • assertions, and

  • machine-readable comments.

Assertions are declarations which are included in the source program and provide the compiler with information regarding properties of the code. Typical assertions include type declarations, modes, computational properties (such as nonfailure or determinacy), many compiler directives (such as dynamic/1, op/3, meta_predicate/1...), etc. When documenting a module, lpdoc will use the assertions associated with the module interface to construct a textual description of this interface. In principle, only the exported predicates are documented, although any predicate can be included in the documentation by explicitly requesting it (see the documentation for the doc/2 declaration). Judicious use of these assertions allows at the same time documenting the program code, documenting the external use of the module, and greatly improving program debugging and allowing program verification. The latter is possible because the assertions provide the compiler with information on the intended meaning or behaviour of the program (i.e., the specification) which can be checked at compile-time (by a suitable preprocessor/static analyzer) and/or at run-time (via checks inserted by a preprocessor). See The Ciao assertion language for more details.

Machine-readable comments are also declarations included in the source program which contain additional information intended to be read by humans (i.e., this is an instantiation of the literate programming style of Knuth [Knu84]). Typical such comments include title, author(s), summary, bugs, changelog, etc. Judicious use of these comments allows enhancing at the same time the documentation of the program text and the manuals generated from it. See Documentation mark-up language and doc declarations for more details. These declarations can also be writtten in wiki (mark-down) style -- see doccomments.

lpdoc requires these assertions and machine-readable comments to be written using the Ciao assertion language. While Ciao has core support for this language, it is however quite straightforward in most Prolog and (C)LP systems to define a library with dummy declarations so that the assertions and comments meant for lpdoc are simply ignored by the compiler, making it possible to compile programs documented using assertions and comments in such systems and at the same time generate documentation using lpdoc (as well as making other uses of the assertions such as checking tehm statically and/or dynamically).

More complex manuals

Writing and generating more complex manuals involves writing a documentation configuration (doccfg) file (e.g, SETTINGS.pl) with this basic structure:

:- module(_, [], [doccfg]).

doc_structure :=

The first line indicates that this is a module implementing a doccfg. The second line defines through doc_structure/1 the document structure, specifying in a tree the main file and (optional) component files. When documenting complex manuals with more than one source files, the main file is the one that will provide the general title, author, date, summary, and the introduction. The component files will appear as separate chapters.

Any option not directly specified will use the default values indicated in doccfg. You may however want to change several of these:

  • filepath/1: option to include all additional directories where the files to be documented can be found (alias paths for libraries are included automatically).

  • doc_mainopts/1: control what is included in the documentation for the main file.

  • doc_compopts/1: sets options for the component files.

  • docformat/1: determines the set of formats (pdf, ascii, html, info, manl, ...) in which the documentation should be generated by default.

  • output_name/1: determines the base file name of the main documents generated by lpdoc.

  • index/1: determines the list of indices to be included at the end of the document.

  • bibfile/1: determines a list of .bib files containing bibliographic entries for using citations.

  • startpage/1: allows changing the page number of the first page of the manual.

  • papertype/1: allows select several paper sizes for the printable outputs (pdf).

See doccfg for other options.

Advanced usage tips

This section contains additional suggestions on the use of lpdoc.

Documenting libraries and/or applications

For each a .pl file, lpdoc tries to determine whether it is a library or an application (exporting main/0 or main/1), and documents it accordingly.

The generated documentation for libraries will contain information on the interface (e.g., the predicates exported by the file, the name of the module and usage if it is a module, etc.), in addition to any other machine readable comments included in the file. The interface information is omitted in for applications by default.

Any combination of libraries and/or main files of applications can be used arbitrarily as components or main files of a lpdoc manual. Some typical combinations are:

  • Main file is a library, no components: A manual of a simple library, which appears externally as a single module. The manual describes the purpose of the library and its interface.

  • Main file is an application, no components: A manual of a simple application.

  • Main file is a library, components are also libraries: This can be used for example for generating an internals manual of a library. The main file describes the purpose and use of the library, while the components describe the internal modules of the library.

  • Main file is an application, components are libraries: This can be used similarly for generating an internals manual of an application. The main file describes the purpose and use of the application, while the components describe the internal modules which compose the application.

  • Main file is a (pseudo-)application, components are libraries: A manual of a complex library made up of smaller libraries (for example, the Prolog library). The (pseudo-)application file contains the introductory material (title, version, etc.). Each chapter describes a particular library.

  • Main file is a (pseudo-)application, components are applications: This can be used to generate a manual of a set of applications (e.g., a set of utilities). The (pseudo-)application file contains the introductory material (title, version, etc.). Each chapter describes a particular component application.

Documenting files which are not modules

Sometimes it is difficult for lpdoc to distinguish include files and Ciao packages from normal user files (i.e., normal code files but which are not modules). The distinction is important because the former are quite different in their form of use (they are loaded via include/1 or use_package/1 declarations instead of ensure_loaded/1) and effect (since they are included, they 'export' operators, declarations, etc.), and should typically be documented differently. There is a special doc/2 declaration (:- doc(filetype,...).) which provides a way of defining the intended use of the file. This declaration is normally not needed in modules, include files, or packages, but should be added in user files (i.e., those meant to be loaded using ensure_loaded/1). Adding this declaration will, for example, avoid spurious documentation of the declarations in the assertions package themselves when this package is included in a user file.

Splitting large documents into parts

In large documents, it is sometimes convenient to build a super-structure of parts, each of which groups several components. There is a special value of the second argument of the :- doc(filetype,...). declaration mentioned above designed for this purpose. The special filetype value part can be used to flag that the file in which it appears should be documented as the start of one of the major parts in a large document. In order to introduce such a part, a .pl file with a declaration :- doc(filetype,part). should be inserted in the sequence of files that make up the components variable of the documentation configuration file at each point in which a major part starts. The :- doc(title,"..."). declaration of this file will be used as the part title, and the :- doc(module,"..."). declaration text will be used as the introduction to the part.

Documenting reexported predicates

Reexported predicates, i.e., predicates which are exported by a module m1 but defined in another module m2 which is used by m1, are normally not documented in the original module, but instead a simple reference is included to the module in which it is defined. This can be changed, so that the documentation is included in the original module, by using a doc/2 declaration with doinclude in the first argument (see the comments library). This is often useful when documenting a library made of several components. For a simple user's manual, it is often sufficient to include in the documentation configuration file the principal module, which is the one which users will do a use_module/1 of, in the manual. This module typically exports or reexports all the predicates which define the library's user interface. Note, however, that currently, due to limitations in the implementation, only the comments inside assertions (but not those in doc/2 declarations) are included for reexported predicates.

Separating the documentation from the source file

Sometimes one would not like to include long introductory comments in the module itself but would rather have them in a different file. This can be done quite simply by using the @include command. For example, the following declaration:

:- doc(module,"@include{Intro.lpdoc}").

will include the contents of the file Intro.lpdoc as the module description.

Alternatively, sometimes one may want to generate the documentation from a completely different file. Assuming that the original module is mod.pl, this can be done by calling the module containing the documentation mod_doc.pl. This mod_doc.pl file is the one that will be included in the documentation configuration file, instead of mod.pl. lpdoc recognizes and treats such _doc files specially so that the name without the _doc part is used in the different parts of the documentation, in the same way as if the documentation were placed in file mod.

Generating README files

Using lpdoc it is often possible to use a common source for documentation text which should appear in several places. For example, assume a file INSTALLATION.lpdoc contains text describing an application. This text can be included in a section of the main file documentation as follows:

:- doc(module,"
   @section{Installation instructions}

At the same time, this text can be used to generate a nicely formatted INSTALLATION file in ascii, which can perhaps be included in the top level of the source directory of the application. To this end, an INSTALL.pl file as follows can be constructed:

:- use_package([assertions]).
:- doc(filetype, application). %% forces file to be documented as an application
:- doc(title,"Installation instructions").
:- doc(module,"@include{INSTALLATION.lpdoc}").

Then, the ascii INSTALLATION file can be generated by simply running lpdoc -t ascii INSTALLATION.pl.

Documenting version/patch changes

lpdoc supports version comments (:- doc(version(...), "...").) to document the list of version/patch changes (CHANGELOGs) of a particular software. These can be included as part of the manual or translated to plain text (Generating README files).

Version numbers in comments specify a major, minor, and patch number. As a common convention, patch changes (e.g., 1.1#2 to 1.1#3) are reserved for internal changes, such as bug fixes and backward-compatible changes whose detailed description may not be relevant for the user. More general changes (including the summary of internal changes when appropriate) are documented with changes in the major and minor numbers (e.g., 1.1#2 to 1.2#0).

Selecting the appropriate options in lpdoc (e.g., no_patch in doc_mainopts), it is possible to include in the manual the version changes but not the patch changes (which might on the other hand be included in an internals manual). This is useful, for example, to document separatelly internal from general changes.

Troubleshooting with texinfo-based targets

Due to limitations in texinfo and GNU info, it is sometimes a little tricky to get things to work uniformly for all formats. The following recommendations are intended to help in achieving useful manuals in texinfo-based formats, as well as some common errors and their usual fix:

  • The GNU info format requires all nodes (chapters, sections, etc.) to have different names. This is ensured by lpdoc for the automatically generated sections (by appending the module or file name to all section headings). However, care must be taken when writing section names manually to make them different. For example, use “lpdoc usage” instead of simply “Usage”, which is much more likely to be used as a section name in another file being documented.

  • Also due to a limitation of the info format, do not use : or , or -- in section, chapter, etc. headings.

  • The character “_” in names may sometimes give problems in indices, since current versions of texinfo do not always handle it correctly.

  • Messages of the type:
     ! No room for a new .
    while converting from .texi to .dvi (i.e., while running tex). These messages are tex's way of saying that an internal area (typically for an index) is full. This is normally because more indices were selected in the index/1 option of the documentation configuration file than the maximum number supported by the installed version of tex/texinfo installations, as mentioned in Generating and accessing manuals. The easiest fix is to reduce the number of indices generated. Alternatively, it may be possible to recompile your local tex/texinfo installation with a higher number of indices.

  • Missing links in info files (a section which exists in the printed document cannot be accessed in the on-line document) can be due to the presence of a colon (:), a comma (,), a double dash (--), or other such separators in a section name. Due to limitations of info section names cannot contain these symbols.

  • Menu listings in info which do not work (i.e., the menu listings are there, but they cannot be followed): see if they are indented. In that case it is due to an itemize or enumerate which was not closed.