[dpdk-dev] tools brainstorming

Butler, Siobhan A siobhan.a.butler at intel.com
Wed Apr 8 12:43:53 CEST 2015


Hi all,
To add to the tools brainstorming - I propose we use the following Coding Standards as the basis of guidelines on coding style going forward.
The style outlined below is in alignment with the current convention used for the majority of the project.
Any thoughts/suggestions or feedback welcome.
Thanks
Siobhan :)
<siobhan.a.butler at intel.com>



Coding Style
~~~~~~~~~~

Description
-----------

This document specifies the preferred style for source files in the DPDK source tree. 
It is based on the Linux Kernel coding guidelines and the FreeBSD 7.2 Kernel Developer's Manual (see man style(9)), 
but was heavily modified for the needs of the DPDK. Many of the style rules are implicit in the examples. 
Be careful to check the examples before assuming that style is silent on an issue. 

General Guidelines
------------------

The rules and guidelines given in this document cannot cover every situation, so the following general guidelines should be used as a fallback: 
The code style should be consistent within each individual file, and within each file in a given directory or module - in the case of creating new files 
The primary reason for coding standards is to increase code readability and comprehensibility, therefore always use whatever option will make the code easiest to read. 

The following more specific recommendations apply to all sections, both for C and assembly code: 
Line length is recommended to be not more than 80 characters, including comments. [Tab stop size should be assumed to be at least 4-characters wide] 
Indentation should be to no more than 3 levels deep. 
NOTE The above are recommendations, and not hard limits. However, it is expected that the recommendations should be followed in all but the rarest situations. 
C Comment Style

Usual Comments
--------------

These comments should be used in normal cases. To document a public API, a doxygen-like format must be used: refer to Doxygen Documentation. 
 /*
  * VERY important single-line comments look like this.
  */
 
 /* Most single-line comments look like this. */
 
 /*
  * Multi-line comments look like this.  Make them real sentences. Fill
  * them so they look like real paragraphs.
  */

License Header
--------------

Each file should begin with a special comment tag which will contain the appropriate copyright and license for the file (Generally BSD License). 
After any copyright header, a blank line should be left before any other contents, e.g. include statements in a C file. 

C Preprocessor Directives
-------------------------

Header Includes

In DPDK sources, the include files should be ordered as following: 
 libc includes (system includes first) 
 DPDK EAL includes 
 DPDK misc libraries includes 
 application-specific includes 

Example: 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <rte_eal.h>
 
 #include <rte_ring.h>
 #include <rte_mempool.h>
 
 #include "application.h"


Global pathnames are defined in <paths.h>. Pathnames local to the program go in "pathnames.h" in the local directory. 
 #include <paths.h>


Leave another blank line before the user include files. 
 #include "pathnames.h"         /* Local includes in double quotes. */

NOTE Please avoid, as much as possible, including headers from other headers file. Doing so should be properly explained and justified. 
Headers should be protected against multiple inclusion with the usual: 
 #ifndef _FILE_H_
 #define _FILE_H_
 
 /* Code */
 
 #endif /* _FILE_H_ */


Macros

Do not ``#define`` or declare names in the implementation namespace except for implementing application interfaces. 

The names of ``unsafe`` macros (ones that have side effects), and the names of macros for manifest constants, are all in uppercase. 

The expansions of expression-like macros are either a single token or have outer parentheses. If a macro is an inline expansion of a function, 
the function name is all in lowercase and the macro has the same name all in uppercase. Right-justify the backslashes; 
it makes it easier to read. If the macro encapsulates a compound statement, enclose it in a do loop, so that it can be used safely in if statements. 
Any final statement-terminating semicolon should be supplied by the macro invocation rather than the macro, to make parsing easier for pretty-printers and editors. 
 #define MACRO(x, y) do {                                        \
         variable = (x) + (y);                                   \
         (y) += 2;                                               \
 }while (0)

NOTE Wherever possible, enums and typedefs should be preferred to macros, since they provide additional degrees 
of type-safety and can allow compilers to emit extra warnings about unsafe code. 

