VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/BaseTools/Plugin/CodeQL/CodeQlBuildPlugin.py@ 108492

Last change on this file since 108492 was 105670, checked in by vboxsync, 9 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 7.1 KB
Line 
1# @file CodeQlBuildPlugin.py
2#
3# A build plugin that produces CodeQL results for the present build.
4#
5# Copyright (c) Microsoft Corporation. All rights reserved.
6# SPDX-License-Identifier: BSD-2-Clause-Patent
7##
8
9import glob
10import logging
11import os
12import stat
13from common import codeql_plugin
14from pathlib import Path
15
16from edk2toolext import edk2_logging
17from edk2toolext.environment.plugintypes.uefi_build_plugin import \
18 IUefiBuildPlugin
19from edk2toolext.environment.uefi_build import UefiBuilder
20from edk2toollib.uefi.edk2.path_utilities import Edk2Path
21from edk2toollib.utility_functions import GetHostInfo, RemoveTree
22
23
24class CodeQlBuildPlugin(IUefiBuildPlugin):
25
26 def do_pre_build(self, builder: UefiBuilder) -> int:
27 """CodeQL pre-build functionality.
28
29 Args:
30 builder (UefiBuilder): A UEFI builder object for this build.
31
32 Returns:
33 int: The plugin return code. Zero indicates the plugin ran
34 successfully. A non-zero value indicates an unexpected error
35 occurred during plugin execution.
36 """
37
38 if not builder.SkipBuild:
39 self.builder = builder
40 self.package = builder.edk2path.GetContainingPackage(
41 builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
42 builder.env.GetValue("ACTIVE_PLATFORM")
43 )
44 )
45
46 self.target = builder.env.GetValue("TARGET")
47
48 self.build_output_dir = builder.env.GetValue("BUILD_OUTPUT_BASE")
49
50 self.codeql_db_path = codeql_plugin.get_codeql_db_path(
51 builder.ws, self.package, self.target)
52
53 edk2_logging.log_progress(f"{self.package} will be built for CodeQL")
54 edk2_logging.log_progress(f" CodeQL database will be written to "
55 f"{self.codeql_db_path}")
56
57 self.codeql_path = codeql_plugin.get_codeql_cli_path()
58 if not self.codeql_path:
59 logging.critical("CodeQL build enabled but CodeQL CLI application "
60 "not found.")
61 return -1
62
63 # CodeQL can only generate a database on clean build
64 #
65 # Note: builder.CleanTree() cannot be used here as some platforms
66 # have build steps that run before this plugin that store
67 # files in the build output directory.
68 #
69 # CodeQL does not care about with those files or many others such
70 # as the FV directory, build logs, etc. so instead focus on
71 # removing only the directories with compilation/linker output
72 # for the architectures being built (that need clean runs for
73 # CodeQL to work).
74 targets = self.builder.env.GetValue("TARGET_ARCH").split(" ")
75 for target in targets:
76 directory_to_delete = Path(self.build_output_dir, target)
77
78 if directory_to_delete.is_dir():
79 logging.debug(f"Removing {str(directory_to_delete)} to have a "
80 f"clean build for CodeQL.")
81 RemoveTree(str(directory_to_delete))
82
83 # CodeQL CLI does not handle spaces passed in CLI commands well
84 # (perhaps at all) as discussed here:
85 # 1. https://github.com/github/codeql-cli-binaries/issues/73
86 # 2. https://github.com/github/codeql/issues/4910
87 #
88 # Since it's unclear how quotes are handled and may change in the
89 # future, this code is going to use the workaround to place the
90 # command in an executable file that is instead passed to CodeQL.
91 self.codeql_cmd_path = Path(self.build_output_dir, "codeql_build_command")
92
93 build_params = self._get_build_params()
94
95 codeql_build_cmd = ""
96 if GetHostInfo().os == "Windows":
97 self.codeql_cmd_path = self.codeql_cmd_path.parent / (
98 self.codeql_cmd_path.name + '.bat')
99 elif GetHostInfo().os == "Linux":
100 self.codeql_cmd_path = self.codeql_cmd_path.parent / (
101 self.codeql_cmd_path.name + '.sh')
102 codeql_build_cmd += f"#!/bin/bash{os.linesep * 2}"
103 codeql_build_cmd += "build " + build_params
104
105 self.codeql_cmd_path.parent.mkdir(exist_ok=True, parents=True)
106 self.codeql_cmd_path.write_text(encoding='utf8', data=codeql_build_cmd)
107
108 if GetHostInfo().os == "Linux":
109 os.chmod(self.codeql_cmd_path,
110 os.stat(self.codeql_cmd_path).st_mode | stat.S_IEXEC)
111 for f in glob.glob(os.path.join(
112 os.path.dirname(self.codeql_path), '**/*'), recursive=True):
113 os.chmod(f, os.stat(f).st_mode | stat.S_IEXEC)
114
115 codeql_params = (f'database create {self.codeql_db_path} '
116 f'--language=cpp '
117 f'--source-root={builder.ws} '
118 f'--command={self.codeql_cmd_path}')
119
120 # Set environment variables so the CodeQL build command is picked up
121 # as the active build command.
122 #
123 # Note: Requires recent changes in edk2-pytool-extensions (0.20.0)
124 # to support reading these variables.
125 builder.env.SetValue(
126 "EDK_BUILD_CMD", self.codeql_path, "Set in CodeQL Build Plugin")
127 builder.env.SetValue(
128 "EDK_BUILD_PARAMS", codeql_params, "Set in CodeQL Build Plugin")
129
130 return 0
131
132 def _get_build_params(self) -> str:
133 """Returns the build command parameters for this build.
134
135 Based on the well-defined `build` command-line parameters.
136
137 Returns:
138 str: A string representing the parameters for the build command.
139 """
140 build_params = f"-p {self.builder.env.GetValue('ACTIVE_PLATFORM')}"
141 build_params += f" -b {self.target}"
142 build_params += f" -t {self.builder.env.GetValue('TOOL_CHAIN_TAG')}"
143
144 max_threads = self.builder.env.GetValue('MAX_CONCURRENT_THREAD_NUMBER')
145 if max_threads is not None:
146 build_params += f" -n {max_threads}"
147
148 rt = self.builder.env.GetValue("TARGET_ARCH").split(" ")
149 for t in rt:
150 build_params += " -a " + t
151
152 if (self.builder.env.GetValue("BUILDREPORTING") == "TRUE"):
153 build_params += (" -y " +
154 self.builder.env.GetValue("BUILDREPORT_FILE"))
155 rt = self.builder.env.GetValue("BUILDREPORT_TYPES").split(" ")
156 for t in rt:
157 build_params += " -Y " + t
158
159 # add special processing to handle building a single module
160 mod = self.builder.env.GetValue("BUILDMODULE")
161 if (mod is not None and len(mod.strip()) > 0):
162 build_params += " -m " + mod
163 edk2_logging.log_progress("Single Module Build: " + mod)
164
165 build_vars = self.builder.env.GetAllBuildKeyValues(self.target)
166 for key, value in build_vars.items():
167 build_params += " -D " + key + "=" + value
168
169 return build_params
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette