@@ -234,6 +234,116 @@ SPDX-License-Identifier: LGPL-2.1-or-later
234234 const char *input);
235235 ```
236236
237+ - Please do not introduce new circular dependencies between header files.
238+ Effectively this means that if a.h includes b.h, then b.h cannot include a.h,
239+ directly or transitively via another header. Circular header dependencies can
240+ make for extremely confusing errors when modifying the headers, which can be
241+ easily avoided by getting rid of the circular dependency. To get rid of a
242+ circular header dependency, there are a few possible techniques:
243+ - Introduce a new common header with the declarations that need to be shared
244+ by both headers and include only this header in the other headers.
245+ - Move declarations around between the two headers so one header doesn't need
246+ to include the other header anymore.
247+ - Use forward declarations if possible to remove the need for one header to
248+ include the other. To make this possible, you can move the body of static
249+ inline functions that require the full definition of a struct into the
250+ implementation file so that only a forward declaration of the struct is
251+ required and not the full definition.
252+
253+ Bad:
254+
255+ ```c
256+ // manager.h
257+
258+ typedef struct Manager Manager;
259+
260+ #include "unit.h"
261+
262+ struct Manager {
263+ Unit *unit;
264+ };
265+
266+ // unit.h
267+
268+ typedef struct Unit Unit;
269+
270+ #include "manager.h"
271+
272+ struct Unit {
273+ Manager *manager;
274+ };
275+ ```
276+
277+ Good:
278+
279+ ``` c
280+ // manager.h
281+
282+ typedef struct Unit Unit;
283+
284+ typedef struct Manager {
285+ Unit *unit;
286+ } Manager;
287+
288+ // manager.c
289+
290+ #include "unit.h"
291+
292+ // unit.h
293+
294+ typedef struct Manager Manager;
295+
296+ typedef struct Unit {
297+ Manager * manager;
298+ } Unit;
299+
300+ // unit.c
301+
302+ #include "manager.h"
303+ ```
304+
305+ - Please keep header files as lean as possible. Prefer implementing functions in
306+ the implementation (.c) file over implementing them in the corresponding
307+ header file. Inline functions in the header are allowed if they are just a few
308+ lines and don't require including any extra header files that would otherwise
309+ not have to be included. Similarly, prefer forward declarations of structs
310+ over including the corresponding header file. Keeping header files as lean as
311+ possible speeds up incremental builds when header files are changed (either by
312+ yourself when working on a pull request or as part of rebasing onto the main
313+ branch) as each file that (transitively) includes a header that was changed
314+ needs to be recompiled. By keeping the number of header files included by
315+ other header files low, we reduce the impact of modifying header files on
316+ incremental builds as much as possible.
317+
318+ Bad:
319+
320+ ```c
321+ // source.h
322+
323+ #include "log.h"
324+
325+ static inline void my_function_that_logs(void) {
326+ log_error("oops");
327+ }
328+ ```
329+
330+ Good:
331+
332+ ``` c
333+ // source.h
334+
335+ void my_function_that_logs (void);
336+
337+ // source.c
338+
339+ #include "header.h"
340+ #include "log.h"
341+
342+ void my_function_that_logs(void) {
343+ log_error("oops");
344+ }
345+ ```
346+
237347- The order in which header files are included doesn't matter too
238348 much. systemd-internal headers must not rely on an include order, so it is
239349 safe to include them in any order possible. However, to not clutter global
0 commit comments