Conditional Compilation
-----------------------

When code is conditionally compiled using #ifdef or #if, a comment may be added following the matching #endif or #else to 
permit the reader to easily discern where conditionally compiled code regions end. This comment should be used only for 
(subjectively) long regions, regions greater than 20 lines, or where a series of nested #ifdef 's may be confusing to the reader. 
Exceptions may be made for cases where code is conditionally not compiled for the purposes of lint(1), even though the uncompiled 
region may be small. The comment should be separated from the #endif or #else by a single space. For short conditionally compiled regions, 
a closing comment should not be used. 

The comment for #endif should match the expression used in the corresponding #if or #ifdef. The comment for #else and #elif 
should match the inverse of the expression(s) used in the preceding #if and/or #elif statements. In the comments, 
the subexpression defined(FOO) is abbreviated as FOO. For the purposes of comments, #ifndef FOO is treated as #if !defined(FOO). 
 #ifdef KTRACE
 #include <sys/ktrace.h>
 #endif
 
 #ifdef COMPAT_43
 /* A large region here, or other conditional code. */
 #else /* !COMPAT_43 */
 /* Or here. */
 #endif /* COMPAT_43 */
 
 #ifndef COMPAT_43
 /* Yet another large region here, or other conditional code. */
 #else /* COMPAT_43 */
 /* Or here. */
 #endif /* !COMPAT_43 */

NOTE Conditional compilation should be used only when absolutely necessary, as it increases the number of target binaries that need to be built and tested. 
C Types

Integers

For fixed/minimum-size integer values, the project uses the form uintXX_t (from stdint.h) instead of older BSD-style integer identifiers of the form u_intXX_t. 

Enumerations
------------

Enumeration values are all uppercase. 
 enum enumtype { ONE, TWO } et;


Bitfields
---------

The developer should group bitfields that are included in the same integer, as follows: 
 struct grehdr {
   uint16_t rec:3,
       srr:1,
       seq:1,
       key:1,
       routing:1,
       csum:1,
       version:3,
       reserved:4,
       ack:1;
 /* ... */
 }


Variable Declarations
---------------------

In declarations, do not put any whitespace between asterisks and adjacent tokens, except for tokens that are identifiers related to types. 
(These identifiers are the names of basic types, type qualifiers, and typedef-names other than the one being declared.) 
Separate these identifiers from asterisks using a single space. 

Structure Declarations

When declaring variables in structures, declare them sorted by use, then by size (largest to smallest), and then in alphabetical order. 
Alignment constraints may override the previous rules. The first category normally does not apply, but there are exceptions. 
Each structure element gets its own line. Try to make the structure readable by aligning the member names using spaces as shown below. 
Names following extremely long types, which therefore cannot be easily aligned with the rest, should be separated by a single space. 
 struct foo {
         struct foo      *next;          /* List of active foo. */
         struct mumble   amumble;        /* Comment for mumble. */
         int             bar;            /* Try to align the comments. */
         struct verylongtypename *baz;   /* Won't fit with other members */
 };


Major structures should be declared at the top of the file in which they are used, or in separate header files if they are used 
in multiple source files. Use of the structures should be by separate declarations and should be extern if they are declared in a header file. 

Queues

Use queue(3) macros rather than rolling your own lists, whenever possible. Thus, the previous example would be better written: 
 #include <sys/queue.h>
 
 struct foo {
         LIST_ENTRY(foo) link;      /* Use queue macros for foo lists. */
         struct mumble   amumble;   /* Comment for mumble. */
         int             bar;       /* Try to align the comments. */
         struct verylongtypename *baz;   /* Won't fit with other members */
 };
 LIST_HEAD(, foo) foohead;          /* Head of global foo list. */


DPDK also provides an optimized way to store elements in lockless rings. This should be used in all data-path code, when there are several 
consumer and/or producers to avoid locking for concurrent access. 

Typedefs

