]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/PlatformCI/PlatformBuild.py
EmulatorPkg: Add Platform CI and configuration for Core CI
[mirror_edk2.git] / EmulatorPkg / PlatformCI / PlatformBuild.py
CommitLineData
951a0353
SB
1# @file\r
2# Script to Build EmulatorPkg UEFI firmware\r
3#\r
4# Copyright (c) Microsoft Corporation.\r
5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
6##\r
7import os\r
8import logging\r
9import io\r
10\r
11from edk2toolext.environment import shell_environment\r
12from edk2toolext.environment.uefi_build import UefiBuilder\r
13from edk2toolext.invocables.edk2_platform_build import BuildSettingsManager\r
14from edk2toolext.invocables.edk2_setup import SetupSettingsManager, RequiredSubmodule\r
15from edk2toolext.invocables.edk2_update import UpdateSettingsManager\r
16from edk2toolext.invocables.edk2_pr_eval import PrEvalSettingsManager\r
17from edk2toollib.utility_functions import RunCmd\r
18from edk2toollib.utility_functions import GetHostInfo\r
19\r
20# ####################################################################################### #\r
21# Common Configuration #\r
22# ####################################################################################### #\r
23\r
24\r
25class CommonPlatform():\r
26 ''' Common settings for this platform. Define static data here and use\r
27 for the different parts of stuart\r
28 '''\r
29 PackagesSupported = ("EmulatorPkg",)\r
30 ArchSupported = ("X64", "IA32")\r
31 TargetsSupported = ("DEBUG", "RELEASE", "NOOPT")\r
32 Scopes = ('emulatorpkg', 'edk2-build')\r
33 WorkspaceRoot = os.path.realpath(os.path.join(\r
34 os.path.dirname(os.path.abspath(__file__)), "..", ".."))\r
35\r
36 # ####################################################################################### #\r
37 # Configuration for Update & Setup #\r
38 # ####################################################################################### #\r
39\r
40\r
41class SettingsManager(UpdateSettingsManager, SetupSettingsManager, PrEvalSettingsManager):\r
42\r
43 def GetPackagesSupported(self):\r
44 ''' return iterable of edk2 packages supported by this build.\r
45 These should be edk2 workspace relative paths '''\r
46 return CommonPlatform.PackagesSupported\r
47\r
48 def GetArchitecturesSupported(self):\r
49 ''' return iterable of edk2 architectures supported by this build '''\r
50 return CommonPlatform.ArchSupported\r
51\r
52 def GetTargetsSupported(self):\r
53 ''' return iterable of edk2 target tags supported by this build '''\r
54 return CommonPlatform.TargetsSupported\r
55\r
56 def GetRequiredSubmodules(self):\r
57 ''' return iterable containing RequiredSubmodule objects.\r
58 If no RequiredSubmodules return an empty iterable\r
59 '''\r
60 rs = []\r
61 # intentionally declare this one with recursive false to avoid overhead\r
62 rs.append(RequiredSubmodule(\r
63 "CryptoPkg/Library/OpensslLib/openssl", False))\r
64\r
65 # To avoid maintenance of this file for every new submodule\r
66 # lets just parse the .gitmodules and add each if not already in list.\r
67 # The GetRequiredSubmodules is designed to allow a build to optimize\r
68 # the desired submodules but it isn't necessary for this repository.\r
69 result = io.StringIO()\r
70 ret = RunCmd("git", "config --file .gitmodules --get-regexp path", workingdir=self.GetWorkspaceRoot(), outstream=result)\r
71 # Cmd output is expected to look like:\r
72 # submodule.CryptoPkg/Library/OpensslLib/openssl.path CryptoPkg/Library/OpensslLib/openssl\r
73 # submodule.SoftFloat.path ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3\r
74 if ret == 0:\r
75 for line in result.getvalue().splitlines():\r
76 _, _, path = line.partition(" ")\r
77 if path is not None:\r
78 if path not in [x.path for x in rs]:\r
79 rs.append(RequiredSubmodule(path, True)) # add it with recursive since we don't know\r
80 return rs\r
81\r
82 def SetArchitectures(self, list_of_requested_architectures):\r
83 ''' Confirm the requests architecture list is valid and configure SettingsManager\r
84 to run only the requested architectures.\r
85\r
86 Raise Exception if a list_of_requested_architectures is not supported\r
87 '''\r
88 unsupported = set(list_of_requested_architectures) - \\r
89 set(self.GetArchitecturesSupported())\r
90 if(len(unsupported) > 0):\r
91 errorString = (\r
92 "Unsupported Architecture Requested: " + " ".join(unsupported))\r
93 logging.critical(errorString)\r
94 raise Exception(errorString)\r
95 self.ActualArchitectures = list_of_requested_architectures\r
96\r
97 def GetWorkspaceRoot(self):\r
98 ''' get WorkspacePath '''\r
99 return CommonPlatform.WorkspaceRoot\r
100\r
101 def GetActiveScopes(self):\r
102 ''' return tuple containing scopes that should be active for this process '''\r
103 return CommonPlatform.Scopes\r
104\r
105 def FilterPackagesToTest(self, changedFilesList: list, potentialPackagesList: list) -> list:\r
106 ''' Filter other cases that this package should be built\r
107 based on changed files. This should cover things that can't\r
108 be detected as dependencies. '''\r
109 build_these_packages = []\r
110 possible_packages = potentialPackagesList.copy()\r
111 for f in changedFilesList:\r
112 # BaseTools files that might change the build\r
113 if "BaseTools" in f:\r
114 if os.path.splitext(f) not in [".txt", ".md"]:\r
115 build_these_packages = possible_packages\r
116 break\r
117 # if the azure pipeline platform template file changed\r
118 if "platform-build-run-steps.yml" in f:\r
119 build_these_packages = possible_packages\r
120 break\r
121 return build_these_packages\r
122\r
123 def GetPlatformDscAndConfig(self) -> tuple:\r
124 ''' If a platform desires to provide its DSC then Policy 4 will evaluate if\r
125 any of the changes will be built in the dsc.\r
126\r
127 The tuple should be (<workspace relative path to dsc file>, <input dictionary of dsc key value pairs>)\r
128 '''\r
129 return (os.path.join("EmulatorPkg", "EmulatorPkg.dsc"), {})\r
130\r
131 # ####################################################################################### #\r
132 # Actual Configuration for Platform Build #\r
133 # ####################################################################################### #\r
134\r
135\r
136class PlatformBuilder(UefiBuilder, BuildSettingsManager):\r
137 def __init__(self):\r
138 UefiBuilder.__init__(self)\r
139\r
140 def AddCommandLineOptions(self, parserObj):\r
141 ''' Add command line options to the argparser '''\r
142 parserObj.add_argument('-a', "--arch", dest="build_arch", type=str, default="X64",\r
143 help="Optional - architecture to build. IA32 will use IA32 for Pei & Dxe. "\r
144 "X64 will use X64 for both PEI and DXE.")\r
145\r
146 def RetrieveCommandLineOptions(self, args):\r
147 ''' Retrieve command line options from the argparser '''\r
148\r
149 shell_environment.GetBuildVars().SetValue(\r
150 "TARGET_ARCH", args.build_arch.upper(), "From CmdLine")\r
151 shell_environment.GetBuildVars().SetValue(\r
152 "ACTIVE_PLATFORM", "EmulatorPkg/EmulatorPkg.dsc", "From CmdLine")\r
153\r
154 def GetWorkspaceRoot(self):\r
155 ''' get WorkspacePath '''\r
156 return CommonPlatform.WorkspaceRoot\r
157\r
158 def GetPackagesPath(self):\r
159 ''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''\r
160 return ()\r
161\r
162 def GetActiveScopes(self):\r
163 ''' return tuple containing scopes that should be active for this process '''\r
164 return CommonPlatform.Scopes\r
165\r
166 def GetName(self):\r
167 ''' Get the name of the repo, platform, or product being build '''\r
168 ''' Used for naming the log file, among others '''\r
169\r
170 # check the startup nsh flag and if set then rename the log file.\r
171 # this helps in CI so we don't overwrite the build log since running\r
172 # uses the stuart_build command.\r
173 if(shell_environment.GetBuildVars().GetValue("MAKE_STARTUP_NSH", "FALSE") == "TRUE"):\r
174 return "EmulatorPkg_With_Run"\r
175 return "EmulatorPkg"\r
176\r
177 def GetLoggingLevel(self, loggerType):\r
178 ''' Get the logging level for a given type\r
179 base == lowest logging level supported\r
180 con == Screen logging\r
181 txt == plain text file logging\r
182 md == markdown file logging\r
183 '''\r
184 return logging.DEBUG\r
185\r
186 def SetPlatformEnv(self):\r
187 logging.debug("PlatformBuilder SetPlatformEnv")\r
188 self.env.SetValue("PRODUCT_NAME", "EmulatorPkg", "Platform Hardcoded")\r
189 self.env.SetValue("TOOL_CHAIN_TAG", "VS2019", "Default Toolchain")\r
190\r
191 # Add support for using the correct Platform Headers, tools, and Libs based on emulator architecture\r
192 # requested to be built when building VS2019 or VS2017\r
193 if self.env.GetValue("TOOL_CHAIN_TAG") == "VS2019" or self.env.GetValue("TOOL_CHAIN_TAG") == "VS2017":\r
194 key = self.env.GetValue("TOOL_CHAIN_TAG") + "_HOST"\r
195 if self.env.GetValue("TARGET_ARCH") == "IA32":\r
196 shell_environment.ShellEnvironment().set_shell_var(key, "x86")\r
197 elif self.env.GetValue("TARGET_ARCH") == "X64":\r
198 shell_environment.ShellEnvironment().set_shell_var(key, "x64")\r
199\r
200 # Add support for using the correct Platform Headers, tools, and Libs based on emulator architecture\r
201 # requested to be built when building on linux.\r
202 if GetHostInfo().os.upper() == "LINUX":\r
203 self.ConfigureLinuxDLinkPath()\r
204\r
205 if GetHostInfo().os.upper() == "WINDOWS":\r
206 self.env.SetValue("BLD_*_WIN_HOST_BUILD", "TRUE",\r
207 "Trigger Windows host build")\r
208\r
209 self.env.SetValue("MAKE_STARTUP_NSH", "FALSE", "Default to false")\r
210\r
211 # I don't see what this does but it is in build.sh\r
212 key = "BLD_*_BUILD_" + self.env.GetValue("TARGET_ARCH")\r
213 self.env.SetValue(key, "TRUE", "match script in build.sh")\r
214 return 0\r
215\r
216 def PlatformPreBuild(self):\r
217 return 0\r
218\r
219 def PlatformPostBuild(self):\r
220 return 0\r
221\r
222 def FlashRomImage(self):\r
223 ''' Use the FlashRom Function to run the emulator. This gives an easy stuart command line to\r
224 activate the emulator. '''\r
225\r
226 OutputPath = os.path.join(self.env.GetValue(\r
227 "BUILD_OUTPUT_BASE"), self.env.GetValue("TARGET_ARCH"))\r
228\r
229 if (self.env.GetValue("MAKE_STARTUP_NSH") == "TRUE"):\r
230 f = open(os.path.join(OutputPath, "startup.nsh"), "w")\r
231 f.write("BOOT SUCCESS !!! \n")\r
232 # add commands here\r
233 f.write("reset\n")\r
234 f.close()\r
235\r
236 if GetHostInfo().os.upper() == "WINDOWS":\r
237 cmd = "WinHost.exe"\r
238 elif GetHostInfo().os.upper() == "LINUX":\r
239 cmd = "./Host"\r
240 else:\r
241 logging.critical("Unsupported Host")\r
242 return -1\r
243 return RunCmd(cmd, "", workingdir=OutputPath)\r
244\r
245 def ConfigureLinuxDLinkPath(self):\r
246 '''\r
247 logic copied from build.sh to setup the correct libraries\r
248 '''\r
249 if self.env.GetValue("TARGET_ARCH") == "IA32":\r
250 LIB_NAMES = ["ld-linux.so.2", "libdl.so.2 crt1.o", "crti.o crtn.o"]\r
251 LIB_SEARCH_PATHS = ["/usr/lib/i386-linux-gnu",\r
252 "/usr/lib32", "/lib32", "/usr/lib", "/lib"]\r
253 elif self.env.GetValue("TARGET_ARCH") == "X64":\r
254 LIB_NAMES = ["ld-linux-x86-64.so.2",\r
255 "libdl.so.2", "crt1.o", "crti.o", "crtn.o"]\r
256 LIB_SEARCH_PATHS = ["/usr/lib/x86_64-linux-gnu",\r
257 "/usr/lib64", "/lib64", "/usr/lib", "/lib"]\r
258\r
259 HOST_DLINK_PATHS = ""\r
260 for lname in LIB_NAMES:\r
261 logging.debug(f"Looking for {lname}")\r
262 for dname in LIB_SEARCH_PATHS:\r
263 logging.debug(f"In {dname}")\r
264 if os.path.isfile(os.path.join(dname, lname)):\r
265 logging.debug(f"Found {lname} in {dname}")\r
266 HOST_DLINK_PATHS += os.path.join(\r
267 os.path.join(dname, lname)) + os.pathsep\r
268 break\r
269 HOST_DLINK_PATHS = HOST_DLINK_PATHS.rstrip(os.pathsep)\r
270 logging.critical(f"Setting HOST_DLINK_PATHS to {HOST_DLINK_PATHS}")\r
271 shell_environment.ShellEnvironment().set_shell_var(\r
272 "HOST_DLINK_PATHS", HOST_DLINK_PATHS)\r