5.3 Include Files

5.3.1 All C include file names shall contain only one extension and it must be .h.

Using only one extension dramatically simplifies build issues and standardizes naming.

5.3.2 Every include file shall have a unique name.

The name of all include files, within the EDK II code base, must be unique. The uniqueness test applies to the entire path used in the #include directive. For example:

#include <Peach/Pit.h>
#include "Olive/Pit.h"
#include <MoneyPit.h>
#include "OpenPit.h"

These are unique, even if the file name itself is not, as long as the preceding path component is included.

To see why this is necessary, consider a package, FruitPkg, that has the following in its DEC file:

[Includes]
Include
Include/Olive
Include/Peach

Both the Include/Olive and Include/Peach directories contain a file Pit.h. It then becomes ambiguous which file is being referenced if one encounters #include <Pit.h> in a source file. This ambiguity would be compounded if another package, also dependent upon FruitPkg, contained a Pit.h file in its Include directory.

Existing automatically generated include files, such as AutoGen.h, are exempted from this rule. It is not mandatory to rename pre-existing include files.

Unique file names may also be formed by appending or prepending a short character sequence, such as the module or package name in which the file resides, or an abbreviation of one of these, to the file name.

PeachPit.h OlivePit.h MoneyPit.h PitBoss.h

5.3.3 Include files shall not consist mainly of include directives.

This type of omnibus header file can significantly increase the time required to rebuild a project. If any of the included files changes, every file that includes the omnibus file will have to be recompiled; even if that particular file did not use the changed header file.

5.3.4 Include files may include only those headers that it directly depends upon.

This maintains proper dependency relationships between the files and allows the header file to be used without prior knowledge of its dependencies.

5.3.5 All include file contents must be protected by a #include guard.

Also known as a "macro guard", use #include guards to avoid multiple inclusions when dealing with the include directive. Adding #include guards to a header file makes that file idempotent.

#ifndef FILE_NAME_H_
#define FILE_NAME_H_
...
#endif // FILE_NAME_H_

Avoid duplicating the guard macro name in different header files. Including a duplicate guard macro name prevents the symbols in the other from being defined. Names starting with one or two underscores, such as _MACRO_GUARD_FILE_NAME_H_, must not be used. They are reserved for compiler implementation.

With modern programming practices, particularly include files including other include files, it is almost impossible to avoid including the same file more than once. This can only slow down the processing time and may cause difficult to diagnose issues. To avoid this, the use of macro guards is required in all include files to protect against inadvertent multiple inclusion.

  • The #ifndef shall be on the first line following the file header comment. This location ensures that all code is contained.

  • The #endif shall appear as the last line in the file. The #endif is followed by a comment consisting solely of the guard token. The line shall end with a carriage return (new line) as the last thing in the file, thus ensuring that all code is contained.

5.3.6 Include files shall contain only public or only private data.

Include files must not contain both types of information. Examples of public include files would be protocol definitions or industry standard specifications (EFI, SAL, ACPI, SMBIOS, etc.). Private data would include functions and internal data structure declarations used only within a single module.

5.3.7 Include files shall not generate code or define data variables.

Including code or defining variables can result in issues that are very difficult to debug.

The sample below shows the suggested order of declarations in an include file. Not all types of declarations are present in every file.

/** @file
Public declarations of bizarre protocols for something.
This is a detailed description of the something for which this
file exists. Something rotates upon the blarvitz allowing
implementation of bizarre protocols. If the blarvitz is NULL,
describe what is happening in more detail. If non-null, then
you should probably also explain your rationale.
Copyright (c) 20XX, Acme Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Specification Reference:
- UEFI 2.3, Chapter 9, Device Path Protocol
- PI 1.1, Chapter 10, Boot Paths
**/
#ifndef SAMPLE_THING_H_
#define SAMPLE_THING_H_
/* Include directives for dependent header files */
/* Simple defines of such items as status codes and macros */
/* Type definitions */
/* Function prototype declarations */
/* Protocol declarations */
#endif /* SAMPLE_THING_H_ */