Avoid using typedefs for structure types. For example, use: 
 struct my_struct_type {
 /* ... */
 };
 
 struct my_struct_type my_var;


rather than: 
 typedef struct my_struct_type {
 /* ... */
 } my_struct_type;
 
 my_struct_type my_var


Typedefs are problematic because they do not properly hide their underlying type; for example, you need to know if the typedef is 
the structure itself, as shown above, or a pointer to the structure. In addition, they must be declared exactly once, whereas an 
incomplete structure type can be mentioned as many times as necessary. Typedefs are difficult to use in stand-alone header files. 
The header that defines the typedef must be included before the header that uses it, or by the header that uses it (which causes namespace pollution), 
or there must be a back-door mechanism for obtaining the typedef. 
NOTE #defines used instead of typedefs also are problematic (since they do not propagate the pointer type correctly due to direct text replacement). 
For example, ``#define pint int *`` does not work as expected, while ``typedef int *pint`` does work. As stated when discussing macros, typedefs 
should be preferred to macros in cases like this. 
When convention requires a typedef; make its name match the struct tag. Avoid typedefs ending in ``_t``, except as specified in Standard C or by POSIX. 
 /* Make the structure name match the typedef. */
 typedef struct bar {
         int     level;
 } BAR;
 typedef int             foo;            /* This is foo. */
 typedef const long      baz;            /* This is baz. */


C Function Definition, Declaration and Use

Prototypes

It is recommended, but not required that all functions are prototyped somewhere. 

Any function prototypes for private functions (that is, functions not used elsewhere) go at the top of the first source module. Functions 
local to one source module should be declared static. 

Functions used from other parts of code (external API) must be prototyped in the relevant include file. 
Function prototypes should be listed in a logical order, preferably alphabetical unless there is a compelling reason to use a different ordering. 

Functions that are used locally in more than one module go into a separate header file, for example, "extern.h". 

Do not use the ``__P`` macro. 

Functions that are part of an external API should be documented using Doxygen-like comments above declarations. See the Doxgen documentation topic for details. 

Associate names with parameter types, for example: 
 void function(int fd);


Short function prototypes should be contained on a single line. Longer prototypes, e.g. those with many parameters, 
can be split across multiple lines. Multi-line prototypes should use space-indentation to enable function parameters to line up: 
 static char *function1(int _arg, const char *_arg2, 
                      struct foo *_arg3,
                      struct bar *_arg4,
                      struct baz *_arg5);
 static void usage(void);


Definitions
-----------

