diff options
Diffstat (limited to 'BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py')
| -rw-r--r-- | BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py | 338 |
1 files changed, 169 insertions, 169 deletions
diff --git a/BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py b/BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py index 2f6c928c21..06898dfec6 100644 --- a/BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py +++ b/BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py @@ -1,169 +1,169 @@ -# @file CodeQlBuildPlugin.py
-#
-# A build plugin that produces CodeQL results for the present build.
-#
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-import glob
-import logging
-import os
-import stat
-from common import codeql_plugin
-from pathlib import Path
-
-from edk2toolext import edk2_logging
-from edk2toolext.environment.plugintypes.uefi_build_plugin import \
- IUefiBuildPlugin
-from edk2toolext.environment.uefi_build import UefiBuilder
-from edk2toollib.uefi.edk2.path_utilities import Edk2Path
-from edk2toollib.utility_functions import GetHostInfo, RemoveTree
-
-
-class CodeQlBuildPlugin(IUefiBuildPlugin):
-
- def do_pre_build(self, builder: UefiBuilder) -> int:
- """CodeQL pre-build functionality.
-
- Args:
- builder (UefiBuilder): A UEFI builder object for this build.
-
- Returns:
- int: The plugin return code. Zero indicates the plugin ran
- successfully. A non-zero value indicates an unexpected error
- occurred during plugin execution.
- """
-
- if not builder.SkipBuild:
- self.builder = builder
- self.package = builder.edk2path.GetContainingPackage(
- builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
- builder.env.GetValue("ACTIVE_PLATFORM")
- )
- )
-
- self.target = builder.env.GetValue("TARGET")
-
- self.build_output_dir = builder.env.GetValue("BUILD_OUTPUT_BASE")
-
- self.codeql_db_path = codeql_plugin.get_codeql_db_path(
- builder.ws, self.package, self.target)
-
- edk2_logging.log_progress(f"{self.package} will be built for CodeQL")
- edk2_logging.log_progress(f" CodeQL database will be written to "
- f"{self.codeql_db_path}")
-
- self.codeql_path = codeql_plugin.get_codeql_cli_path()
- if not self.codeql_path:
- logging.critical("CodeQL build enabled but CodeQL CLI application "
- "not found.")
- return -1
-
- # CodeQL can only generate a database on clean build
- #
- # Note: builder.CleanTree() cannot be used here as some platforms
- # have build steps that run before this plugin that store
- # files in the build output directory.
- #
- # CodeQL does not care about with those files or many others such
- # as the FV directory, build logs, etc. so instead focus on
- # removing only the directories with compilation/linker output
- # for the architectures being built (that need clean runs for
- # CodeQL to work).
- targets = self.builder.env.GetValue("TARGET_ARCH").split(" ")
- for target in targets:
- directory_to_delete = Path(self.build_output_dir, target)
-
- if directory_to_delete.is_dir():
- logging.debug(f"Removing {str(directory_to_delete)} to have a "
- f"clean build for CodeQL.")
- RemoveTree(str(directory_to_delete))
-
- # CodeQL CLI does not handle spaces passed in CLI commands well
- # (perhaps at all) as discussed here:
- # 1. https://github.com/github/codeql-cli-binaries/issues/73
- # 2. https://github.com/github/codeql/issues/4910
- #
- # Since it's unclear how quotes are handled and may change in the
- # future, this code is going to use the workaround to place the
- # command in an executable file that is instead passed to CodeQL.
- self.codeql_cmd_path = Path(self.build_output_dir, "codeql_build_command")
-
- build_params = self._get_build_params()
-
- codeql_build_cmd = ""
- if GetHostInfo().os == "Windows":
- self.codeql_cmd_path = self.codeql_cmd_path.parent / (
- self.codeql_cmd_path.name + '.bat')
- elif GetHostInfo().os == "Linux":
- self.codeql_cmd_path = self.codeql_cmd_path.parent / (
- self.codeql_cmd_path.name + '.sh')
- codeql_build_cmd += f"#!/bin/bash{os.linesep * 2}"
- codeql_build_cmd += "build " + build_params
-
- self.codeql_cmd_path.parent.mkdir(exist_ok=True, parents=True)
- self.codeql_cmd_path.write_text(encoding='utf8', data=codeql_build_cmd)
-
- if GetHostInfo().os == "Linux":
- os.chmod(self.codeql_cmd_path,
- os.stat(self.codeql_cmd_path).st_mode | stat.S_IEXEC)
- for f in glob.glob(os.path.join(
- os.path.dirname(self.codeql_path), '**/*'), recursive=True):
- os.chmod(f, os.stat(f).st_mode | stat.S_IEXEC)
-
- codeql_params = (f'database create {self.codeql_db_path} '
- f'--language=cpp '
- f'--source-root={builder.ws} '
- f'--command={self.codeql_cmd_path}')
-
- # Set environment variables so the CodeQL build command is picked up
- # as the active build command.
- #
- # Note: Requires recent changes in edk2-pytool-extensions (0.20.0)
- # to support reading these variables.
- builder.env.SetValue(
- "EDK_BUILD_CMD", self.codeql_path, "Set in CodeQL Build Plugin")
- builder.env.SetValue(
- "EDK_BUILD_PARAMS", codeql_params, "Set in CodeQL Build Plugin")
-
- return 0
-
- def _get_build_params(self) -> str:
- """Returns the build command parameters for this build.
-
- Based on the well-defined `build` command-line parameters.
-
- Returns:
- str: A string representing the parameters for the build command.
- """
- build_params = f"-p {self.builder.env.GetValue('ACTIVE_PLATFORM')}"
- build_params += f" -b {self.target}"
- build_params += f" -t {self.builder.env.GetValue('TOOL_CHAIN_TAG')}"
-
- max_threads = self.builder.env.GetValue('MAX_CONCURRENT_THREAD_NUMBER')
- if max_threads is not None:
- build_params += f" -n {max_threads}"
-
- rt = self.builder.env.GetValue("TARGET_ARCH").split(" ")
- for t in rt:
- build_params += " -a " + t
-
- if (self.builder.env.GetValue("BUILDREPORTING") == "TRUE"):
- build_params += (" -y " +
- self.builder.env.GetValue("BUILDREPORT_FILE"))
- rt = self.builder.env.GetValue("BUILDREPORT_TYPES").split(" ")
- for t in rt:
- build_params += " -Y " + t
-
- # add special processing to handle building a single module
- mod = self.builder.env.GetValue("BUILDMODULE")
- if (mod is not None and len(mod.strip()) > 0):
- build_params += " -m " + mod
- edk2_logging.log_progress("Single Module Build: " + mod)
-
- build_vars = self.builder.env.GetAllBuildKeyValues(self.target)
- for key, value in build_vars.items():
- build_params += " -D " + key + "=" + value
-
- return build_params
+# @file CodeQlBuildPlugin.py +# +# A build plugin that produces CodeQL results for the present build. +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +import glob +import logging +import os +import stat +from common import codeql_plugin +from pathlib import Path + +from edk2toolext import edk2_logging +from edk2toolext.environment.plugintypes.uefi_build_plugin import \ + IUefiBuildPlugin +from edk2toolext.environment.uefi_build import UefiBuilder +from edk2toollib.uefi.edk2.path_utilities import Edk2Path +from edk2toollib.utility_functions import GetHostInfo, RemoveTree + + +class CodeQlBuildPlugin(IUefiBuildPlugin): + + def do_pre_build(self, builder: UefiBuilder) -> int: + """CodeQL pre-build functionality. + + Args: + builder (UefiBuilder): A UEFI builder object for this build. + + Returns: + int: The plugin return code. Zero indicates the plugin ran + successfully. A non-zero value indicates an unexpected error + occurred during plugin execution. + """ + + if not builder.SkipBuild: + self.builder = builder + self.package = builder.edk2path.GetContainingPackage( + builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath( + builder.env.GetValue("ACTIVE_PLATFORM") + ) + ) + + self.target = builder.env.GetValue("TARGET") + + self.build_output_dir = builder.env.GetValue("BUILD_OUTPUT_BASE") + + self.codeql_db_path = codeql_plugin.get_codeql_db_path( + builder.ws, self.package, self.target) + + edk2_logging.log_progress(f"{self.package} will be built for CodeQL") + edk2_logging.log_progress(f" CodeQL database will be written to " + f"{self.codeql_db_path}") + + self.codeql_path = codeql_plugin.get_codeql_cli_path() + if not self.codeql_path: + logging.critical("CodeQL build enabled but CodeQL CLI application " + "not found.") + return -1 + + # CodeQL can only generate a database on clean build + # + # Note: builder.CleanTree() cannot be used here as some platforms + # have build steps that run before this plugin that store + # files in the build output directory. + # + # CodeQL does not care about with those files or many others such + # as the FV directory, build logs, etc. so instead focus on + # removing only the directories with compilation/linker output + # for the architectures being built (that need clean runs for + # CodeQL to work). + targets = self.builder.env.GetValue("TARGET_ARCH").split(" ") + for target in targets: + directory_to_delete = Path(self.build_output_dir, target) + + if directory_to_delete.is_dir(): + logging.debug(f"Removing {str(directory_to_delete)} to have a " + f"clean build for CodeQL.") + RemoveTree(str(directory_to_delete)) + + # CodeQL CLI does not handle spaces passed in CLI commands well + # (perhaps at all) as discussed here: + # 1. https://github.com/github/codeql-cli-binaries/issues/73 + # 2. https://github.com/github/codeql/issues/4910 + # + # Since it's unclear how quotes are handled and may change in the + # future, this code is going to use the workaround to place the + # command in an executable file that is instead passed to CodeQL. + self.codeql_cmd_path = Path(self.build_output_dir, "codeql_build_command") + + build_params = self._get_build_params() + + codeql_build_cmd = "" + if GetHostInfo().os == "Windows": + self.codeql_cmd_path = self.codeql_cmd_path.parent / ( + self.codeql_cmd_path.name + '.bat') + elif GetHostInfo().os == "Linux": + self.codeql_cmd_path = self.codeql_cmd_path.parent / ( + self.codeql_cmd_path.name + '.sh') + codeql_build_cmd += f"#!/bin/bash{os.linesep * 2}" + codeql_build_cmd += "build " + build_params + + self.codeql_cmd_path.parent.mkdir(exist_ok=True, parents=True) + self.codeql_cmd_path.write_text(encoding='utf8', data=codeql_build_cmd) + + if GetHostInfo().os == "Linux": + os.chmod(self.codeql_cmd_path, + os.stat(self.codeql_cmd_path).st_mode | stat.S_IEXEC) + for f in glob.glob(os.path.join( + os.path.dirname(self.codeql_path), '**/*'), recursive=True): + os.chmod(f, os.stat(f).st_mode | stat.S_IEXEC) + + codeql_params = (f'database create {self.codeql_db_path} ' + f'--language=cpp ' + f'--source-root={builder.ws} ' + f'--command={self.codeql_cmd_path}') + + # Set environment variables so the CodeQL build command is picked up + # as the active build command. + # + # Note: Requires recent changes in edk2-pytool-extensions (0.20.0) + # to support reading these variables. + builder.env.SetValue( + "EDK_BUILD_CMD", self.codeql_path, "Set in CodeQL Build Plugin") + builder.env.SetValue( + "EDK_BUILD_PARAMS", codeql_params, "Set in CodeQL Build Plugin") + + return 0 + + def _get_build_params(self) -> str: + """Returns the build command parameters for this build. + + Based on the well-defined `build` command-line parameters. + + Returns: + str: A string representing the parameters for the build command. + """ + build_params = f"-p {self.builder.env.GetValue('ACTIVE_PLATFORM')}" + build_params += f" -b {self.target}" + build_params += f" -t {self.builder.env.GetValue('TOOL_CHAIN_TAG')}" + + max_threads = self.builder.env.GetValue('MAX_CONCURRENT_THREAD_NUMBER') + if max_threads is not None: + build_params += f" -n {max_threads}" + + rt = self.builder.env.GetValue("TARGET_ARCH").split(" ") + for t in rt: + build_params += " -a " + t + + if (self.builder.env.GetValue("BUILDREPORTING") == "TRUE"): + build_params += (" -y " + + self.builder.env.GetValue("BUILDREPORT_FILE")) + rt = self.builder.env.GetValue("BUILDREPORT_TYPES").split(" ") + for t in rt: + build_params += " -Y " + t + + # add special processing to handle building a single module + mod = self.builder.env.GetValue("BUILDMODULE") + if (mod is not None and len(mod.strip()) > 0): + build_params += " -m " + mod + edk2_logging.log_progress("Single Module Build: " + mod) + + build_vars = self.builder.env.GetAllBuildKeyValues(self.target) + for key, value in build_vars.items(): + build_params += " -D " + key + "=" + value + + return build_params |
