2 # Create makefile for MS nmake and GNU make
4 # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
10 from __future__
import print_function
11 from __future__
import absolute_import
12 import os
.path
as path
14 from collections
import defaultdict
15 from GenFds
.FdfParser
import FdfParser
16 from Workspace
.WorkspaceCommon
import GetModuleLibInstances
17 from AutoGen
import GenMake
18 from AutoGen
.AutoGen
import AutoGen
19 from AutoGen
.PlatformAutoGen
import PlatformAutoGen
20 from AutoGen
.BuildEngine
import gDefaultBuildRuleFile
21 from Common
.ToolDefClassObject
import gDefaultToolsDefFile
22 from Common
.StringUtils
import NormPath
23 from Common
.BuildToolError
import *
24 from Common
.DataType
import *
25 from Common
.Misc
import *
28 ## Regular expression for splitting Dependency Expression string into tokens
29 gDepexTokenPattern
= re
.compile("(\(|\)|\w+| \S+\.inf)")
31 ## Regular expression for match: PCD(xxxx.yyy)
32 gPCDAsGuidPattern
= re
.compile(r
"^PCD\(.+\..+\)$")
34 ## Workspace AutoGen class
36 # This class is used mainly to control the whole platform build for different
37 # architecture. This class will generate top level makefile.
39 class WorkspaceAutoGen(AutoGen
):
40 # call super().__init__ then call the worker function with different parameter count
41 def __init__(self
, Workspace
, MetaFile
, Target
, Toolchain
, Arch
, *args
, **kwargs
):
42 if not hasattr(self
, "_Init"):
43 self
._InitWorker
(Workspace
, MetaFile
, Target
, Toolchain
, Arch
, *args
, **kwargs
)
46 ## Initialize WorkspaceAutoGen
48 # @param WorkspaceDir Root directory of workspace
49 # @param ActivePlatform Meta-file of active platform
50 # @param Target Build target
51 # @param Toolchain Tool chain name
52 # @param ArchList List of architecture of current build
53 # @param MetaFileDb Database containing meta-files
54 # @param BuildConfig Configuration of build
55 # @param ToolDefinition Tool chain definitions
56 # @param FlashDefinitionFile File of flash definition
57 # @param Fds FD list to be generated
58 # @param Fvs FV list to be generated
59 # @param Caps Capsule list to be generated
60 # @param SkuId SKU id from command line
62 def _InitWorker(self
, WorkspaceDir
, ActivePlatform
, Target
, Toolchain
, ArchList
, MetaFileDb
,
63 BuildConfig
, ToolDefinition
, FlashDefinitionFile
='', Fds
=None, Fvs
=None, Caps
=None, SkuId
='', UniFlag
=None,
64 Progress
=None, BuildModule
=None):
65 self
.BuildDatabase
= MetaFileDb
66 self
.MetaFile
= ActivePlatform
67 self
.WorkspaceDir
= WorkspaceDir
68 self
.Platform
= self
.BuildDatabase
[self
.MetaFile
, TAB_ARCH_COMMON
, Target
, Toolchain
]
69 GlobalData
.gActivePlatform
= self
.Platform
70 self
.BuildTarget
= Target
71 self
.ToolChain
= Toolchain
72 self
.ArchList
= ArchList
74 self
.UniFlag
= UniFlag
76 self
.TargetTxt
= BuildConfig
77 self
.ToolDef
= ToolDefinition
78 self
.FdfFile
= FlashDefinitionFile
79 self
.FdTargetList
= Fds
if Fds
else []
80 self
.FvTargetList
= Fvs
if Fvs
else []
81 self
.CapTargetList
= Caps
if Caps
else []
82 self
.AutoGenObjectList
= []
85 # there's many relative directory operations, so ...
86 os
.chdir(self
.WorkspaceDir
)
89 self
.ValidateBuildTarget()
93 EdkLogger
.info('%-16s = %s' % ("Architecture(s)", ' '.join(self
.ArchList
)))
94 EdkLogger
.info('%-16s = %s' % ("Build target", self
.BuildTarget
))
95 EdkLogger
.info('%-16s = %s' % ("Toolchain", self
.ToolChain
))
97 EdkLogger
.info('\n%-24s = %s' % ("Active Platform", self
.Platform
))
99 EdkLogger
.info('%-24s = %s' % ("Active Module", BuildModule
))
102 EdkLogger
.info('%-24s = %s' % ("Flash Image Definition", self
.FdfFile
))
104 EdkLogger
.verbose("\nFLASH_DEFINITION = %s" % self
.FdfFile
)
107 Progress
.Start("\nProcessing meta-data")
109 # Mark now build in AutoGen Phase
111 GlobalData
.gAutoGenPhase
= True
112 self
.ProcessModuleFromPdf()
113 self
.ProcessPcdType()
114 self
.ProcessMixedPcd()
115 self
.VerifyPcdsFromFDF()
116 self
.CollectAllPcds()
117 for Pa
in self
.AutoGenObjectList
:
118 Pa
.FillData_LibConstPcd()
119 self
.GeneratePkgLevelHash()
121 # Check PCDs token value conflict in each DEC file.
123 self
._CheckAllPcdsTokenValueConflict
()
125 # Check PCD type and definition between DSC and DEC
127 self
._CheckPcdDefineAndType
()
129 self
.CreateBuildOptionsFile()
130 self
.CreatePcdTokenNumberFile()
131 self
.GeneratePlatformLevelHash()
137 if not self
.ArchList
:
138 ArchList
= set(self
.Platform
.SupArchList
)
140 ArchList
= set(self
.ArchList
) & set(self
.Platform
.SupArchList
)
142 EdkLogger
.error("build", PARAMETER_INVALID
,
143 ExtraData
= "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self
.Platform
.SupArchList
)))
144 elif self
.ArchList
and len(ArchList
) != len(self
.ArchList
):
145 SkippedArchList
= set(self
.ArchList
).symmetric_difference(set(self
.Platform
.SupArchList
))
146 EdkLogger
.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
147 % (" ".join(SkippedArchList
), " ".join(self
.Platform
.SupArchList
)))
148 self
.ArchList
= tuple(ArchList
)
150 # Validate build target
151 def ValidateBuildTarget(self
):
152 if self
.BuildTarget
not in self
.Platform
.BuildTargets
:
153 EdkLogger
.error("build", PARAMETER_INVALID
,
154 ExtraData
="Build target [%s] is not supported by the platform. [Valid target: %s]"
155 % (self
.BuildTarget
, " ".join(self
.Platform
.BuildTargets
)))
157 def FdfProfile(self
):
159 self
.FdfFile
= self
.Platform
.FlashDefinition
163 Fdf
= FdfParser(self
.FdfFile
.Path
)
165 GlobalData
.gFdfParser
= Fdf
166 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
167 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
168 for FdRegion
in FdDict
.RegionList
:
169 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
170 if int(FdRegion
.Offset
) % 8 != 0:
171 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
172 FdfProfile
= Fdf
.Profile
174 if self
.FdTargetList
:
175 EdkLogger
.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self
.FdTargetList
))
176 self
.FdTargetList
= []
177 if self
.FvTargetList
:
178 EdkLogger
.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self
.FvTargetList
))
179 self
.FvTargetList
= []
180 if self
.CapTargetList
:
181 EdkLogger
.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self
.CapTargetList
))
182 self
.CapTargetList
= []
186 def ProcessModuleFromPdf(self
):
189 for fvname
in self
.FvTargetList
:
190 if fvname
.upper() not in self
.FdfProfile
.FvDict
:
191 EdkLogger
.error("build", OPTION_VALUE_INVALID
,
192 "No such an FV in FDF file: %s" % fvname
)
194 # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
195 # but the path (self.MetaFile.Path) is the real path
196 for key
in self
.FdfProfile
.InfDict
:
198 MetaFile_cache
= defaultdict(set)
199 for Arch
in self
.ArchList
:
200 Current_Platform_cache
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
201 for Pkey
in Current_Platform_cache
.Modules
:
202 MetaFile_cache
[Arch
].add(Current_Platform_cache
.Modules
[Pkey
].MetaFile
)
203 for Inf
in self
.FdfProfile
.InfDict
[key
]:
204 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
205 for Arch
in self
.ArchList
:
206 if ModuleFile
in MetaFile_cache
[Arch
]:
209 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
210 if not ModuleData
.IsBinaryModule
:
211 EdkLogger
.error('build', PARSER_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile
)
214 for Arch
in self
.ArchList
:
216 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
218 for Pkey
in Platform
.Modules
:
219 MetaFileList
.add(Platform
.Modules
[Pkey
].MetaFile
)
220 for Inf
in self
.FdfProfile
.InfDict
[key
]:
221 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
222 if ModuleFile
in MetaFileList
:
224 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
225 if not ModuleData
.IsBinaryModule
:
226 EdkLogger
.error('build', PARSER_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile
)
230 # parse FDF file to get PCDs in it, if any
231 def VerifyPcdsFromFDF(self
):
234 PcdSet
= self
.FdfProfile
.PcdDict
235 self
.VerifyPcdDeclearation(PcdSet
)
237 def ProcessPcdType(self
):
238 for Arch
in self
.ArchList
:
239 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
241 # generate the SourcePcdDict and BinaryPcdDict
243 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
244 if BuildData
.Arch
!= Arch
:
246 if BuildData
.MetaFile
.Ext
== '.inf' and str(BuildData
) in Platform
.Modules
:
247 Libs
.extend(GetModuleLibInstances(BuildData
, Platform
,
252 self
.Platform
.MetaFile
,
255 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
256 if BuildData
.Arch
!= Arch
:
258 if BuildData
.MetaFile
.Ext
== '.inf':
259 for key
in BuildData
.Pcds
:
260 if BuildData
.Pcds
[key
].Pending
:
261 if key
in Platform
.Pcds
:
262 PcdInPlatform
= Platform
.Pcds
[key
]
263 if PcdInPlatform
.Type
:
264 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
265 BuildData
.Pcds
[key
].Pending
= False
267 if BuildData
.MetaFile
in Platform
.Modules
:
268 PlatformModule
= Platform
.Modules
[str(BuildData
.MetaFile
)]
269 if key
in PlatformModule
.Pcds
:
270 PcdInPlatform
= PlatformModule
.Pcds
[key
]
271 if PcdInPlatform
.Type
:
272 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
273 BuildData
.Pcds
[key
].Pending
= False
275 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
276 if BuildData
.Pcds
[key
].Pending
:
277 if bool(BuildData
.LibraryClass
):
278 if BuildData
in set(Libs
):
279 ReferenceModules
= BuildData
.ReferenceModules
280 for ReferenceModule
in ReferenceModules
:
281 if ReferenceModule
.MetaFile
in Platform
.Modules
:
282 RefPlatformModule
= Platform
.Modules
[str(ReferenceModule
.MetaFile
)]
283 if key
in RefPlatformModule
.Pcds
:
284 PcdInReferenceModule
= RefPlatformModule
.Pcds
[key
]
285 if PcdInReferenceModule
.Type
:
286 BuildData
.Pcds
[key
].Type
= PcdInReferenceModule
.Type
287 BuildData
.Pcds
[key
].Pending
= False
290 def ProcessMixedPcd(self
):
291 for Arch
in self
.ArchList
:
292 SourcePcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set(),TAB_PCDS_DYNAMIC
:set(),TAB_PCDS_FIXED_AT_BUILD
:set()}
293 BinaryPcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set()}
294 SourcePcdDict_Keys
= SourcePcdDict
.keys()
295 BinaryPcdDict_Keys
= BinaryPcdDict
.keys()
297 # generate the SourcePcdDict and BinaryPcdDict
299 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
300 if BuildData
.Arch
!= Arch
:
302 if BuildData
.MetaFile
.Ext
== '.inf':
303 for key
in BuildData
.Pcds
:
304 if TAB_PCDS_DYNAMIC_EX
in BuildData
.Pcds
[key
].Type
:
305 if BuildData
.IsBinaryModule
:
306 BinaryPcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
308 SourcePcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
310 elif TAB_PCDS_PATCHABLE_IN_MODULE
in BuildData
.Pcds
[key
].Type
:
311 if BuildData
.MetaFile
.Ext
== '.inf':
312 if BuildData
.IsBinaryModule
:
313 BinaryPcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
315 SourcePcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
317 elif TAB_PCDS_DYNAMIC
in BuildData
.Pcds
[key
].Type
:
318 SourcePcdDict
[TAB_PCDS_DYNAMIC
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
319 elif TAB_PCDS_FIXED_AT_BUILD
in BuildData
.Pcds
[key
].Type
:
320 SourcePcdDict
[TAB_PCDS_FIXED_AT_BUILD
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
323 # A PCD can only use one type for all source modules
325 for i
in SourcePcdDict_Keys
:
326 for j
in SourcePcdDict_Keys
:
328 Intersections
= SourcePcdDict
[i
].intersection(SourcePcdDict
[j
])
329 if len(Intersections
) > 0:
333 "Building modules from source INFs, following PCD use %s and %s access method. It must be corrected to use only one access method." % (i
, j
),
334 ExtraData
='\n\t'.join(str(P
[1]+'.'+P
[0]) for P
in Intersections
)
338 # intersection the BinaryPCD for Mixed PCD
340 for i
in BinaryPcdDict_Keys
:
341 for j
in BinaryPcdDict_Keys
:
343 Intersections
= BinaryPcdDict
[i
].intersection(BinaryPcdDict
[j
])
344 for item
in Intersections
:
345 NewPcd1
= (item
[0] + '_' + i
, item
[1])
346 NewPcd2
= (item
[0] + '_' + j
, item
[1])
347 if item
not in GlobalData
.MixedPcd
:
348 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
350 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
351 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
352 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
353 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
356 # intersection the SourcePCD and BinaryPCD for Mixed PCD
358 for i
in SourcePcdDict_Keys
:
359 for j
in BinaryPcdDict_Keys
:
361 Intersections
= SourcePcdDict
[i
].intersection(BinaryPcdDict
[j
])
362 for item
in Intersections
:
363 NewPcd1
= (item
[0] + '_' + i
, item
[1])
364 NewPcd2
= (item
[0] + '_' + j
, item
[1])
365 if item
not in GlobalData
.MixedPcd
:
366 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
368 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
369 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
370 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
371 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
373 BuildData
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
374 for key
in BuildData
.Pcds
:
375 for SinglePcd
in GlobalData
.MixedPcd
:
376 if (BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
) == SinglePcd
:
377 for item
in GlobalData
.MixedPcd
[SinglePcd
]:
378 Pcd_Type
= item
[0].split('_')[-1]
379 if (Pcd_Type
== BuildData
.Pcds
[key
].Type
) or (Pcd_Type
== TAB_PCDS_DYNAMIC_EX
and BuildData
.Pcds
[key
].Type
in PCD_DYNAMIC_EX_TYPE_SET
) or \
380 (Pcd_Type
== TAB_PCDS_DYNAMIC
and BuildData
.Pcds
[key
].Type
in PCD_DYNAMIC_TYPE_SET
):
381 Value
= BuildData
.Pcds
[key
]
382 Value
.TokenCName
= BuildData
.Pcds
[key
].TokenCName
+ '_' + Pcd_Type
384 newkey
= (Value
.TokenCName
, key
[1])
386 newkey
= (Value
.TokenCName
, key
[1], key
[2])
387 del BuildData
.Pcds
[key
]
388 BuildData
.Pcds
[newkey
] = Value
393 PcdSet
= self
.FdfProfile
.PcdDict
394 # handle the mixed pcd in FDF file
396 if key
in GlobalData
.MixedPcd
:
399 for item
in GlobalData
.MixedPcd
[key
]:
402 #Collect package set information from INF of FDF
406 self
.FdfFile
= self
.Platform
.FlashDefinition
409 ModuleList
= self
.FdfProfile
.InfList
413 for Arch
in self
.ArchList
:
414 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
416 for mb
in [self
.BuildDatabase
[m
, Arch
, self
.BuildTarget
, self
.ToolChain
] for m
in Platform
.Modules
]:
417 PkgSet
.update(mb
.Packages
)
418 for Inf
in ModuleList
:
419 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
420 if ModuleFile
in Platform
.Modules
:
422 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
423 PkgSet
.update(ModuleData
.Packages
)
424 PkgSet
.update(Platform
.Packages
)
425 Pkgs
[Arch
] = list(PkgSet
)
428 def VerifyPcdDeclearation(self
,PcdSet
):
429 for Arch
in self
.ArchList
:
430 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
431 Pkgs
= self
.PkgSet
[Arch
]
436 DecPcds
.add((Pcd
[0], Pcd
[1]))
437 DecPcdsKey
.add((Pcd
[0], Pcd
[1], Pcd
[2]))
439 Platform
.SkuName
= self
.SkuId
440 for Name
, Guid
,Fileds
in PcdSet
:
441 if (Name
, Guid
) not in DecPcds
:
445 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid
, Name
),
446 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
447 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
450 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
451 if (Name
, Guid
, TAB_PCDS_FIXED_AT_BUILD
) in DecPcdsKey \
452 or (Name
, Guid
, TAB_PCDS_PATCHABLE_IN_MODULE
) in DecPcdsKey \
453 or (Name
, Guid
, TAB_PCDS_FEATURE_FLAG
) in DecPcdsKey
:
455 elif (Name
, Guid
, TAB_PCDS_DYNAMIC
) in DecPcdsKey
or (Name
, Guid
, TAB_PCDS_DYNAMIC_EX
) in DecPcdsKey
:
459 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid
, Name
),
460 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
461 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
463 def CollectAllPcds(self
):
465 for Arch
in self
.ArchList
:
466 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
468 # Explicitly collect platform's dynamic PCDs
470 Pa
.CollectPlatformDynamicPcds()
471 Pa
.CollectFixedAtBuildPcds()
472 self
.AutoGenObjectList
.append(Pa
)
473 # We need to calculate the PcdTokenNumber after all Arch Pcds are collected.
474 for Arch
in self
.ArchList
:
476 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
477 self
.UpdateModuleDataPipe(Arch
, {"PCD_TNUM":Pa
.PcdTokenNumber
})
479 def UpdateModuleDataPipe(self
,arch
, attr_dict
):
480 for (Target
, Toolchain
, Arch
, MetaFile
) in AutoGen
.Cache():
484 AutoGen
.Cache()[(Target
, Toolchain
, Arch
, MetaFile
)].DataPipe
.DataContainer
= attr_dict
488 # Generate Package level hash value
490 def GeneratePkgLevelHash(self
):
491 for Arch
in self
.ArchList
:
492 GlobalData
.gPackageHash
= {}
493 if GlobalData
.gUseHashCache
:
494 for Pkg
in self
.PkgSet
[Arch
]:
495 self
._GenPkgLevelHash
(Pkg
)
498 def CreateBuildOptionsFile(self
):
500 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
502 content
= 'gCommandLineDefines: '
503 content
+= str(GlobalData
.gCommandLineDefines
)
504 content
+= TAB_LINE_BREAK
505 content
+= 'BuildOptionPcd: '
506 content
+= str(GlobalData
.BuildOptionPcd
)
507 content
+= TAB_LINE_BREAK
508 content
+= 'Active Platform: '
509 content
+= str(self
.Platform
)
510 content
+= TAB_LINE_BREAK
512 content
+= 'Flash Image Definition: '
513 content
+= str(self
.FdfFile
)
514 content
+= TAB_LINE_BREAK
515 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'BuildOptions'), content
, False)
517 def CreatePcdTokenNumberFile(self
):
519 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
521 PcdTokenNumber
= 'PcdTokenNumber: '
522 Pa
= self
.AutoGenObjectList
[0]
523 if Pa
.PcdTokenNumber
:
524 if Pa
.DynamicPcdList
:
525 for Pcd
in Pa
.DynamicPcdList
:
526 PcdTokenNumber
+= TAB_LINE_BREAK
527 PcdTokenNumber
+= str((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
528 PcdTokenNumber
+= ' : '
529 PcdTokenNumber
+= str(Pa
.PcdTokenNumber
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
])
530 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'), PcdTokenNumber
, False)
532 def GeneratePlatformLevelHash(self
):
534 # Get set of workspace metafiles
536 AllWorkSpaceMetaFiles
= self
._GetMetaFiles
(self
.BuildTarget
, self
.ToolChain
)
537 AllWorkSpaceMetaFileList
= sorted(AllWorkSpaceMetaFiles
, key
=lambda x
: str(x
))
539 # Retrieve latest modified time of all metafiles
542 for f
in AllWorkSpaceMetaFiles
:
543 if os
.stat(f
)[8] > SrcTimeStamp
:
544 SrcTimeStamp
= os
.stat(f
)[8]
545 self
._SrcTimeStamp
= SrcTimeStamp
547 if GlobalData
.gUseHashCache
:
550 for file in AllWorkSpaceMetaFileList
:
551 if file.endswith('.dec'):
557 FileList
.append((str(file), hashlib
.md5(Content
).hexdigest()))
559 HashDir
= path
.join(self
.BuildDir
, "Hash_Platform")
560 HashFile
= path
.join(HashDir
, 'Platform.hash.' + m
.hexdigest())
561 SaveFileOnChange(HashFile
, m
.hexdigest(), False)
562 HashChainFile
= path
.join(HashDir
, 'Platform.hashchain.' + m
.hexdigest())
563 GlobalData
.gPlatformHashFile
= HashChainFile
565 with
open(HashChainFile
, 'w') as f
:
566 json
.dump(FileList
, f
, indent
=2)
568 EdkLogger
.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile
)
570 if GlobalData
.gBinCacheDest
:
571 # Copy platform hash files to cache destination
572 FileDir
= path
.join(GlobalData
.gBinCacheDest
, self
.OutputDir
, self
.BuildTarget
+ "_" + self
.ToolChain
, "Hash_Platform")
573 CacheFileDir
= FileDir
574 CreateDirectory(CacheFileDir
)
575 CopyFileOnChange(HashFile
, CacheFileDir
)
576 CopyFileOnChange(HashChainFile
, CacheFileDir
)
579 # Write metafile list to build directory
581 AutoGenFilePath
= os
.path
.join(self
.BuildDir
, 'AutoGen')
582 if os
.path
.exists (AutoGenFilePath
):
583 os
.remove(AutoGenFilePath
)
584 if not os
.path
.exists(self
.BuildDir
):
585 os
.makedirs(self
.BuildDir
)
586 with
open(os
.path
.join(self
.BuildDir
, 'AutoGen'), 'w+') as file:
587 for f
in AllWorkSpaceMetaFileList
:
591 def _GenPkgLevelHash(self
, Pkg
):
592 if Pkg
.PackageName
in GlobalData
.gPackageHash
:
595 PkgDir
= os
.path
.join(self
.BuildDir
, Pkg
.Arch
, "Hash_Pkg", Pkg
.PackageName
)
596 CreateDirectory(PkgDir
)
599 # Get .dec file's hash value
600 f
= open(Pkg
.MetaFile
.Path
, 'rb')
604 FileList
.append((str(Pkg
.MetaFile
.Path
), hashlib
.md5(Content
).hexdigest()))
605 # Get include files hash value
607 for inc
in sorted(Pkg
.Includes
, key
=lambda x
: str(x
)):
608 for Root
, Dirs
, Files
in os
.walk(str(inc
)):
609 for File
in sorted(Files
):
610 File_Path
= os
.path
.join(Root
, File
)
611 f
= open(File_Path
, 'rb')
615 FileList
.append((str(File_Path
), hashlib
.md5(Content
).hexdigest()))
616 GlobalData
.gPackageHash
[Pkg
.PackageName
] = m
.hexdigest()
619 HashFile
= path
.join(HashDir
, Pkg
.PackageName
+ '.hash.' + m
.hexdigest())
620 SaveFileOnChange(HashFile
, m
.hexdigest(), False)
621 HashChainFile
= path
.join(HashDir
, Pkg
.PackageName
+ '.hashchain.' + m
.hexdigest())
622 GlobalData
.gPackageHashFile
[(Pkg
.PackageName
, Pkg
.Arch
)] = HashChainFile
624 with
open(HashChainFile
, 'w') as f
:
625 json
.dump(FileList
, f
, indent
=2)
627 EdkLogger
.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile
)
629 if GlobalData
.gBinCacheDest
:
630 # Copy Pkg hash files to cache destination dir
631 FileDir
= path
.join(GlobalData
.gBinCacheDest
, self
.OutputDir
, self
.BuildTarget
+ "_" + self
.ToolChain
, Pkg
.Arch
, "Hash_Pkg", Pkg
.PackageName
)
632 CacheFileDir
= FileDir
633 CreateDirectory(CacheFileDir
)
634 CopyFileOnChange(HashFile
, CacheFileDir
)
635 CopyFileOnChange(HashChainFile
, CacheFileDir
)
637 def _GetMetaFiles(self
, Target
, Toolchain
):
638 AllWorkSpaceMetaFiles
= set()
643 AllWorkSpaceMetaFiles
.add (self
.FdfFile
.Path
)
644 for f
in GlobalData
.gFdfParser
.GetAllIncludedFile():
645 AllWorkSpaceMetaFiles
.add (f
.FileName
)
649 AllWorkSpaceMetaFiles
.add(self
.MetaFile
.Path
)
652 # add build_rule.txt & tools_def.txt
654 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultBuildRuleFile
))
655 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultToolsDefFile
))
657 # add BuildOption metafile
659 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'BuildOptions'))
661 # add PcdToken Number file for Dynamic/DynamicEx Pcd
663 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'))
665 for Pa
in self
.AutoGenObjectList
:
666 AllWorkSpaceMetaFiles
.add(Pa
.ToolDefinitionFile
)
668 for Arch
in self
.ArchList
:
672 for Package
in PlatformAutoGen(self
, self
.MetaFile
, Target
, Toolchain
, Arch
).PackageList
:
673 AllWorkSpaceMetaFiles
.add(Package
.MetaFile
.Path
)
678 for filePath
in self
.BuildDatabase
[self
.MetaFile
, Arch
, Target
, Toolchain
]._RawData
.IncludedFiles
:
679 AllWorkSpaceMetaFiles
.add(filePath
.Path
)
681 return AllWorkSpaceMetaFiles
683 def _CheckPcdDefineAndType(self
):
684 PcdTypeSet
= {TAB_PCDS_FIXED_AT_BUILD
,
685 TAB_PCDS_PATCHABLE_IN_MODULE
,
686 TAB_PCDS_FEATURE_FLAG
,
690 # This dict store PCDs which are not used by any modules with specified arches
691 UnusedPcd
= OrderedDict()
692 for Pa
in self
.AutoGenObjectList
:
693 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
694 for Pcd
in Pa
.Platform
.Pcds
:
695 PcdType
= Pa
.Platform
.Pcds
[Pcd
].Type
697 # If no PCD type, this PCD comes from FDF
701 # Try to remove Hii and Vpd suffix
702 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
703 PcdType
= TAB_PCDS_DYNAMIC_EX
704 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
705 PcdType
= TAB_PCDS_DYNAMIC
707 for Package
in Pa
.PackageList
:
708 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
709 if (Pcd
[0], Pcd
[1], PcdType
) in Package
.Pcds
:
711 for Type
in PcdTypeSet
:
712 if (Pcd
[0], Pcd
[1], Type
) in Package
.Pcds
:
716 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
717 % (Pa
.Platform
.Pcds
[Pcd
].Type
, Pcd
[1], Pcd
[0], Type
),
722 UnusedPcd
.setdefault(Pcd
, []).append(Pa
.Arch
)
724 for Pcd
in UnusedPcd
:
727 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
728 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
729 % (Pcd
[1], Pcd
[0], os
.path
.basename(str(self
.MetaFile
)), str(UnusedPcd
[Pcd
])),
734 return "%s [%s]" % (self
.MetaFile
, ", ".join(self
.ArchList
))
736 ## Return the directory to store FV files
739 return path
.join(self
.BuildDir
, TAB_FV_DIRECTORY
)
741 ## Return the directory to store all intermediate and final files built
744 return self
.AutoGenObjectList
[0].BuildDir
746 ## Return the build output directory platform specifies
749 return self
.Platform
.OutputDirectory
751 ## Return platform name
754 return self
.Platform
.PlatformName
756 ## Return meta-file GUID
759 return self
.Platform
.Guid
761 ## Return platform version
764 return self
.Platform
.Version
766 ## Return paths of tools
768 def ToolDefinition(self
):
769 return self
.AutoGenObjectList
[0].ToolDefinition
771 ## Return directory of platform makefile
773 # @retval string Makefile directory
776 def MakeFileDir(self
):
779 ## Return build command string
781 # @retval string Build command string
784 def BuildCommand(self
):
785 # BuildCommand should be all the same. So just get one from platform AutoGen
786 return self
.AutoGenObjectList
[0].BuildCommand
788 ## Check the PCDs token value conflict in each DEC file.
790 # Will cause build break and raise error message while two PCDs conflict.
794 def _CheckAllPcdsTokenValueConflict(self
):
795 for Pa
in self
.AutoGenObjectList
:
796 for Package
in Pa
.PackageList
:
797 PcdList
= list(Package
.Pcds
.values())
798 PcdList
.sort(key
=lambda x
: int(x
.TokenValue
, 0))
800 while (Count
< len(PcdList
) - 1) :
801 Item
= PcdList
[Count
]
802 ItemNext
= PcdList
[Count
+ 1]
804 # Make sure in the same token space the TokenValue should be unique
806 if (int(Item
.TokenValue
, 0) == int(ItemNext
.TokenValue
, 0)):
807 SameTokenValuePcdList
= []
808 SameTokenValuePcdList
.append(Item
)
809 SameTokenValuePcdList
.append(ItemNext
)
810 RemainPcdListLength
= len(PcdList
) - Count
- 2
811 for ValueSameCount
in range(RemainPcdListLength
):
812 if int(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
].TokenValue
, 0) == int(Item
.TokenValue
, 0):
813 SameTokenValuePcdList
.append(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
])
817 # Sort same token value PCD list with TokenGuid and TokenCName
819 SameTokenValuePcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
820 SameTokenValuePcdListCount
= 0
821 while (SameTokenValuePcdListCount
< len(SameTokenValuePcdList
) - 1):
823 TemListItem
= SameTokenValuePcdList
[SameTokenValuePcdListCount
]
824 TemListItemNext
= SameTokenValuePcdList
[SameTokenValuePcdListCount
+ 1]
826 if (TemListItem
.TokenSpaceGuidCName
== TemListItemNext
.TokenSpaceGuidCName
) and (TemListItem
.TokenCName
!= TemListItemNext
.TokenCName
):
827 for PcdItem
in GlobalData
.MixedPcd
:
828 if (TemListItem
.TokenCName
, TemListItem
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
] or \
829 (TemListItemNext
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
]:
835 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
836 % (TemListItem
.TokenValue
, TemListItem
.TokenSpaceGuidCName
, TemListItem
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
, TemListItemNext
.TokenCName
, Package
),
839 SameTokenValuePcdListCount
+= 1
840 Count
+= SameTokenValuePcdListCount
843 PcdList
= list(Package
.Pcds
.values())
844 PcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
846 while (Count
< len(PcdList
) - 1) :
847 Item
= PcdList
[Count
]
848 ItemNext
= PcdList
[Count
+ 1]
850 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
852 if (Item
.TokenSpaceGuidCName
== ItemNext
.TokenSpaceGuidCName
) and (Item
.TokenCName
== ItemNext
.TokenCName
) and (int(Item
.TokenValue
, 0) != int(ItemNext
.TokenValue
, 0)):
856 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
857 % (Item
.TokenValue
, Item
.TokenSpaceGuidCName
, Item
.TokenCName
, Package
),
861 ## Generate fds command
863 def GenFdsCommand(self
):
864 return (GenMake
.TopLevelMakefile(self
)._TEMPLATE
_.Replace(GenMake
.TopLevelMakefile(self
)._TemplateDict
)).strip()
867 def GenFdsCommandDict(self
):
869 LogLevel
= EdkLogger
.GetLevel()
870 if LogLevel
== EdkLogger
.VERBOSE
:
871 FdsCommandDict
["verbose"] = True
872 elif LogLevel
<= EdkLogger
.DEBUG_9
:
873 FdsCommandDict
["debug"] = LogLevel
- 1
874 elif LogLevel
== EdkLogger
.QUIET
:
875 FdsCommandDict
["quiet"] = True
877 FdsCommandDict
["GenfdsMultiThread"] = GlobalData
.gEnableGenfdsMultiThread
878 if GlobalData
.gIgnoreSource
:
879 FdsCommandDict
["IgnoreSources"] = True
881 FdsCommandDict
["OptionPcd"] = []
882 for pcd
in GlobalData
.BuildOptionPcd
:
884 pcdname
= '.'.join(pcd
[0:3])
886 pcdname
= '.'.join(pcd
[0:2])
887 if pcd
[3].startswith('{'):
888 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + 'H' + '"' + pcd
[3] + '"')
890 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + pcd
[3])
893 # macros passed to GenFds
895 MacroDict
.update(GlobalData
.gGlobalDefines
)
896 MacroDict
.update(GlobalData
.gCommandLineDefines
)
897 for MacroName
in MacroDict
:
898 if MacroDict
[MacroName
] != "":
899 MacroList
.append('"%s=%s"' % (MacroName
, MacroDict
[MacroName
].replace('\\', '\\\\')))
901 MacroList
.append('"%s"' % MacroName
)
902 FdsCommandDict
["macro"] = MacroList
904 FdsCommandDict
["fdf_file"] = [self
.FdfFile
]
905 FdsCommandDict
["build_target"] = self
.BuildTarget
906 FdsCommandDict
["toolchain_tag"] = self
.ToolChain
907 FdsCommandDict
["active_platform"] = str(self
)
909 FdsCommandDict
["conf_directory"] = GlobalData
.gConfDirectory
910 FdsCommandDict
["build_architecture_list"] = ','.join(self
.ArchList
)
911 FdsCommandDict
["platform_build_directory"] = self
.BuildDir
913 FdsCommandDict
["fd"] = self
.FdTargetList
914 FdsCommandDict
["fv"] = self
.FvTargetList
915 FdsCommandDict
["cap"] = self
.CapTargetList
916 return FdsCommandDict
918 ## Create makefile for the platform and modules in it
920 # @param CreateDepsMakeFile Flag indicating if the makefile for
921 # modules will be created as well
923 def CreateMakeFile(self
, CreateDepsMakeFile
=False):
924 if not CreateDepsMakeFile
:
926 for Pa
in self
.AutoGenObjectList
:
927 Pa
.CreateMakeFile(CreateDepsMakeFile
)
929 ## Create autogen code for platform and modules
931 # Since there's no autogen code for platform, this method will do nothing
932 # if CreateModuleCodeFile is set to False.
934 # @param CreateDepsCodeFile Flag indicating if creating module's
935 # autogen code file or not
937 def CreateCodeFile(self
, CreateDepsCodeFile
=False):
938 if not CreateDepsCodeFile
:
940 for Pa
in self
.AutoGenObjectList
:
941 Pa
.CreateCodeFile(CreateDepsCodeFile
)
943 ## Create AsBuilt INF file the platform
945 def CreateAsBuiltInf(self
):