From c7e42c2705c71ff50d156e58583149d0a70ca398 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sat, 19 Apr 2025 10:11:12 +0200 Subject: [PATCH] docs: Add paragraph about circular includes to CODING_STYLE.md --- docs/CODING_STYLE.md | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md index b8b420c1423..2b8cf694208 100644 --- a/docs/CODING_STYLE.md +++ b/docs/CODING_STYLE.md @@ -234,6 +234,74 @@ SPDX-License-Identifier: LGPL-2.1-or-later const char *input); ``` +- Please do not introduce new circular dependencies between header files. + Effectively this means that if a.h includes b.h, then b.h cannot include a.h, + directly or transitively via another header. Circular header dependencies can + make for extremely confusing errors when modifying the headers, which can be + easily avoided by getting rid of the circular dependency. To get rid of a + circular header dependency, there are a few possible techniques: + - Introduce a new common header with the declarations that need to be shared + by both headers and include only this header in the other headers. + - Move declarations around between the two headers so one header doesn't need + to include the other header anymore. + - Use forward declarations if possible to remove the need for one header to + include the other. To make this possible, you can move the body of static + inline functions that require the full definition of a struct into the + implementation file so that only a forward declaration of the struct is + required and not the full definition. + + Bad: + + ```c + // manager.h + + typedef struct Manager Manager; + + #include "unit.h" + + struct Manager { + Unit *unit; + }; + + // unit.h + + typedef struct Unit Unit; + + #include "manager.h" + + struct Unit { + Manager *manager; + }; + ``` + + Good: + + ```c + // manager.h + + typedef struct Unit Unit; + + typedef struct Manager { + Unit *unit; + } Manager; + + // manager.c + + #include "unit.h" + + // unit.h + + typedef struct Manager Manager; + + typedef struct Unit { + Manager *manager; + } Unit; + + // unit.c + + #include "manager.h" + ``` + - The order in which header files are included doesn't matter too much. systemd-internal headers must not rely on an include order, so it is safe to include them in any order possible. However, to not clutter global -- 2.47.3