Skip to content

BaseTools/Trim.py: Strip "#pragma once" from inlined ASL content#12667

Open
makubacki wants to merge 1 commit into
tianocore:masterfrom
makubacki:trim_pragma_once_update
Open

BaseTools/Trim.py: Strip "#pragma once" from inlined ASL content#12667
makubacki wants to merge 1 commit into
tianocore:masterfrom
makubacki:trim_pragma_once_update

Conversation

@makubacki

@makubacki makubacki commented Jun 11, 2026

Copy link
Copy Markdown
Member

Description

Note: I've made this description verbose because (1) I'm not sure everyone is familiar with the details and nuances of this flow and (2) I tried to balance a simple solution versus practical concerns and I want that to be obvious for feedback on the approach. TLDR is this addresses a potential warning in some C preprocessors if #pragma once is used in header files included in certain ways in ASL source files.


When Trim processes an ASL file (--asl-file), it textually inlines the body of every Include()'d file directly into the constructed preprocessor input, once per include site.

Its has duplicate protection in the form of a circular-include stack (gIncludedAslFile), that prevents A->B->A cycles. But, as far as the script is concerned, each Include() is a unique include site.

Various combinations of includes and file types are possible and handled slightly differently.

Starting with file types as defined in BaseTools\Conf\build_rule.template:

  • .aslc, .act files fall under Acpi-Table-Code-File and are compiled, linked, and processed by genfw.
  • .asl, .Asl, and .ASL files fall in Acpi-Source-Language-File and are processed by Trim:
    1. Trim --asl-file to produce a single combined .i file with includes inlined.
    2. ASLPP (ASL preprocessor, a C preprocessor) on the output of Trim to produce a .iii file with all macros expanded and conditional branches resolved. AutoGen.h is also included and processed here to resolve fixed PCD values if needed.
    3. Trim --source-code which takes the pre-processed .iii file and produces a .iiii file with content like linemarkers cleaned up.
    4. The ACPI compiler compiles the .iiii file to produce AML bytecode in a .aml file.

Because the .aslc/.act files are directly passed to normal C processing tools, they are not part of the Trim change made in this commit and the remainder of this message focuses on the ACPI Source Language File case.

ASL files can use either an ASL Include() directive or a C-style #include directive. In addition, different file types may be included such as a .asl file or a .h file.

Trim handles these cases differently:

  • For ASL Include() directives, Trim inlines the content of the included file directly into the output at the include site. This is done for all included ASL files regardless of their extension. The inlining is purely textual and does not attempt to resolve or preserve any preprocessor directives such as #pragma once or include guards.
  • For C-style #include directives, Trim checks the file extension of the included file. If the file is an ASL file (.asl or .asi), Trim treats the file the same as the Include() case. Otherwise, Trim passes the directive through verbatim to the output, allowing the downstream C preprocessor (ASLPP) to handle it according to normal C preprocessor rules.

This creates a situtation in which the resulting .i might include:

  • Inlined file content (from a .asl or .h file) depending on the include type and file extension.
  • Verbatim #include directives for non-ASL files which will be processed by the C preprocessor.

