Skip to content

Commit b8875f9

Browse files
authored
BaseTools/Trim.py: Strip "#pragma once" from inlined ASL content (#1840)
## Description The pragma once changes in edk2 were not made until the end of February and are first released in the [edk2-stable202605](https://github.com/tianocore/edk2/releases/tag/edk2-stable202605) tag. However, some Mu platforms have moved ahead with pragma once changes in code outside of Mu. The main issue reported with doing so is compiling ASL where some of the header files in subprojects are using pragma once. This PR introduces the change to Mu first so the platforms that need this support now can have it and confirm the change with their platform build. There is not impact to existing use cases that do not use pragma once in header files included in ASL builds. Note: If a broader move to pragma once is needed before the 202605 stable tag is released in Mu, that needs to be requested in a GitHub issue and will require additional changes. --- 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). --- - [ ] Impacts functionality? - [ ] Impacts security? - [ ] Breaking change? - [ ] Includes tests? - [ ] Includes documentation? ## How This Was Tested - edk2/Mu CI - Platform build with no pragma once in header files - 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 Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
1 parent f11f110 commit b8875f9

1 file changed

Lines changed: 8 additions & 0 deletions

File tree

  • BaseTools/Source/Python/Trim

BaseTools/Source/Python/Trim/Trim.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@
5454
gAslIncludePattern = re.compile(r"^(\s*)[iI]nclude\s*\(\"?([^\"\(\)]+)\"\)", re.MULTILINE)
5555
## Regular expression for matching C style #include "XXX.asl" in asl file
5656
gAslCIncludePattern = re.compile(r'^(\s*)#include\s*[<"]\s*([-\\/\w.]+)\s*([>"])', re.MULTILINE)
57+
# MU_CHANGE [BEGIN] - Handle pragma once in ASL
58+
## Regular expression for matching "#pragma once"
59+
gPragmaOncePattern = re.compile(r"^\s*#\s*pragma\s+once\b", re.IGNORECASE)
60+
# MU_CHANGE [END] - Handle pragma once in ASL
5761
## Patterns used to convert EDK conventions to EDK2 ECP conventions
5862

5963
## Regular expression for finding header file inclusions
@@ -322,6 +326,10 @@ def DoInclude(Source, Indent='', IncludePathList=[], LocalSearchPath=None, Inclu
322326
if len(Result) == 0:
323327
Result = gAslCIncludePattern.findall(Line)
324328
if len(Result) == 0 or os.path.splitext(Result[0][1])[1].lower() not in [".asl", ".asi"]:
329+
# MU_CHANGE [BEGIN] - Handle pragma once in ASL
330+
if gPragmaOncePattern.match(Line):
331+
continue
332+
# MU_CHANGE [END] - Handle pragma once in ASL
325333
NewFileContent.append("%s%s" % (Indent, Line))
326334
continue
327335
#

0 commit comments

Comments
 (0)