The function type should be on a line by itself preceding the function. The opening brace of the function body should be on a line by itself. 
 static char *
 function(int a1, int a2, float fl, int a4)
 {


Do not declare functions inside other functions. ANSI C states that such declarations have file scope regardless of the nesting of the declaration. 
Hiding file declarations in what appears to be a local scope is undesirable and will elicit complaints from a good compiler. 

Old-style (K&R) function declaration should not be used, use ANSI function declarations instead as shown below. Long argument lists 
should be wrapped as described above in the function prototypes section. 
 /*
  * All major routines should have a comment briefly describing what
  * they do. The comment before the "main" routine should describe
  * what the program does.
  */
 int
 main(int argc, char *argv[])
 {
         char *ep;
         long num;
         int ch;


C Command Line Parsing
----------------------

For consistency, getopt(3) should be used to parse options. Options should be sorted in the getopt(3) call and the switch statement, 
unless parts of the switch cascade. Elements in a switch statement that cascade should have a FALLTHROUGH comment. 
Numerical arguments should be checked for accuracy. Code that cannot be reached should have a NOTREACHED comment. 
 while ((ch = getopt(argc, argv, "abNn:")) != -1)
         switch (ch) {         /* Indent the switch. */
         case 'a':             /* Don't indent the case. */
                 aflag = 1;    /* Indent case body one tab. */
                 /* FALLTHROUGH */
         case 'b':
                 bflag = 1;
                 break;
         case 'N':
                 Nflag = 1;
                 break;
         case 'n':
                 num = strtol(optarg, &ep, 10);
                 if (num <= 0 || *ep != '\0') {
                         warnx("illegal number, -n argument -- %s",
                               optarg);
                         usage();
                 }
                 break;
         case '?':
         default:
                 usage();
                 /* NOTREACHED */
         }
 argc -= optind;
 argv += optind;





C Indentation
-------------

Control Statements and Loops

Include a space after keywords (if, while, for, return, switch). Do not use braces (``{`` and ``}``) for control statements with zero or just a 
single statement, unless that statement is more than a single line in which case the braces are permitted. Forever loops are done with for statements, not while statements. 
 for (p = buf; *p != '\0'; ++p)
         ;       /* nothing */
 for (;;)
         stmt;
 for (;;) {
         z = a + really + long + statement + that + needs +
                 two + lines + gets + indented + on + the + 
                 second + and + subsequent + lines;
 }
 for (;;) {
         if (cond)
                 stmt;
 }
 if (val != NULL)
         val = realloc(val, newsize);


Parts of a for loop may be left empty. It is recommended that you do not put declarations inside blocks unless the routine is unusually complicated. 
 for (; cnt < 15; cnt++) {
         stmt1;
         stmt2;
 }


Indentation is a hard tab, that is, a tab character, not a sequence of spaces. 
NOTE General rule in DPDK, use tabs for indentation, spaces for alignment. 
If you have to wrap a long statement, put the operator at the end of the line, and indent again. For control statements (if, while, etc.), 
it is recommended that the next line be indented by two tabs, rather than one, to prevent confusion as to whether the second line of the 
control statement forms part of the statement body or not. For non-control statements, this issue does not apply, so they can be indented 
by a single tab. However, a two-tab indent is recommended in this case also to keep consistency across all statement types. 
 while (really_long_variable_name_1 == really_long_variable_name_2 &&
     var3 == var4){
     x = y + z;      /* control stmt body lines up with second line of */
     a = b + c;      /* control statement itself if single indent used */
 }
 
 if (really_long_variable_name_1 == really_long_variable_name_2 &&
         var3 == var4){  /* two tabs used */
     x = y + z;          /* statement body no longer lines up */
     a = b + c;
 }
 
 z = a + really + long + statement + that + needs +
         two + lines + gets + indented + on + the + 
         second + and + subsequent + lines;


Do not add whitespace at the end of a line. 

Closing and opening braces go on the same line as the else keyword. Braces that are not necessary should be left out. 
 if (test)
         stmt;
 else if (bar) {
         stmt;
         stmt;
 } else
         stmt;


Function Calls
--------------

Do not use spaces after function names. Commas should have a space after them. No spaces after ``(`` or ``[`` or preceding the ``]`` or ``)`` characters. 
 error = function(a1, a2);
 if (error != 0)
         exit(error);


Operators
---------

Unary operators do not require spaces, binary operators do. Do not use parentheses unless they are required for precedence or unless the 
statement is confusing without them. Remember that other people may be more easily confused than you. 

Exit

Exits should be 0 on success, or 1 on failure. 
         exit(0);        /*
                          * Avoid obvious comments such as
                          * "Exit 0 on success."
                          */
 }


Local Variables
---------------

When declaring variables in functions, declare them sorted by size, then in alphabetical order. Multiple variables per line are OK. 
If a line overflows reuse the type keyword. 

Be careful to not obfuscate the code by initializing variables in the declarations, only the last variable on a line should be initialized. 
If multiple variables are to be initialised when defined, put one per line. Do not use function calls in initializers. 
 int i = 0, j = 0, k = 0;  /* bad, too many initializer */
 
 char a = 0;        /* OK, one variable per line with initializer */
 char b = 0;
 
 float x, y = 0.0;  /* OK, only last variable has initializer */


Casts and sizeof

Casts and sizeof statements are not followed by a space. Always write sizeof statements with parenthesis. 
The redundant parenthesis rules do not apply to sizeof(var) instances. 

C Style and Conventions

NULL Pointers

NULL is the preferred null pointer constant. Use NULL instead of ``(type *)0`` or ``(type *)NULL`` in contexts where the compiler knows the type, 
for example, in assignments. Use ``(type *)NULL`` in other contexts, in particular for all function args. 
(Casting is essential for variadic args and is necessary for other args if the function prototype might not be in scope.) Test pointers against NULL, for example, use:: 
 (p = f()) == NULL


not:: 
 !(p = f())


Do not use ! for tests unless it is a boolean, for example, use:: 
 if (*p == '\0')


not:: 
 if (!*p)


Return Value
------------

If possible, functions should return 0 on success and a negative value on error. The negative value should be ``-errno`` if relevant, for example, ``-EINVAL``. 

Routines returning ``void *`` should not have their return values cast to any pointer type. 
(Typecasting can prevent the compiler from warning about missing prototypes as any implicit definition of a function returns int - which, unlike "void *" needs a typecast to assign to a pointer variable.) 
NOTE The above rule applies to malloc, as well as to DPDK functions. 
Values in return statements should be enclosed in parentheses. 

Logging and Errors
------------------

In the DPDK environment, use the logging interface provided:: 
 #define RTE_LOGTYPE_TESTAPP1 RTE_LOGTYPE_USER1
 #define RTE_LOGTYPE_TESTAPP2 RTE_LOGTYPE_USER2
 
 /* enable these logs type */
 rte_set_log_type(RTE_LOGTYPE_TESTAPP1, 1);
 rte_set_log_type(RTE_LOGTYPE_TESTAPP2, 1);
 
 /* log in debug level */
 rte_set_log_level(RTE_LOG_DEBUG);
 RTE_LOG(DEBUG, TESTAPP1, "this is is a debug level message\n");
 RTE_LOG(INFO, TESTAPP1, "this is is a info level message\n");
 RTE_LOG(WARNING, TESTAPP1, "this is is a warning level message\n");
 
 /* log in info level */
 rte_set_log_level(RTE_LOG_INFO);
 RTE_LOG(DEBUG, TESTAPP2, "debug level message (not displayed)\n");


In a userland program that is not a DPDK application, use err(3) or warn(3). Do not create your own variant. 
         if ((four = malloc(sizeof(struct foo))) == NULL)
                 err(1, (char *)NULL);
         if ((six = (int *)overflow()) == NULL)
                 errx(1, "number overflowed");
         return (eight);
 }