Focusing on the "inlined" case, historically .h files would have traditional C include guards (#ifndef/#define, #endif). However, files might also include #pragma once as a guard.

In that case, the inlined content of the .i file could contain multiple #pragma once directives, one per include site. When the C preprocessor (ASLPP) processes the .i file, it sees multiple #pragma once directives in what it considers the main file, and could emit a warning like the following from gcc:

warning: '#pragma once' in main file [-Wpragma-once-outside-header]

The remainder of this commit message describes the change made to address this warning.

This change strips "#pragma once" lines on the ASL content path in DoInclude() in Trim.py so the directive is removed before it reaches the C preprocessor.

  • "#include" directives for non-ASL files are still passed through verbatim for the C preprocessor to resolve where the contents of those .h files might contain "#pragma once" or traditional guards.
  • Traditional include guards are untouched and continue to behave as before where multiple include sites might inline the same content in the .i file before reaching the C preprocessor.

The change:

In the case that a file is inlined with a #pragma once directive, the directive is stripped from the inlined content which prevents the warning.

This is considered acceptable because it only removes the #pragma once directive from the inlined content for these specific cases. So, the .i file might contain multiple inlined copies of the same header content (like always in this inline case) but without the #pragma once directives. Because actual C content was already not processed or trimmed out (e.g. typedef struct) duplicate content that could cause multiple symbol definitions is not considered to be a problem (#define multiple times is not a problem for the C preprocessor).

  • Breaking change?
  • Impacts security?
  • Includes tests?

How This Was Tested

  • Look at the output (.i, .iii files, etc.) of Trim.py and C preprocessor output with gcc and MSVC linkers.
  • Test against platforms using complex variations of include types including the inlining case with #pragma once in .h files.

Integration Instructions

  • N/A

When Trim processes an ASL file (`--asl-file`), it textually inlines
the body of every `Include()`'d file directly into the constructed
preprocessor input, once per include site.

Its has duplicate protection in the form of a circular-include stack
(`gIncludedAslFile`), that prevents A->B->A cycles. But, as far as
the script is concerned, each `Include()` is a unique include site.

Various combinations of includes and file types are possible and
handled slightly differently.

Starting with file types as defined in
BaseTools\Conf\build_rule.template:

- `.aslc`, `.act` files fall under `Acpi-Table-Code-File` and are
  compiled, linked, and processed by genfw.
- `.asl`, `.Asl`, and `.ASL` files fall in `Acpi-Source-Language-File`
  and are processed by Trim:
  1. `Trim --asl-file` to produce a single combined .i file with
     includes inlined.
  2. `ASLPP` (ASL preprocessor, a C preprocessor) on the output of
     Trim to produce a .iii file with all macros expanded and
     conditional branches resolved. AutoGen.h is also included and
     processed here to resolve fixed PCD values if needed.
  3. `Trim --source-code` which takes the pre-processed .iii file and
     produces a .iiii file with content like linemarkers cleaned up.
  4. The ACPI compiler compiles the .iiii file to produce AML bytecode
     in a .aml file.

Because the `.aslc`/`.act` files are directly passed to normal C
processing tools, they are not part of the Trim change made in this
commit and the remainder of this message focuses on the ACPI Source
Language File case.

ASL files can use either an ASL `Include()` directive or a C-style
`#include` directive. In addition, different file types may be
included such as a `.asl` file or a `.h` file.

`Trim` handles these cases differently:

- For ASL `Include()` directives, `Trim` inlines the content of the
  included file directly into the output at the include site. This is
  done for all included ASL files regardless of their extension. The
  inlining is purely textual and does not attempt to resolve or
  preserve any preprocessor directives such as `#pragma once` or
  include guards.
- For C-style `#include` directives, `Trim` checks the file extension
  of the included file. If the file is an ASL file (`.asl` or `.asi`),
  `Trim` treats the file the same as the `Include()` case. Otherwise,
  `Trim` passes the directive through verbatim to the output, allowing
  the downstream C preprocessor (`ASLPP`) to handle it according to
  normal C preprocessor rules.

This creates a situtation in which the resulting `.i` might include:

- Inlined file content (from a `.asl` or `.h` file) depending on the
  include type and file extension.
- Verbatim `#include` directives for non-ASL files which will be
  processed by the C preprocessor.

Focusing on the "inlined" case, historically `.h` files would have
traditional C include guards (`#ifndef`/`#define`, `#endif`). However,
files might also include `#pragma once` as a guard.

In that case, the inlined content of the `.i` file could contain
multiple `#pragma once` directives, one per include site. When the
C preprocessor (`ASLPP`) processes the `.i` file, it sees multiple
`#pragma once` directives in what it considers the main file, and
could emit a warning like the following from gcc:

  warning: '#pragma once' in main file [-Wpragma-once-outside-header]

The remainder of this commit message describes the change made to
address this warning.

This change strips "#pragma once" lines on the ASL content path in
`DoInclude()` in `Trim.py` so the directive is removed before it
reaches the C preprocessor.

  - "#include" directives for non-ASL files are still passed through
    verbatim for the C preprocessor to resolve where the contents of
    those .h files might contain "#pragma once" or traditional guards.
  - Traditional include guards are untouched and continue to behave as
    before where multiple include sites might inline the same content
    in the .i file before reaching the C preprocessor.

The change:

In the case that a file is inlined with a `#pragma once` directive,
the directive is stripped from the inlined content which prevents the
warning.

This is considered acceptable because it only removes the
`#pragma once` directive from the inlined content for these specific
cases. So, the `.i` file might contain multiple inlined copies of the
same header content (like always in this inline case) but without the
`#pragma once` directives. Because actual C content was already not
processed or trimmed out (e.g. `typedef struct`) duplicate content is
not considered to be a problem (`#define` multiple times is not a
problem for the C preprocessor).

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants