-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathPlatformBuild.py
More file actions
298 lines (250 loc) · 12.5 KB
/
PlatformBuild.py
File metadata and controls
298 lines (250 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# @file PlatformBuild.py
# Script to Build OneCryptoPkg
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
import os
import io
import logging
from pathlib import Path
from edk2toolext.environment.uefi_build import UefiBuilder
from edk2toolext.invocables.edk2_ci_setup import CiSetupSettingsManager
from edk2toolext.invocables.edk2_platform_build import BuildSettingsManager
from edk2toolext.invocables.edk2_setup import SetupSettingsManager, RequiredSubmodule
from edk2toolext.invocables.edk2_update import UpdateSettingsManager
from edk2toollib.utility_functions import RunCmd
# ####################################################################################### #
# Common Configuration #
# ####################################################################################### #
class CommonPlatform():
''' Common settings for this platform. Define static data here and use
for the different parts of stuart
'''
PackagesSupported = ("OneCryptoPkg",)
ArchSupported = ("X64", "AARCH64")
TargetsSupported = ("DEBUG", "RELEASE")
Scopes = ('OneCrypto', 'edk2-build')
WorkspaceRoot = str(Path(__file__).resolve().parent)
@staticmethod
def GetAllSubmodules():
rs = []
# To avoid maintenance of this file for every new submodule
# lets just parse the .gitmodules and add each if not already in list.
result = io.StringIO()
ret = RunCmd("git", "config --file .gitmodules --get-regexp path",
workingdir=CommonPlatform.WorkspaceRoot, outstream=result)
# Cmd output is expected to look like:
# submodule.MU_BASECORE.path MU_BASECORE
if ret == 0:
for line in result.getvalue().splitlines():
_, _, path = line.partition(" ")
if path is not None:
if path not in [x.path for x in rs]:
# add it with recursive since we don't know
rs.append(RequiredSubmodule(path, True))
return rs
@staticmethod
def GetAllSubmodulePaths():
return (sm.path for sm in CommonPlatform.GetAllSubmodules())
@staticmethod
@staticmethod
def GetDependencies():
''' Return Git Repository Dependencies '''
return [
{
"Path": "MU_BASECORE",
"Url": "https://github.com/microsoft/mu_basecore.git",
"Commit": "8178984858b17819e10468d8540525e443c1978e"
},
{
"Path": "Features/MM_SUPV",
"Url": "https://github.com/microsoft/mu_feature_mm_supv.git",
"Commit": "4f686975e6a3e76c2d64e097415abdb773b8e56b"
},
{
"Path": "Common/MU",
"Url": "https://github.com/microsoft/mu_plus.git",
"Commit": "31f2b85ddb606cf6e4b4019ec2db1349d97b162b"
}
]
# ####################################################################################### #
# Configuration for Update & Setup #
# ####################################################################################### #
class SettingsManager(UpdateSettingsManager, SetupSettingsManager, CiSetupSettingsManager):
def GetPackagesSupported(self):
''' return iterable of edk2 packages supported by this build.
These should be edk2 workspace relative paths '''
return CommonPlatform.PackagesSupported
def GetArchitecturesSupported(self):
''' return iterable of edk2 architectures supported by this build '''
return CommonPlatform.ArchSupported
def GetTargetsSupported(self):
''' return iterable of edk2 target tags supported by this build '''
return CommonPlatform.TargetsSupported
def GetRequiredSubmodules(self):
''' return iterable containing RequiredSubmodule objects.
If no RequiredSubmodules return an empty iterable
'''
return CommonPlatform.GetAllSubmodules()
def SetArchitectures(self, list_of_requested_architectures):
''' Confirm the requests architecture list is valid and configure SettingsManager
to run only the requested architectures.
Raise Exception if a list_of_requested_architectures is not supported
'''
unsupported = set(list_of_requested_architectures) - \
set(self.GetArchitecturesSupported())
if len(unsupported) > 0:
errorString = (
"Unsupported Architecture Requested: " + " ".join(unsupported))
logging.critical(errorString)
raise Exception(errorString)
self.ActualArchitectures = list_of_requested_architectures
def GetWorkspaceRoot(self):
''' get WorkspacePath '''
return CommonPlatform.WorkspaceRoot
def GetActiveScopes(self):
''' return tuple containing scopes that should be active for this process '''
return CommonPlatform.Scopes
def GetName(self):
return "OneCryptoPkg"
def GetDependencies(self):
''' Return Git Repository Dependencies '''
return CommonPlatform.GetDependencies()
def GetPackagesPath(self):
''' Return a list of paths that should be mapped as edk2 PackagesPath '''
result = list(CommonPlatform.GetAllSubmodulePaths())
for dep in CommonPlatform.GetDependencies():
if dep["Path"] not in result:
result.append(dep["Path"])
return result
# ####################################################################################### #
# Actual Configuration for Platform Build #
# ####################################################################################### #
class PlatformBuilder(UefiBuilder, BuildSettingsManager):
def __init__(self):
UefiBuilder.__init__(self)
def AddCommandLineOptions(self, parserObj):
''' Add command line options to the argparser '''
parserObj.add_argument("-a", "--arch", dest="arch",
action="append",
choices=CommonPlatform.ArchSupported,
default=None,
help="target architecture(s) for the build, can be specified multiple times")
parserObj.add_argument("-t", "--target", dest="target",
action="append",
choices=CommonPlatform.TargetsSupported,
help="the target(s) to build, can be specified multiple times")
parserObj.add_argument("-sp", "--skip-packaging", dest="skip_packaging",
action="store_true", default=False,
help="skip OneCrypto packaging after build")
def RetrieveCommandLineOptions(self, args):
self.target = list(set(args.target)) if args.target else list(CommonPlatform.TargetsSupported)
self.arch = args.arch if args.arch else list(CommonPlatform.ArchSupported)
self.skip_packaging = args.skip_packaging
def GetWorkspaceRoot(self):
''' get WorkspacePath '''
return CommonPlatform.WorkspaceRoot
def GetPackagesPath(self):
''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''
result = list(CommonPlatform.GetAllSubmodulePaths())
for dep in CommonPlatform.GetDependencies():
if dep["Path"] not in result:
result.append(dep["Path"])
return result
def GetActiveScopes(self):
''' return tuple containing scopes that should be active for this process '''
return CommonPlatform.Scopes
def GetName(self):
''' Get the name of the repo, platform, or product being built '''
''' Used for naming the log file, among others '''
return "OneCryptoPkg"
def GetLoggingLevel(self, loggerType):
''' Get the logging level for a given type
base == lowest logging level supported
con == Screen logging
txt == plain text file logging
md == markdown file logging
'''
return super().GetLoggingLevel(loggerType)
def SetPlatformEnv(self):
logging.debug("PlatformBuilder SetPlatformEnv")
self.env.SetValue("PRODUCT_NAME", "OneCrypto", "Platform Hardcoded")
self.env.SetValue("ACTIVE_PLATFORM", "OneCryptoPkg/OneCryptoPkg.dsc", "Platform Hardcoded")
self.env.SetValue("OUTPUT_DIRECTORY", "Build/OneCryptoPkg", "Platform Hardcoded")
self.env.SetValue("TARGET_ARCH", " ".join(self.arch), "CLI args")
self.env.SetValue("TOOL_CHAIN_TAG", "CLANGPDB", "Platform Hardcoded")
# Default turn on build reporting.
self.env.SetValue("BUILDREPORTING", "TRUE", "Enabling build report")
self.env.SetValue("BUILDREPORT_TYPES",
"PCD DEPEX FLASH BUILD_FLAGS LIBRARY FIXED_ADDRESS HASH",
"Setting build report types")
return 0
def PlatformPreBuild(self):
return 0
def Build(self):
BUILD_LOOP_REASON = "Platform Hardcoded Build Loop"
toolchain = self.env.GetValue("TOOL_CHAIN_TAG", "CLANGPDB")
for target in self.target:
# Update TARGET to current target for this loop iteration
self.env.SetValue("TARGET", target, BUILD_LOOP_REASON, overridable=True)
# Update BUILD_OUTPUT_BASE to the new location based off TARGET_TOOLCHAIN combination
new_base = Path(self.env.GetValue("BUILD_OUTPUT_BASE")) / ".." / f"{target}_{toolchain}"
self.env.GetEntry("BUILD_OUTPUT_BASE").AllowOverride()
self.env.SetValue("BUILD_OUTPUT_BASE", new_base, BUILD_LOOP_REASON)
# Update BUILDREPORT_FILE to the new location based off TARGET_TOOLCHAIN combination
build_report = str(Path(self.env.GetValue("BUILD_OUTPUT_BASE")) / f"BUILD_REPORT.TXT")
self.env.GetEntry("BUILDREPORT_FILE").AllowOverride()
self.env.SetValue("BUILDREPORT_FILE", build_report, BUILD_LOOP_REASON)
# Build the current TARGET
ret = super().Build()
if ret != 0:
return ret
return 0
def PlatformPostBuild(self):
# Skip packaging if requested
if self.skip_packaging:
logging.critical("=" * 80)
logging.critical("Skipping post-build packaging (--skip-packaging)")
return 0
# Helper registered at OneCryptoPkg/Plugin/OneCryptoBundler
self.Helper.create_package(
workspace = self.ws,
output_zip = Path(self.env.GetValue("BUILD_OUTPUT_BASE")) / ".." / "OneCrypto-Drivers.zip",
architectures = self.arch,
toolchain = self.env.GetValue("TOOL_CHAIN_TAG", "CLANGPDB"),
targets = self.target
)
return 0
if __name__ == "__main__":
import argparse
import sys
from edk2toolext.invocables.edk2_update import Edk2Update
from edk2toolext.invocables.edk2_setup import Edk2PlatformSetup
from edk2toolext.invocables.edk2_platform_build import Edk2PlatformBuild
print("Invoking Stuart")
print(r" ) _ _")
print(r" ( (^)-~-(^)")
print(r"__,-.\_( 0 0 )__,-.___")
print(r" 'W' \ / 'W'")
print(r" >o<")
SCRIPT_PATH = os.path.relpath(__file__)
parser = argparse.ArgumentParser(add_help=False)
parse_group = parser.add_mutually_exclusive_group()
parse_group.add_argument("--update", "--UPDATE",
action='store_true', help="Invokes stuart_update")
parse_group.add_argument("--setup", "--SETUP",
action='store_true', help="Invokes stuart_setup")
args, remaining = parser.parse_known_args()
new_args = ["stuart", "-c", SCRIPT_PATH]
new_args = new_args + remaining
sys.argv = new_args
if args.setup:
print("Running stuart_setup -c " + SCRIPT_PATH)
Edk2PlatformSetup().Invoke()
elif args.update:
print("Running stuart_update -c " + SCRIPT_PATH)
Edk2Update().Invoke()
else:
print("Running stuart_build -c " + SCRIPT_PATH)
Edk2PlatformBuild().Invoke()