DelphiDox - Documentation
Prerequisites

Using DelphiDox requires some preparation:


Preparing the Delphi Project


Creating a Doxygen configuration

In "Project explorer" right click on "Build configurations" and choose "New configuration":

Then add the configurations name "Doxygen" in the "New build configuration" dialog:


Setting configuration options

Open build configuration

Open the project options dialog and select the newly created build configuration:

Set Delphi output directories

In "Create / Delphi compiler" set the output directories as desired, additionally define the condition "DOXYGEN":

Configure C++ (.hpp) header generation

Do so in the "Create / Delphi compiler / C/C++ output" dialog; also select "Create C++ objs, headers" in the respective dropdown field:

Note
  • As Delphi doesn't create an executable the $(platform) macro can be ommitted and only the $(config) macro may be used to specify the destination directories.
  • The important selection is "Create C++ objs, headers" which results in creating the .hpp header files during compilation.
  • Also the .obj files for C++Builder always are created, but are not used for our purpose.
Attention
  • Selecting "Create C++ objs, headers" also results in not creating an executable and thus resulting in an error message if you try to start the application.

Automatically generate Doxygen documentation

Optionally Post build events can be set to automatically execute Doxygen after building the Delphi project:

Note
In DelphiDox.bat adjust the path to your Doxygen installation!

Preparing Delphi modules


Excluding Delphi code from Doxygen parsing

To cause Doxygen parsing files there must be included a \file command; to not confuse Doxygen afterwards exclude all Delphi source code from being parsed by Doxygen:

//! @file
//! @brief this is a Delphi source code unit
//!
//! ...Doxygen documentation commands... - s. below
//!
//! @cond
//
// Delphi directives: s. below
//
unit example;
...Delphi source code...
end;
//! @endcond

Treat Delphi unit as a Doxygen module

Also it is convenient to gather whole unit documentation in a Doxygen module; so a \addtogroup directive should be added:

//! @file
//! ...
//! @addtogroup
//! @{
//! ...group description...
//! @cond
unit example;
...Delphi source code...
end;
//! @endcond
//! @}

Adding Doxygen stuff to Delphi generated .hpp file

Next some additional output has to be written to the Delphi generated .hpp file. This is done by the Delphi directive {$HPPEMIT ...} which puts user defined output at the beginning of the .hpp file and likewise {$HPPEMIT END ...} puts additional output at the end of the .hpp file.

So next there are added the following Delphi directives to cause the Delphi compiler to insert user code into the compiler generated .hpp file:

{$HPPEMIT '//! @file <example>.pas'} // causes the Delphi module file to be part of
// the Doxygen's files section documentation
{$HPPEMIT '//! @file'} // causes the .hpp file to be part of
// the Doxygen's files section documentation
{$HPPEMIT '#include "doxygen.h"'} // s. below

The additional include file "doxygen.h" consists of defines to replace some C++Builder specific output by nothing for better readability. This file may be changed or extended as desired:

1 // =============================================================================
2 // Hilfsdatei zur Kommentierung von Delphi-Quelltexten mit Doxygen
3 //
4 // Diese Datei sollte per HPPEMIT in die von Delphi erzeugten HPP-Dateien
5 // eingefügt werden
6 // =============================================================================
7 
8 #ifdef DOXYGEN // PREDEFINED by Doxygen configuration!
9 
10 // -----------------------------------------------------------------------------
11 // Eliminierung von C-Builder-Spezialitäten
12 // -----------------------------------------------------------------------------
13 #define DELPHI_PACKAGE
14 #define __published public
15 #define __property property
16 #define __fastcall
17 #define extern
18 #define DECLSPEC_DRECORD
19 #define _ANNOT_ATTR_NC
20 
21 #define HIDESBASE
22 
23 #define DECLSPEC_DENUM
24 
25 #define _DELPHI_SET_CHAR
26 
27 
28 // -----------------------------------------------------------------------------
29 // replace C++ builder identifiers with their Delphi pendants:
30 // -----------------------------------------------------------------------------
31 #define UnicodeString String
32 #define Word WORD
33 
34 #endif
35 // =============================================================================
36 
Note
  • Put doxygen.h to somewhere Doxygen can find it!

Treat Delphi unit as a Doxygen module

Last it is convenient to have a dummy struct to gather local functions and procedures, cause Doxygen requires complete declarations for plain functions but not for member functions. Thus some Delphi statement look like C/C++ statement Doxygen interprets them out of the box. This concerns especially for unit Unitname; which Doxyen interprets as a variable Unitname of type unit; on the other hand Doxygen is able to evaluate configurated PREDEFINED macros. So one can replace unit with typedef struct {}. Effectively Doxygen replaces the Delphi unit statement by a C/C++ type statement:

somewhere in the Doxygen configuration file:
PREDEFINED += \
unit="typedef struct { }" \

And to take effect the Doxygen command \cond is moved after the unit statement:

//! @file
//! ...
unit example;
//! @addtogroup
//! @{
//! ...group description...
//! @cond
// ...Delphi directives...
...Delphi source code...
end;
//! @endcond
//! @}
Note
unit statement is moved to before \addtogroup since this type should not be part of the group because some documentation would be created twice!

Delphi unit structure: Summary

In summary the heading of Delphi modules should look like this, where DDTemplateUnit has to be replaced by the respective module name:

// =============================================================================
//! @file
//! @brief this is a Delphi source code template unit
//!
//! ...further Doxygen documentation for all entities in this Delphi unit...
//!
// =============================================================================
//! @brief DelphiDox template unit
unit DDTemplateUnit;
//! @addtogroup DDTemplateUnit-Group
//! @{
//! optional group definition
//!
//! Advised for units with only plain data (variables, functions, procedures).
//! May be omitted for units only declaring classes.
//! @cond
{$HPPEMIT '//! @file DDTemplateUnit.pas'} // causes the Delphi module file to be part of
// the Doxygen's files section documentation
{$HPPEMIT '//! @file'} // causes the .hpp file to be part of
// the Doxygen's files section documentation
{$HPPEMIT '#include "doxygen.h"'} // to replace C++Builder stuff as desired
interface
//...Delphi source code
implementation
//...Delphi source code
end.
//! @endcond
//! @}

Or use the file directly as your template: DDTemplateUnit.pas


Configuring Doxygen

All configuration and generation files should be located in the Doxygen build configuration directory of Delphi (create it manually or created automatically by Delphi on first compiling this build configuration).

In detail these are the files:

  • DDExample.dox : special Doxygen configuration as describe below.
  • doxygen.h : Additional header file, inserted to all Delphi generated .hpp files (s. Delphi module header); put it somewhere Doxygen can find it.
  • Doxygen.bat : Batch file to create the Doxygen documentation in post build phase (s. Automatically generate Doxygen documentation )
    Note
    Adjust the path to your Doxygen installation!
  • DDExample.bat : Display documentation

In the following all relevant Doxygen configurations are listed; they are summarized in files DDAliases.dox and DDPredefined.dox which can easily added to any Doxygen configuration file by adding the following lines to that configuration file (s. DDExample.dox ):

@INCLUDE_PATH = ../../DoxyGen/files
@INCLUDE = DDAliases.dox
@INCLUDE = DDPredefined.dox

Be aware that doxywizard.exe merges this file explicitly to the configuration and deletes the @INCLUDE_PATH and @INCLUDE lines! If you prefer this you can load DDExample.dox into doxywizard.exe and save it explicitly.

Following settings are based on the default settings (i.e. only changes on default settings are listed).

The configuration file from Example project can be found here: DDExample.dox


Required

The following configurations are required:

#-------------------------------------------------------------------------------
# DelphiDox.dox V.1.1
#
# This file should been imported into your Doxygen configuration file:
#
# @INCLUDE_PATH = ...path to this file...
# @INCLUDE = DDAliases.dox
#
# Be aware that doxywizard.exe merges include files explicitly and removes
# @INCLUDE_PATH / @INCLUDE directives afterwards!
#
# Alternatively it can be used directly preserving all other options to their
# default values
#-------------------------------------------------------------------------------
# Section identifiers for conditional documenting
# - DelphiDox --> DelphiDox is available
# - DDVER11 --> DelphiDox V.1.1
ENABLED_SECTIONS += DelphiDox DDVER11
# treat Delphi (.pas) files as C++:
EXTENSION_MAPPING += pas=C++
# ...and in case Delphi project (.dpr) file shall documented, too:
EXTENSION_MAPPING += dpr=C++
# Delphi uses ISO-8859-15 encoding!
INPUT_ENCODING = ISO-8859-15
# parse at least:
FILE_PATTERNS += *.pas *.hpp *.h
# to eliminate guard macros generated by Delphi from documentation:
EXCLUDE_SYMBOLS += *HPP
# Predefined Macros:
# - "DOXYGEN" for conditional compiling (#ifdef/#endif) in C-sources
# - to replace Delphi's reserved word "unit" with "typedef struct {}";
# and, since Delphi is case insensitive, in various spellings:
PREDEFINED += \
DOXYGEN \
unit="typedef struct { }" \
Unit="typedef struct { }" \
UNIT="typedef struct { }"
# ------------------------------------------------------------------------------
# and of course: the DelphiDox ALIASES
# ------------------------------------------------------------------------------
ALIASES += \

Project related configuration

To adjust Doxygen to your project as desired:

# project identification
PROJECT_NAME = ...as desired...
PROJECT_LOGO = ...as desired...
# ------------------------------------------------------------------------------
# Adjust as desired
# input files and directories:
INPUT += ...directory with Delphi generated .hpp files... \
...files and directories with Delphi source code...
# src directory & subdirectories!:
RECURSIVE = YES/NO as desired
# be sure that doxygen.h is covered by this settings(!):
INCLUDE_PATH += ...as desired...
# output directory
OUTPUT_DIRECTORY = ...as desired...
# to include Delphi declarations into the documentation:
EXAMPLE_PATH += ...path to *.pas files (same as INPUT without .hpp files)...
EXAMPLE_PATTERNS += ...as desired...
EXAMPLE_RECURSIVE = ...as desired...
# if you have dot installed; adjust path for your installation:
HAVE_DOT = YES
DOT_PATH = ...path to your graphviz installation...
DOT_MULTI_TARGETS = YES

Recommended

The following configurations are recommended:

# ------------------------------------------------------------------------------
# The following configuration are recommended:
# ------------------------------------------------------------------------------
# to exclude Delphi's __history and __recovery directories and files from being parsed:
EXCLUDE_PATTERNS = */__*/* \
*.~*~
# useful if Delphi sources complain with VCL (alle types are preceeded by "T"):
IGNORE_PREFIX = T
# for proper evaluation of doxygen.h
MACRO_EXPANSION = YES
# if Doxygen sorts the member docs some members my not be covered!
SORT_MEMBER_DOCS = NO
# since Delphi collects all .hpp files in a single directory, it's very difficult
# to prevent .hpp files not to be wanted from being documented (i.e. from external
# Delphi modules); so hide all undoced entities and don't warn on undocumented members
HIDE_UNDOC_CLASSES = YES
HIDE_UNDOC_MEMBERS = YES
HIDE_SCOPE_NAMES = YES
WARN_IF_UNDOCUMENTED = NO

Useful

The following configurations may also be usesful:

# ------------------------------------------------------------------------------
# The following configurations may also be useful:
# ------------------------------------------------------------------------------
# probably makes no sense setting this to YES:
VERBATIM_HEADERS = NO
# probably makes no sense cause source code isn't available
EXTRACT_PACKAGE = NO
INLINE_GROUPED_CLASSES = YES
INLINE_SIMPLE_STRUCTS = YES
TYPEDEF_HIDES_STRUCT = YES
EXTRACT_PRIVATE = YES
EXTRACT_PRIV_VIRTUAL = YES
EXTRACT_STATIC = YES
# all paths relative to upper (= Example) directory
STRIP_FROM_PATH = ../
# output options
GENERATE_TREEVIEW = YES
HTML_TIMESTAMP = YES
HTML_DYNAMIC_SECTIONS = YES
# if there are only few entries the index looks very poor with more than on column
COLS_IN_ALPHA_INDEX = 1
# group name with an anchor for referencing:
# note that the anchor is placed behind \name tag, regardless it is noted before!
ALIASES += "Name{2}=\anchor \1 ^^ \name \2" \
"Name{1}=\Name{\1,\1} "