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 #pragma once.

#pragma once is a widely supported preprocessor directive that serves the same purpose as include guards: preventing multiple inclusions of the same header file. Unlike include guards, it is more concise, less error‑prone, and does not require defining a unique macro name.

#pragma once

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 pragma once is required in all include files to protect against inadvertent multiple inclusion.

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

Note that unlike macro-based include guards, #pragma once does not require any changes at the end of the file, such as an #endif directive.

Some files in the codebase specially generated by tools or copied directly from an external project may not use #pragma once. These files are exempted from this rule.

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_ */