Skip to content

Commit 6f9d8b6

Browse files
authored
Add two new paragraphs to coding style about header files (systemd#37188)
2 parents e895a49 + 352fee1 commit 6f9d8b6

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

docs/CODING_STYLE.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)