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
112 # Collect Platform Guids to support Guid name in Fdfparser.
114 self
.CollectPlatformGuids()
115 GlobalData
.gAutoGenPhase
= True
116 self
.ProcessModuleFromPdf()
117 self
.ProcessPcdType()
118 self
.ProcessMixedPcd()
119 self
.VerifyPcdsFromFDF()
120 self
.CollectAllPcds()
121 for Pa
in self
.AutoGenObjectList
:
122 Pa
.FillData_LibConstPcd()
123 self
.GeneratePkgLevelHash()
125 # Check PCDs token value conflict in each DEC file.
127 self
._CheckAllPcdsTokenValueConflict
()
129 # Check PCD type and definition between DSC and DEC
131 self
._CheckPcdDefineAndType
()
133 self
.CreateBuildOptionsFile()
134 self
.CreatePcdTokenNumberFile()
135 self
.GeneratePlatformLevelHash()
141 if not self
.ArchList
:
142 ArchList
= set(self
.Platform
.SupArchList
)
144 ArchList
= set(self
.ArchList
) & set(self
.Platform
.SupArchList
)
146 EdkLogger
.error("build", PARAMETER_INVALID
,
147 ExtraData
= "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self
.Platform
.SupArchList
)))
148 elif self
.ArchList
and len(ArchList
) != len(self
.ArchList
):
149 SkippedArchList
= set(self
.ArchList
).symmetric_difference(set(self
.Platform
.SupArchList
))
150 EdkLogger
.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
151 % (" ".join(SkippedArchList
), " ".join(self
.Platform
.SupArchList
)))
152 self
.ArchList
= tuple(ArchList
)
154 # Validate build target
155 def ValidateBuildTarget(self
):
156 if self
.BuildTarget
not in self
.Platform
.BuildTargets
:
157 EdkLogger
.error("build", PARAMETER_INVALID
,
158 ExtraData
="Build target [%s] is not supported by the platform. [Valid target: %s]"
159 % (self
.BuildTarget
, " ".join(self
.Platform
.BuildTargets
)))
161 def CollectPlatformGuids(self
):
165 for Arch
in self
.ArchList
:
166 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
167 oriInfList
= Platform
.Modules
168 for ModuleFile
in oriInfList
:
169 ModuleData
= self
.BuildDatabase
[ModuleFile
, Platform
._Arch
, Platform
._Target
, Platform
._Toolchain
]
170 oriPkgSet
.update(ModuleData
.Packages
)
171 for Pkg
in oriPkgSet
:
173 GlobalData
.gGuidDict
.update(Guids
)
174 if Platform
.Packages
:
175 PlatformPkg
.update(Platform
.Packages
)
176 for Pkg
in PlatformPkg
:
178 GlobalData
.gGuidDict
.update(Guids
)
181 def FdfProfile(self
):
183 self
.FdfFile
= self
.Platform
.FlashDefinition
187 Fdf
= FdfParser(self
.FdfFile
.Path
)
189 GlobalData
.gFdfParser
= Fdf
190 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
191 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
192 for FdRegion
in FdDict
.RegionList
:
193 if str(FdRegion
.RegionType
) == 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
194 if int(FdRegion
.Offset
) % 8 != 0:
195 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
196 FdfProfile
= Fdf
.Profile
198 if self
.FdTargetList
:
199 EdkLogger
.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self
.FdTargetList
))
200 self
.FdTargetList
= []
201 if self
.FvTargetList
:
202 EdkLogger
.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self
.FvTargetList
))
203 self
.FvTargetList
= []
204 if self
.CapTargetList
:
205 EdkLogger
.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self
.CapTargetList
))
206 self
.CapTargetList
= []
210 def ProcessModuleFromPdf(self
):
213 for fvname
in self
.FvTargetList
:
214 if fvname
.upper() not in self
.FdfProfile
.FvDict
:
215 EdkLogger
.error("build", OPTION_VALUE_INVALID
,
216 "No such an FV in FDF file: %s" % fvname
)
218 # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
219 # but the path (self.MetaFile.Path) is the real path
220 for key
in self
.FdfProfile
.InfDict
:
222 MetaFile_cache
= defaultdict(set)
223 for Arch
in self
.ArchList
:
224 Current_Platform_cache
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
225 for Pkey
in Current_Platform_cache
.Modules
:
226 MetaFile_cache
[Arch
].add(Current_Platform_cache
.Modules
[Pkey
].MetaFile
)
227 for Inf
in self
.FdfProfile
.InfDict
[key
]:
228 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
229 for Arch
in self
.ArchList
:
230 if ModuleFile
in MetaFile_cache
[Arch
]:
233 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
234 if not ModuleData
.IsBinaryModule
:
235 EdkLogger
.error('build', PARSER_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile
)
238 for Arch
in self
.ArchList
:
240 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
242 for Pkey
in Platform
.Modules
:
243 MetaFileList
.add(Platform
.Modules
[Pkey
].MetaFile
)
244 for Inf
in self
.FdfProfile
.InfDict
[key
]:
245 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
246 if ModuleFile
in MetaFileList
:
248 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
249 if not ModuleData
.IsBinaryModule
:
250 EdkLogger
.error('build', PARSER_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile
)
254 # parse FDF file to get PCDs in it, if any
255 def VerifyPcdsFromFDF(self
):
258 PcdSet
= self
.FdfProfile
.PcdDict
259 self
.VerifyPcdDeclearation(PcdSet
)
261 def ProcessPcdType(self
):
262 for Arch
in self
.ArchList
:
263 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
265 # generate the SourcePcdDict and BinaryPcdDict
267 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
268 if BuildData
.Arch
!= Arch
:
270 if BuildData
.MetaFile
.Ext
== '.inf' and str(BuildData
) in Platform
.Modules
:
271 Libs
.extend(GetModuleLibInstances(BuildData
, Platform
,
276 self
.Platform
.MetaFile
,
279 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
280 if BuildData
.Arch
!= Arch
:
282 if BuildData
.MetaFile
.Ext
== '.inf':
283 for key
in BuildData
.Pcds
:
284 if BuildData
.Pcds
[key
].Pending
:
285 if key
in Platform
.Pcds
:
286 PcdInPlatform
= Platform
.Pcds
[key
]
287 if PcdInPlatform
.Type
:
288 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
289 BuildData
.Pcds
[key
].Pending
= False
291 if BuildData
.MetaFile
in Platform
.Modules
:
292 PlatformModule
= Platform
.Modules
[str(BuildData
.MetaFile
)]
293 if key
in PlatformModule
.Pcds
:
294 PcdInPlatform
= PlatformModule
.Pcds
[key
]
295 if PcdInPlatform
.Type
:
296 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
297 BuildData
.Pcds
[key
].Pending
= False
299 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
300 if BuildData
.Pcds
[key
].Pending
:
301 if bool(BuildData
.LibraryClass
):
302 if BuildData
in set(Libs
):
303 ReferenceModules
= BuildData
.ReferenceModules
304 for ReferenceModule
in ReferenceModules
:
305 if ReferenceModule
.MetaFile
in Platform
.Modules
:
306 RefPlatformModule
= Platform
.Modules
[str(ReferenceModule
.MetaFile
)]
307 if key
in RefPlatformModule
.Pcds
:
308 PcdInReferenceModule
= RefPlatformModule
.Pcds
[key
]
309 if PcdInReferenceModule
.Type
:
310 BuildData
.Pcds
[key
].Type
= PcdInReferenceModule
.Type
311 BuildData
.Pcds
[key
].Pending
= False
314 def ProcessMixedPcd(self
):
315 for Arch
in self
.ArchList
:
316 SourcePcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set(),TAB_PCDS_DYNAMIC
:set(),TAB_PCDS_FIXED_AT_BUILD
:set()}
317 BinaryPcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set()}
318 SourcePcdDict_Keys
= SourcePcdDict
.keys()
319 BinaryPcdDict_Keys
= BinaryPcdDict
.keys()
321 # generate the SourcePcdDict and BinaryPcdDict
323 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
324 if BuildData
.Arch
!= Arch
:
326 if BuildData
.MetaFile
.Ext
== '.inf':
327 for key
in BuildData
.Pcds
:
328 if TAB_PCDS_DYNAMIC_EX
in BuildData
.Pcds
[key
].Type
:
329 if BuildData
.IsBinaryModule
:
330 BinaryPcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
332 SourcePcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
334 elif TAB_PCDS_PATCHABLE_IN_MODULE
in BuildData
.Pcds
[key
].Type
:
335 if BuildData
.MetaFile
.Ext
== '.inf':
336 if BuildData
.IsBinaryModule
:
337 BinaryPcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
339 SourcePcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
341 elif TAB_PCDS_DYNAMIC
in BuildData
.Pcds
[key
].Type
:
342 SourcePcdDict
[TAB_PCDS_DYNAMIC
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
343 elif TAB_PCDS_FIXED_AT_BUILD
in BuildData
.Pcds
[key
].Type
:
344 SourcePcdDict
[TAB_PCDS_FIXED_AT_BUILD
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
347 # A PCD can only use one type for all source modules
349 for i
in SourcePcdDict_Keys
:
350 for j
in SourcePcdDict_Keys
:
352 Intersections
= SourcePcdDict
[i
].intersection(SourcePcdDict
[j
])
353 if len(Intersections
) > 0:
357 "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
),
358 ExtraData
='\n\t'.join(str(P
[1]+'.'+P
[0]) for P
in Intersections
)
362 # intersection the BinaryPCD for Mixed PCD
364 for i
in BinaryPcdDict_Keys
:
365 for j
in BinaryPcdDict_Keys
:
367 Intersections
= BinaryPcdDict
[i
].intersection(BinaryPcdDict
[j
])
368 for item
in Intersections
:
369 NewPcd1
= (item
[0] + '_' + i
, item
[1])
370 NewPcd2
= (item
[0] + '_' + j
, item
[1])
371 if item
not in GlobalData
.MixedPcd
:
372 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
374 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
375 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
376 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
377 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
380 # intersection the SourcePCD and BinaryPCD for Mixed PCD
382 for i
in SourcePcdDict_Keys
:
383 for j
in BinaryPcdDict_Keys
:
385 Intersections
= SourcePcdDict
[i
].intersection(BinaryPcdDict
[j
])
386 for item
in Intersections
:
387 NewPcd1
= (item
[0] + '_' + i
, item
[1])
388 NewPcd2
= (item
[0] + '_' + j
, item
[1])
389 if item
not in GlobalData
.MixedPcd
:
390 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
392 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
393 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
394 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
395 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
397 BuildData
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
398 for key
in BuildData
.Pcds
:
399 for SinglePcd
in GlobalData
.MixedPcd
:
400 if (BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
) == SinglePcd
:
401 for item
in GlobalData
.MixedPcd
[SinglePcd
]:
402 Pcd_Type
= item
[0].split('_')[-1]
403 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 \
404 (Pcd_Type
== TAB_PCDS_DYNAMIC
and BuildData
.Pcds
[key
].Type
in PCD_DYNAMIC_TYPE_SET
):
405 Value
= BuildData
.Pcds
[key
]
406 Value
.TokenCName
= BuildData
.Pcds
[key
].TokenCName
+ '_' + Pcd_Type
408 newkey
= (Value
.TokenCName
, key
[1])
410 newkey
= (Value
.TokenCName
, key
[1], key
[2])
411 del BuildData
.Pcds
[key
]
412 BuildData
.Pcds
[newkey
] = Value
417 PcdSet
= self
.FdfProfile
.PcdDict
418 # handle the mixed pcd in FDF file
420 if key
in GlobalData
.MixedPcd
:
423 for item
in GlobalData
.MixedPcd
[key
]:
426 #Collect package set information from INF of FDF
430 self
.FdfFile
= self
.Platform
.FlashDefinition
433 ModuleList
= self
.FdfProfile
.InfList
437 for Arch
in self
.ArchList
:
438 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
440 for mb
in [self
.BuildDatabase
[m
, Arch
, self
.BuildTarget
, self
.ToolChain
] for m
in Platform
.Modules
]:
441 PkgSet
.update(mb
.Packages
)
442 for Inf
in ModuleList
:
443 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
444 if ModuleFile
in Platform
.Modules
:
446 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
447 PkgSet
.update(ModuleData
.Packages
)
448 PkgSet
.update(Platform
.Packages
)
449 Pkgs
[Arch
] = list(PkgSet
)
452 def VerifyPcdDeclearation(self
,PcdSet
):
453 for Arch
in self
.ArchList
:
454 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
455 Pkgs
= self
.PkgSet
[Arch
]
460 DecPcds
.add((Pcd
[0], Pcd
[1]))
461 DecPcdsKey
.add((Pcd
[0], Pcd
[1], Pcd
[2]))
463 Platform
.SkuName
= self
.SkuId
464 for Name
, Guid
,Fileds
in PcdSet
:
465 if (Name
, Guid
) not in DecPcds
:
469 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid
, Name
),
470 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
471 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
474 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
475 if (Name
, Guid
, TAB_PCDS_FIXED_AT_BUILD
) in DecPcdsKey \
476 or (Name
, Guid
, TAB_PCDS_PATCHABLE_IN_MODULE
) in DecPcdsKey \
477 or (Name
, Guid
, TAB_PCDS_FEATURE_FLAG
) in DecPcdsKey
:
479 elif (Name
, Guid
, TAB_PCDS_DYNAMIC
) in DecPcdsKey
or (Name
, Guid
, TAB_PCDS_DYNAMIC_EX
) in DecPcdsKey
:
483 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid
, Name
),
484 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
485 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
487 def CollectAllPcds(self
):
489 for Arch
in self
.ArchList
:
490 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
492 # Explicitly collect platform's dynamic PCDs
494 Pa
.CollectPlatformDynamicPcds()
495 Pa
.CollectFixedAtBuildPcds()
496 self
.AutoGenObjectList
.append(Pa
)
497 # We need to calculate the PcdTokenNumber after all Arch Pcds are collected.
498 for Arch
in self
.ArchList
:
500 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
501 self
.UpdateModuleDataPipe(Arch
, {"PCD_TNUM":Pa
.PcdTokenNumber
})
503 def UpdateModuleDataPipe(self
,arch
, attr_dict
):
504 for (Target
, Toolchain
, Arch
, MetaFile
) in AutoGen
.Cache():
508 AutoGen
.Cache()[(Target
, Toolchain
, Arch
, MetaFile
)].DataPipe
.DataContainer
= attr_dict
512 # Generate Package level hash value
514 def GeneratePkgLevelHash(self
):
515 for Arch
in self
.ArchList
:
516 GlobalData
.gPackageHash
= {}
517 if GlobalData
.gUseHashCache
:
518 for Pkg
in self
.PkgSet
[Arch
]:
519 self
._GenPkgLevelHash
(Pkg
)
522 def CreateBuildOptionsFile(self
):
524 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
526 content
= 'gCommandLineDefines: '
527 content
+= str(GlobalData
.gCommandLineDefines
)
528 content
+= TAB_LINE_BREAK
529 content
+= 'BuildOptionPcd: '
530 content
+= str(GlobalData
.BuildOptionPcd
)
531 content
+= TAB_LINE_BREAK
532 content
+= 'Active Platform: '
533 content
+= str(self
.Platform
)
534 content
+= TAB_LINE_BREAK
536 content
+= 'Flash Image Definition: '
537 content
+= str(self
.FdfFile
)
538 content
+= TAB_LINE_BREAK
539 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'BuildOptions'), content
, False)
541 def CreatePcdTokenNumberFile(self
):
543 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
545 PcdTokenNumber
= 'PcdTokenNumber: '
546 Pa
= self
.AutoGenObjectList
[0]
547 if Pa
.PcdTokenNumber
:
548 if Pa
.DynamicPcdList
:
549 for Pcd
in Pa
.DynamicPcdList
:
550 PcdTokenNumber
+= TAB_LINE_BREAK
551 PcdTokenNumber
+= str((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
552 PcdTokenNumber
+= ' : '
553 PcdTokenNumber
+= str(Pa
.PcdTokenNumber
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
])
554 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'), PcdTokenNumber
, False)
556 def GeneratePlatformLevelHash(self
):
558 # Get set of workspace metafiles
560 AllWorkSpaceMetaFiles
= self
._GetMetaFiles
(self
.BuildTarget
, self
.ToolChain
)
561 AllWorkSpaceMetaFileList
= sorted(AllWorkSpaceMetaFiles
, key
=lambda x
: str(x
))
563 # Retrieve latest modified time of all metafiles
566 for f
in AllWorkSpaceMetaFiles
:
567 if os
.stat(f
)[8] > SrcTimeStamp
:
568 SrcTimeStamp
= os
.stat(f
)[8]
569 self
._SrcTimeStamp
= SrcTimeStamp
571 if GlobalData
.gUseHashCache
:
574 for file in AllWorkSpaceMetaFileList
:
575 if file.endswith('.dec'):
581 FileList
.append((str(file), hashlib
.md5(Content
).hexdigest()))
583 HashDir
= path
.join(self
.BuildDir
, "Hash_Platform")
584 HashFile
= path
.join(HashDir
, 'Platform.hash.' + m
.hexdigest())
585 SaveFileOnChange(HashFile
, m
.hexdigest(), False)
586 HashChainFile
= path
.join(HashDir
, 'Platform.hashchain.' + m
.hexdigest())
587 GlobalData
.gPlatformHashFile
= HashChainFile
589 with
open(HashChainFile
, 'w') as f
:
590 json
.dump(FileList
, f
, indent
=2)
592 EdkLogger
.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile
)
594 if GlobalData
.gBinCacheDest
:
595 # Copy platform hash files to cache destination
596 FileDir
= path
.join(GlobalData
.gBinCacheDest
, self
.OutputDir
, self
.BuildTarget
+ "_" + self
.ToolChain
, "Hash_Platform")
597 CacheFileDir
= FileDir
598 CreateDirectory(CacheFileDir
)
599 CopyFileOnChange(HashFile
, CacheFileDir
)
600 CopyFileOnChange(HashChainFile
, CacheFileDir
)
603 # Write metafile list to build directory
605 AutoGenFilePath
= os
.path
.join(self
.BuildDir
, 'AutoGen')
606 if os
.path
.exists (AutoGenFilePath
):
607 os
.remove(AutoGenFilePath
)
608 if not os
.path
.exists(self
.BuildDir
):
609 os
.makedirs(self
.BuildDir
)
610 with
open(os
.path
.join(self
.BuildDir
, 'AutoGen'), 'w+') as file:
611 for f
in AllWorkSpaceMetaFileList
:
615 def _GenPkgLevelHash(self
, Pkg
):
616 if Pkg
.PackageName
in GlobalData
.gPackageHash
:
619 PkgDir
= os
.path
.join(self
.BuildDir
, Pkg
.Arch
, "Hash_Pkg", Pkg
.PackageName
)
620 CreateDirectory(PkgDir
)
623 # Get .dec file's hash value
624 f
= open(Pkg
.MetaFile
.Path
, 'rb')
628 FileList
.append((str(Pkg
.MetaFile
.Path
), hashlib
.md5(Content
).hexdigest()))
629 # Get include files hash value
631 for inc
in sorted(Pkg
.Includes
, key
=lambda x
: str(x
)):
632 for Root
, Dirs
, Files
in os
.walk(str(inc
)):
633 for File
in sorted(Files
):
634 File_Path
= os
.path
.join(Root
, File
)
635 f
= open(File_Path
, 'rb')
639 FileList
.append((str(File_Path
), hashlib
.md5(Content
).hexdigest()))
640 GlobalData
.gPackageHash
[Pkg
.PackageName
] = m
.hexdigest()
643 HashFile
= path
.join(HashDir
, Pkg
.PackageName
+ '.hash.' + m
.hexdigest())
644 SaveFileOnChange(HashFile
, m
.hexdigest(), False)
645 HashChainFile
= path
.join(HashDir
, Pkg
.PackageName
+ '.hashchain.' + m
.hexdigest())
646 GlobalData
.gPackageHashFile
[(Pkg
.PackageName
, Pkg
.Arch
)] = HashChainFile
648 with
open(HashChainFile
, 'w') as f
:
649 json
.dump(FileList
, f
, indent
=2)
651 EdkLogger
.quiet("[cache warning]: fail to save hashchain file:%s" % HashChainFile
)
653 if GlobalData
.gBinCacheDest
:
654 # Copy Pkg hash files to cache destination dir
655 FileDir
= path
.join(GlobalData
.gBinCacheDest
, self
.OutputDir
, self
.BuildTarget
+ "_" + self
.ToolChain
, Pkg
.Arch
, "Hash_Pkg", Pkg
.PackageName
)
656 CacheFileDir
= FileDir
657 CreateDirectory(CacheFileDir
)
658 CopyFileOnChange(HashFile
, CacheFileDir
)
659 CopyFileOnChange(HashChainFile
, CacheFileDir
)
661 def _GetMetaFiles(self
, Target
, Toolchain
):
662 AllWorkSpaceMetaFiles
= set()
667 AllWorkSpaceMetaFiles
.add (self
.FdfFile
.Path
)
668 for f
in GlobalData
.gFdfParser
.GetAllIncludedFile():
669 AllWorkSpaceMetaFiles
.add (f
.FileName
)
673 AllWorkSpaceMetaFiles
.add(self
.MetaFile
.Path
)
676 # add build_rule.txt & tools_def.txt
678 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultBuildRuleFile
))
679 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultToolsDefFile
))
681 # add BuildOption metafile
683 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'BuildOptions'))
685 # add PcdToken Number file for Dynamic/DynamicEx Pcd
687 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'))
689 for Pa
in self
.AutoGenObjectList
:
690 AllWorkSpaceMetaFiles
.add(Pa
.ToolDefinitionFile
)
692 for Arch
in self
.ArchList
:
696 for Package
in PlatformAutoGen(self
, self
.MetaFile
, Target
, Toolchain
, Arch
).PackageList
:
697 AllWorkSpaceMetaFiles
.add(Package
.MetaFile
.Path
)
702 for filePath
in self
.BuildDatabase
[self
.MetaFile
, Arch
, Target
, Toolchain
]._RawData
.IncludedFiles
:
703 AllWorkSpaceMetaFiles
.add(filePath
.Path
)
705 return AllWorkSpaceMetaFiles
707 def _CheckPcdDefineAndType(self
):
708 PcdTypeSet
= {TAB_PCDS_FIXED_AT_BUILD
,
709 TAB_PCDS_PATCHABLE_IN_MODULE
,
710 TAB_PCDS_FEATURE_FLAG
,
714 # This dict store PCDs which are not used by any modules with specified arches
715 UnusedPcd
= OrderedDict()
716 for Pa
in self
.AutoGenObjectList
:
717 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
718 for Pcd
in Pa
.Platform
.Pcds
:
719 PcdType
= Pa
.Platform
.Pcds
[Pcd
].Type
721 # If no PCD type, this PCD comes from FDF
725 # Try to remove Hii and Vpd suffix
726 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
727 PcdType
= TAB_PCDS_DYNAMIC_EX
728 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
729 PcdType
= TAB_PCDS_DYNAMIC
731 for Package
in Pa
.PackageList
:
732 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
733 if (Pcd
[0], Pcd
[1], PcdType
) in Package
.Pcds
:
735 for Type
in PcdTypeSet
:
736 if (Pcd
[0], Pcd
[1], Type
) in Package
.Pcds
:
740 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
741 % (Pa
.Platform
.Pcds
[Pcd
].Type
, Pcd
[1], Pcd
[0], Type
),
746 UnusedPcd
.setdefault(Pcd
, []).append(Pa
.Arch
)
748 for Pcd
in UnusedPcd
:
751 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
752 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
753 % (Pcd
[1], Pcd
[0], os
.path
.basename(str(self
.MetaFile
)), str(UnusedPcd
[Pcd
])),
758 return "%s [%s]" % (self
.MetaFile
, ", ".join(self
.ArchList
))
760 ## Return the directory to store FV files
763 return path
.join(self
.BuildDir
, TAB_FV_DIRECTORY
)
765 ## Return the directory to store all intermediate and final files built
768 return self
.AutoGenObjectList
[0].BuildDir
770 ## Return the build output directory platform specifies
773 return self
.Platform
.OutputDirectory
775 ## Return platform name
778 return self
.Platform
.PlatformName
780 ## Return meta-file GUID
783 return self
.Platform
.Guid
785 ## Return platform version
788 return self
.Platform
.Version
790 ## Return paths of tools
792 def ToolDefinition(self
):
793 return self
.AutoGenObjectList
[0].ToolDefinition
795 ## Return directory of platform makefile
797 # @retval string Makefile directory
800 def MakeFileDir(self
):
803 ## Return build command string
805 # @retval string Build command string
808 def BuildCommand(self
):
809 # BuildCommand should be all the same. So just get one from platform AutoGen
810 return self
.AutoGenObjectList
[0].BuildCommand
812 ## Check the PCDs token value conflict in each DEC file.
814 # Will cause build break and raise error message while two PCDs conflict.
818 def _CheckAllPcdsTokenValueConflict(self
):
819 for Pa
in self
.AutoGenObjectList
:
820 for Package
in Pa
.PackageList
:
821 PcdList
= list(Package
.Pcds
.values())
822 PcdList
.sort(key
=lambda x
: int(x
.TokenValue
, 0))
824 while (Count
< len(PcdList
) - 1) :
825 Item
= PcdList
[Count
]
826 ItemNext
= PcdList
[Count
+ 1]
828 # Make sure in the same token space the TokenValue should be unique
830 if (int(Item
.TokenValue
, 0) == int(ItemNext
.TokenValue
, 0)):
831 SameTokenValuePcdList
= []
832 SameTokenValuePcdList
.append(Item
)
833 SameTokenValuePcdList
.append(ItemNext
)
834 RemainPcdListLength
= len(PcdList
) - Count
- 2
835 for ValueSameCount
in range(RemainPcdListLength
):
836 if int(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
].TokenValue
, 0) == int(Item
.TokenValue
, 0):
837 SameTokenValuePcdList
.append(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
])
841 # Sort same token value PCD list with TokenGuid and TokenCName
843 SameTokenValuePcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
844 SameTokenValuePcdListCount
= 0
845 while (SameTokenValuePcdListCount
< len(SameTokenValuePcdList
) - 1):
847 TemListItem
= SameTokenValuePcdList
[SameTokenValuePcdListCount
]
848 TemListItemNext
= SameTokenValuePcdList
[SameTokenValuePcdListCount
+ 1]
850 if (TemListItem
.TokenSpaceGuidCName
== TemListItemNext
.TokenSpaceGuidCName
) and (TemListItem
.TokenCName
!= TemListItemNext
.TokenCName
):
851 for PcdItem
in GlobalData
.MixedPcd
:
852 if (TemListItem
.TokenCName
, TemListItem
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
] or \
853 (TemListItemNext
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
]:
859 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
860 % (TemListItem
.TokenValue
, TemListItem
.TokenSpaceGuidCName
, TemListItem
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
, TemListItemNext
.TokenCName
, Package
),
863 SameTokenValuePcdListCount
+= 1
864 Count
+= SameTokenValuePcdListCount
867 PcdList
= list(Package
.Pcds
.values())
868 PcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
870 while (Count
< len(PcdList
) - 1) :
871 Item
= PcdList
[Count
]
872 ItemNext
= PcdList
[Count
+ 1]
874 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
876 if (Item
.TokenSpaceGuidCName
== ItemNext
.TokenSpaceGuidCName
) and (Item
.TokenCName
== ItemNext
.TokenCName
) and (int(Item
.TokenValue
, 0) != int(ItemNext
.TokenValue
, 0)):
880 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
881 % (Item
.TokenValue
, Item
.TokenSpaceGuidCName
, Item
.TokenCName
, Package
),
885 ## Generate fds command
887 def GenFdsCommand(self
):
888 return (GenMake
.TopLevelMakefile(self
)._TEMPLATE
_.Replace(GenMake
.TopLevelMakefile(self
)._TemplateDict
)).strip()
891 def GenFdsCommandDict(self
):
893 LogLevel
= EdkLogger
.GetLevel()
894 if LogLevel
== EdkLogger
.VERBOSE
:
895 FdsCommandDict
["verbose"] = True
896 elif LogLevel
<= EdkLogger
.DEBUG_9
:
897 FdsCommandDict
["debug"] = LogLevel
- 1
898 elif LogLevel
== EdkLogger
.QUIET
:
899 FdsCommandDict
["quiet"] = True
901 FdsCommandDict
["GenfdsMultiThread"] = GlobalData
.gEnableGenfdsMultiThread
902 if GlobalData
.gIgnoreSource
:
903 FdsCommandDict
["IgnoreSources"] = True
905 FdsCommandDict
["OptionPcd"] = []
906 for pcd
in GlobalData
.BuildOptionPcd
:
908 pcdname
= '.'.join(pcd
[0:3])
910 pcdname
= '.'.join(pcd
[0:2])
911 if pcd
[3].startswith('{'):
912 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + 'H' + '"' + pcd
[3] + '"')
914 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + pcd
[3])
917 # macros passed to GenFds
919 MacroDict
.update(GlobalData
.gGlobalDefines
)
920 MacroDict
.update(GlobalData
.gCommandLineDefines
)
921 for MacroName
in MacroDict
:
922 if MacroDict
[MacroName
] != "":
923 MacroList
.append('"%s=%s"' % (MacroName
, MacroDict
[MacroName
].replace('\\', '\\\\')))
925 MacroList
.append('"%s"' % MacroName
)
926 FdsCommandDict
["macro"] = MacroList
928 FdsCommandDict
["fdf_file"] = [self
.FdfFile
]
929 FdsCommandDict
["build_target"] = self
.BuildTarget
930 FdsCommandDict
["toolchain_tag"] = self
.ToolChain
931 FdsCommandDict
["active_platform"] = str(self
)
933 FdsCommandDict
["conf_directory"] = GlobalData
.gConfDirectory
934 FdsCommandDict
["build_architecture_list"] = ','.join(self
.ArchList
)
935 FdsCommandDict
["platform_build_directory"] = self
.BuildDir
937 FdsCommandDict
["fd"] = self
.FdTargetList
938 FdsCommandDict
["fv"] = self
.FvTargetList
939 FdsCommandDict
["cap"] = self
.CapTargetList
940 return FdsCommandDict
942 ## Create makefile for the platform and modules in it
944 # @param CreateDepsMakeFile Flag indicating if the makefile for
945 # modules will be created as well
947 def CreateMakeFile(self
, CreateDepsMakeFile
=False):
948 if not CreateDepsMakeFile
:
950 for Pa
in self
.AutoGenObjectList
:
951 Pa
.CreateMakeFile(CreateDepsMakeFile
)
953 ## Create autogen code for platform and modules
955 # Since there's no autogen code for platform, this method will do nothing
956 # if CreateModuleCodeFile is set to False.
958 # @param CreateDepsCodeFile Flag indicating if creating module's
959 # autogen code file or not
961 def CreateCodeFile(self
, CreateDepsCodeFile
=False):
962 if not CreateDepsCodeFile
:
964 for Pa
in self
.AutoGenObjectList
:
965 Pa
.CreateCodeFile(CreateDepsCodeFile
)
967 ## Create AsBuilt INF file the platform
969 def CreateAsBuiltInf(self
):