[Swan-dev] style discussion: structure of .c files
Andrew Cagney
andrew.cagney at gmail.com
Mon Apr 23 16:56:05 UTC 2018
Are you talking about a program or a library?
In general terms:
- monolithic headers end up being a dumping ground for all sorts of
junk (what libreswan.h sucks in is scary!)
- (I argue) their indirect dependencies make long term maintenance
hard; its easier to eliminate direct dependencies
For programs:
- the large program pluto already has a required header - "defs.h"
- all the other programs are small (single .c files?) so really have
no need for a monolithic header - they can instead explicitly include
their direct dependencies
For libraries:
- is a monolithic header even helpful? shunk.c, for instance, has no
reason to include anything beyond:
#include <string.h>
#include "shunk.h"
- lswlog_realtime.c, is similar, either it requires:
#include <stdbool.h> /* for bool type used in code */
#include "realtime.h"
#include "lswlog.h"
or even ("realtime.h" should have included <stdbool.h>) just:
#include "realtime.h"
#include "lswlog.h"
"libreswan.h" is the last thing it needs - the file doesn't even use
TRUE/FALSE or true/false! - yet now it sucks it in.
So rather than trying to inflict a monolithic mess on libraries, try
the following guidelines:
-- include headers should be wrapped in #ifndef HEADER_H et.al.
wrapper (not __HEADER as a leading underscore is reserved by C?)
-- include headers should directly include their direct dependencies;
and per common and existing convention, first the system includes
using <> and the local includes using ""
For instance, a header using "monotime_t" as a value parameter,
structure field, or return type, should directly include "monotime.h";
ditto for "size_t" and <stddef.h>, 'bool' and <stdbool.h>, and
'uint32_t' and <stdint.h>, ...
However, a struct reference isn't a direct dependency. For instance
'struct lswlog *', just requires the declaration 'struct lswlog;'.
-- for new pass-by-value objects, try to declare them as 'typedef
struct [<object>?] { ..., } <object>_t and put them in "object".h
It makes it easier to find; and easier to directly include. I moved
chunk_t to its own header because I could never find it; and an
unexpected but good consequence is that it allowed the removal of some
redundant includes.
-- library .c files should only need to include their direct
dependencies, and per-convention system headers then local headers ...
Finally, these rules aren't a "must". Instead, when something breaks,
or is being re-organized, just use them as a guideline for how to
clean up the existing code.
Andrew
On 22 April 2018 at 17:40, D. Hugh Redelmeier <hugh at mimosa.com> wrote:
> This is meant as a conversation starter. Thoughts?
>
> 0. First line: a succinct description of the file
>
> 1. License bumpf
>
> 2. any things mandated by standards to be first
>
> Unlikely example:
> #define _POSIX_C_SOURCE 199506L
> See
> <https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html>
>
> Real example:
> #include <pthread.h>
>
> 3. #includes for headers supplied by the system.
> Don't include system headers that are included by baseline header.
> Generally these can be in any order so put them in a nice order.
> Some OS-specific headers have ordering constraints.
> By including these system headers before our project
> headers, we reduce the chance of interference
>
> 4. #include the appropriate baseline header
>
> 5. #include any additional project headers
>
> 6. the rest of the file in a nice order
>
> An exception can always be made where it makes things simpler or clearer.
>
> Examples: A chunk of code is conditionally compiled, and a header file
> is only needed for that chunk of code, it makes sense to put the
> #include within that conditional.
>
>
> What should be in the baseline header? Definitions that are pervasive
> through the code for which the baseline applies.
> - stddef.h, stdint.h, inttypes.h, stdbool.h, stdlib.h?, string.h,
> limits.h?
> - IETF-defined constants
> - project-pervasive declarations (some of our library routines)
>
> There may well have to be different baseline headers for different
> contexts:
>
> - kernel code and code that interfaces with it (they need to share
> definitions)
> linux/include/libreswan.h?
>
> - userland library code (i.e. the portable code that Henry design).
> It is designed to not depend on anything about libreswan.
>
> - userland library code that knows something about libreswan but isn't
> only used inside pluto. This is tricky because it shares some
> interfaces (logging) but not all with pluto. Several different
> programs can use it
>
> - pluto code
>
> - userland code that has a close relationship with pluto (whack)
>
> - userland non-pluto programs
> include/lswtools.h? Maybe not.
>
> Some existing project headers that perhaps should be available pervasively:
> linux/include/libreswan.h?
> include/constants.h
> include/puluto-constands.h
> include/chunk.h
> include/shunk.h
> include/deltatime.h
> include/monotime.h
> include/realtime.h
> include/lswalloc.h
>
> Related conventions:
>
> For system headers: #include <>
> For project headers: #inlcude ""
>
> As much as is reasonable, every .c file that exports some definitions
> must have a corresponding .h file (with the same basename) that
> declares those definitions.
> _______________________________________________
> Swan-dev mailing list
> Swan-dev at lists.libreswan.org
> https://lists.libreswan.org/mailman/listinfo/swan-dev
More information about the Swan-dev
mailing list