]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
docs: Add paragraph about circular includes to CODING_STYLE.md
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sat, 19 Apr 2025 08:11:12 +0000 (10:11 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sat, 19 Apr 2025 09:51:07 +0000 (11:51 +0200)
docs/CODING_STYLE.md

index b8b420c1423c77c3e19f83dc8d2a04ee578c6559..2b8cf694208cea80ef26db4b13d8480bdccd54be 100644 (file)
@@ -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