summaryrefslogtreecommitdiffstats
path: root/BaseTools/Plugin/DebugMacroCheck/BuildPlugin/DebugMacroCheckBuildPlugin.py
diff options
context:
space:
mode:
Diffstat (limited to 'BaseTools/Plugin/DebugMacroCheck/BuildPlugin/DebugMacroCheckBuildPlugin.py')
-rw-r--r--BaseTools/Plugin/DebugMacroCheck/BuildPlugin/DebugMacroCheckBuildPlugin.py127
1 files changed, 127 insertions, 0 deletions
diff --git a/BaseTools/Plugin/DebugMacroCheck/BuildPlugin/DebugMacroCheckBuildPlugin.py b/BaseTools/Plugin/DebugMacroCheck/BuildPlugin/DebugMacroCheckBuildPlugin.py
new file mode 100644
index 0000000000..b154466602
--- /dev/null
+++ b/BaseTools/Plugin/DebugMacroCheck/BuildPlugin/DebugMacroCheckBuildPlugin.py
@@ -0,0 +1,127 @@
+# @file DebugMacroCheckBuildPlugin.py
+#
+# A build plugin that checks if DEBUG macros are formatted properly.
+#
+# In particular, that print format specifiers are defined
+# with the expected number of arguments in the variable
+# argument list.
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+import logging
+import os
+import pathlib
+import sys
+import yaml
+
+# Import the build plugin
+plugin_file = pathlib.Path(__file__)
+sys.path.append(str(plugin_file.parent.parent))
+
+# flake8 (E402): Ignore flake8 module level import not at top of file
+import DebugMacroCheck # noqa: E402
+
+from edk2toolext import edk2_logging # noqa: E402
+from edk2toolext.environment.plugintypes.uefi_build_plugin import \
+ IUefiBuildPlugin # noqa: E402
+from edk2toolext.environment.uefi_build import UefiBuilder # noqa: E402
+from edk2toollib.uefi.edk2.path_utilities import Edk2Path # noqa: E402
+from pathlib import Path # noqa: E402
+
+
+class DebugMacroCheckBuildPlugin(IUefiBuildPlugin):
+
+ def do_pre_build(self, builder: UefiBuilder) -> int:
+ """Debug Macro Check pre-build functionality.
+
+ The plugin is invoked in pre-build since it can operate independently
+ of build tools and to notify the user of any errors earlier in the
+ build process to reduce feedback time.
+
+ Args:
+ builder (UefiBuilder): A UEFI builder object for this build.
+
+ Returns:
+ int: The number of debug macro errors found. Zero indicates the
+ check either did not run or no errors were found.
+ """
+
+ # Check if disabled in the environment
+ env_disable = builder.env.GetValue("DISABLE_DEBUG_MACRO_CHECK")
+ if env_disable:
+ return 0
+
+ # Only run on targets with compilation
+ build_target = builder.env.GetValue("TARGET").lower()
+ if "no-target" in build_target:
+ return 0
+
+ pp = builder.pp.split(os.pathsep)
+ edk2 = Edk2Path(builder.ws, pp)
+ package = edk2.GetContainingPackage(
+ builder.mws.join(builder.ws,
+ builder.env.GetValue(
+ "ACTIVE_PLATFORM")))
+ package_path = Path(
+ edk2.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
+ package))
+
+ # Every debug macro is printed at DEBUG logging level.
+ # Ensure the level is above DEBUG while executing the macro check
+ # plugin to avoid flooding the log handler.
+ handler_level_context = []
+ for h in logging.getLogger().handlers:
+ if h.level < logging.INFO:
+ handler_level_context.append((h, h.level))
+ h.setLevel(logging.INFO)
+
+ edk2_logging.log_progress("Checking DEBUG Macros")
+
+ # There are two ways to specify macro substitution data for this
+ # plugin. If multiple options are present, data is appended from
+ # each option.
+ #
+ # 1. Specify the substitution data in the package CI YAML file.
+ # 2. Specify a standalone substitution data YAML file.
+ ##
+ sub_data = {}
+
+ # 1. Allow substitution data to be specified in a "DebugMacroCheck" of
+ # the package CI YAML file. This is used to provide a familiar per-
+ # package customization flow for a package maintainer.
+ package_config_file = Path(
+ os.path.join(
+ package_path, package + ".ci.yaml"))
+ if package_config_file.is_file():
+ with open(package_config_file, 'r') as cf:
+ package_config_file_data = yaml.safe_load(cf)
+ if "DebugMacroCheck" in package_config_file_data and \
+ "StringSubstitutions" in \
+ package_config_file_data["DebugMacroCheck"]:
+ logging.info(f"Loading substitution data in "
+ f"{str(package_config_file)}")
+ sub_data |= package_config_file_data["DebugMacroCheck"]["StringSubstitutions"] # noqa
+
+ # 2. Allow a substitution file to be specified as an environment
+ # variable. This is used to provide flexibility in how to specify a
+ # substitution file. The value can be set anywhere prior to this plugin
+ # getting called such as pre-existing build script.
+ sub_file = builder.env.GetValue("DEBUG_MACRO_CHECK_SUB_FILE")
+ if sub_file:
+ logging.info(f"Loading substitution file {sub_file}")
+ with open(sub_file, 'r') as sf:
+ sub_data |= yaml.safe_load(sf)
+
+ try:
+ error_count = DebugMacroCheck.check_macros_in_directory(
+ package_path,
+ ignore_git_submodules=False,
+ show_progress_bar=False,
+ **sub_data)
+ finally:
+ for h, l in handler_level_context:
+ h.setLevel(l)
+
+ return error_count