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