Variable Arguments List
-----------------------

Variable numbers of arguments should look like this: 
 #include <stdarg.h>
 
 void
 vaf(const char *fmt, ...)
 {
         va_list ap;
 
         va_start(ap, fmt);
         STUFF;
         va_end(ap);
         /* No return needed for void functions. */
 }
 
 static void
 usage()
 {
         /* Insert an empty line if the function has no local variables. */


Printf
------

Use printf(3), not fputs(3), puts(3), putchar(3) or whatever. It is faster and usually cleaner, and helps to avoid unnecessary bugs. However, be aware of format string bugs:: 
 int
 main(int argc, char **argv)
 {
         if(argc != 2)
             exit(1);
         printf(argv[1]); /* bad ! */
         printf("%s", argv[1]); /* correct */


Usage
-----

Usage statements should look like the manual pages SYNOPSIS. The usage statement should be structured in the following order: 
1. Options without operands come first, in alphabetical order, inside a single set of brackets (``[`` and ``]``). 
2. Options with operands come next, also in alphabetical order, with each option and its argument inside its own pair of brackets. 
3. Required arguments (if any) are next, listed in the order they should be specified on the command line. 
4. Finally, any optional arguments, listed in the order they should be specified, and all inside brackets. 

A bar (`|') separates ``either-or`` options/arguments, and multiple options/arguments, which are specified together, are placed in a single set of brackets. 
 "usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n"
 "usage: f [-a | -b] [-c [-dEe] [-n number]]\n"
 
 (void)fprintf(stderr, "usage: f [-ab]\n");
         exit(1);
 }


Note that the manual page options description should list the options in pure alphabetical order. That is, without regard to 
whether an option takes arguments or not. The alphabetical ordering should take into account the case ordering shown above. 

Branch Prediction
-----------------

When a test is done in a critical zone (called often or in a data path) use the ``likely()`` and ``unlikely()`` macros. They are expanded 
as a compiler builtin and allow the developer to indicate if the branch is likely to be taken or not. Example: 
 #include <rte_branch_prediction.h>
 if (likely(x > 1))
   do_stuff();


Static Variables and Functions
------------------------------

All functions and variables that are local to a file must be declared as ``static`` because it can often help the compiler to do 
some optimizations (such as, inlining the code). 

Functions that must be inlined have to be declared as ``static inline`` and can be defined in a .c or a .h file. 

Const Attribute
---------------

Particular care must be taken with the use of the ``const`` attribute. It should be used as often as possible when a variable is read-only. 

ASM Coding Rules
----------------

Assembly Syntax

NASM is used for assembly, with the syntax, therefore guidelines given here are appropriate to this target. 
[GNU as is intended to support both syntax variants, but that is not documented here]. The following general guidelines are valid in any case. 
 globals, extern and macros are to be defined at the top of the file 
 labels should stay explicit, and are left aligned 
 code is indented with a tabulation, no spaces 
 instruction and operands should be separated by a tab too 
 code should be separated in blocks 
 blocks, when possible, should start with a comment explanation 

Sample code: 
 ; comment header
 
 ; export this symbol
 [GLOBAL entry]
 
 ; external variables and functions
 [EXTERN variable]
 
 ; 16 bits code
 [BITS 16]
 
 ; macros like
 BIOS_START  EQU     0x7C00
 
 entry:
 
       ; Clear interrupt flag
       cli
 
       ; Set segment registers to 0
       xor     bx, bx
       mov     es, bx
       mov     fs, bx
       mov     gs, bx
       mov     ds, bx
       mov     ss, bx
       mov     sp, 0x7C00
       sti
 
;; [...] snip [...]


Use of C-style macros is allowed. When compiling ASM code, a file is parsed by the C preprocessor. It is then allowed to share some constants between C and assembly code, in a ``.h`` file. 

Inline ASM in C code

The ``asm`` and ``volatile`` keywords do not have underscores. The AT&T syntax should be used. Input and output operands should be named to avoid confusion, 
as shown in the following example:: 
 asm volatile("outb %[val], %[port]"
 : :
 [port] "dN" (port),
 [val] "a" (val));


Environment or Architecture-specific Sources

In DPDK and DPDK applications, some code is specific to an architecture (i686, x86_64) or to an executive environment (bare-metal or linuxapp) and so on. 

There are several ways to handle specific code: 
 Use a ``#ifdef`` with the CONFIG option in the C code. This can be done when the differences are small and they can be embedded in the same C file:: 
   #ifdef RTE_ARCH_I686
   toto();
   #else
   titi();
   #endif

Use the CONFIG option in the Makefile. This is done when the differences are more significant. In this case, the code is split into
two separate files that are architecture or environment specific. 

The same logic applies to header files. 

By convention, a file is common if it is not located in a directory indicating that it is specific. For instance, a file located in a 
subdir of "x86_64" directory is specific to this architecture. A file located in a subdir of "linuxapp" is specific to this execution environment. 
NOTE As in the linux kernel, the "CONFIG_" prefix is not used in C code. This is only needed in Makefiles or shell scripts. 
Per Architecture Sources

The following config options can be used: 
 CONFIG_RTE_ARCH is a string that contains the name of the architecture. 
 CONFIG_RTE_ARCH_I686, CONFIG_RTE_ARCH_X86_64 or CONFIG_RTE_ARCH_X86_64_32 are defined only if we are building for those architectures. 

Per Execution Environment Sources

The following config options can be used: 
 CONFIG_RTE_EXEC_ENV is a string that contains the name of the executive environment. 
 CONFIG_RTE_EXEC_ENV_BAREMETAL or CONFIG_RTE_EXEC_ENV_LINUXAPP are defined only if we are building for this execution environment. 

Per Driver Sources
 RTE_LIBRTE_IGB_PMD or RTE_LIBRTE_IXGBE_PMD are defined only if we are using this driver. 

Doxygen Documentation
---------------------

The API documentation is automatically generated in the DPDK framework. That is why all files that are part of the public 
API must be documented using Doxygen syntax. 

The public API comprises functions of DPDK that can be used by an external application that will use the SDK. Only the Doxygen 
syntax described in the coding rules (this document) should be used in the code. All the Doxygen features are described in the Doxygen manual online. 

Documenting a Function

All public functions must be documented. The documentation is placed in the header file, above the declaration of the function. 
The definition of the function may be documented, but using standard comments (not in doxygen format). 
Private functions can be documented using Doxygen. The following is an example of function documentation: 
 /**
  * Summary here; one sentence on one line (should not exceed 80 chars).
  *
  * A more detailed description goes here.
  *
  * A blank line forms a paragraph. There should be no trailing white-space
  * anywhere.
  *
  * @param first
  *   "@param" is a Doxygen directive to describe a function parameter. Like
  *   some other directives, it takes a term/summary on the same line and a
  *   description (this text) indented by 2 spaces on the next line. All
  *   descriptive text should wrap at 80 chars, without going over.
  *   Newlines are NOT supported within directives; if a newline would be
  *   before this text, it would be appended to the general description above.
  * @param second
  *   There should be no newline between multiple directives (of the same
  *   type).
  *
  * @return
  *   "@return" is a different Doxygen directive to describe the return value
  *   of a function, if there is any.
  */
 int rte_foo(int first, int second)


Documenting Files

Each public file may start with a comment describing what the file does. For example: 
 /**
  * @file
  * This file describes the coding rules of RTE.
  *
  * It contains the coding rules of C code, ASM code, reStructured
  * Text documentation, and of course how to use doxygen to document
  * public API.
  */


Documenting Constants and Variables
 /**
  * The definition of a funny TRUE.
  */
 #define TRUE 0




 #define TRUE 1 /**< another way to document a macro */

 /**
  * Frequency of the HPET counter in Hz
  *
  * @see rte_eal_hpet_init()
  */
 extern uint64_t eal_hpet_resolution_hz;


Documenting Structures

Public structures should also be documented. The ``/**<`` sequence can be used to documented the fields of the structure, as shown in the following example: 
 /**
  * Structure describing a memzone, which is a contiguous portions of
  * physical memory identified by a name.
  */
 struct rte_memzone {
 
 #define MEMZONE_NAMESIZE 32
   char name[MEMZONE_NAMESIZE]; /**< name of the memory zone */
 
   phys_addr_t phys_addr;       /**< start physical address */
   void *addr;                  /**< start virtual address */
   uint64_t len;                /**< len of the memzone */
 
   int socket_id;               /**< NUMA socket id */
 };


Using Lists

Using the minus character, it is possible to generate a bullet list. The minus signs must be column-aligned. If the minus sign is followed by a hash, 
then it generates an enumerated list. Refer to the official Doxygen documentation for more information. 
 /**
  *  A list of events:
  *    - mouse events
  *         -# mouse move event
  *         -# mouse click event\n
  *            More info about the click event.
  *         -# mouse double click event
  *    - keyboard events
  *         -# key down event
  *         -# key up event
  *
  *  More text here.
  */


See Also Sections

The @see keyword can be used to highlight a link to an existing function, file, or URL. This directive should be placed on one line, without anything else, at the bottom of the documentation header. 
 /**
  * (documentation of function, file, ...)
  *
  * @see rte_foo()
  * @see eal_memzone.c
  */
 


More information about the dev mailing list