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 *
27 ## Regular expression for splitting Dependency Expression string into tokens
28 gDepexTokenPattern
= re
.compile("(\(|\)|\w+| \S+\.inf)")
30 ## Regular expression for match: PCD(xxxx.yyy)
31 gPCDAsGuidPattern
= re
.compile(r
"^PCD\(.+\..+\)$")
33 ## Workspace AutoGen class
35 # This class is used mainly to control the whole platform build for different
36 # architecture. This class will generate top level makefile.
38 class WorkspaceAutoGen(AutoGen
):
39 # call super().__init__ then call the worker function with different parameter count
40 def __init__(self
, Workspace
, MetaFile
, Target
, Toolchain
, Arch
, *args
, **kwargs
):
41 if not hasattr(self
, "_Init"):
42 self
._InitWorker
(Workspace
, MetaFile
, Target
, Toolchain
, Arch
, *args
, **kwargs
)
45 ## Initialize WorkspaceAutoGen
47 # @param WorkspaceDir Root directory of workspace
48 # @param ActivePlatform Meta-file of active platform
49 # @param Target Build target
50 # @param Toolchain Tool chain name
51 # @param ArchList List of architecture of current build
52 # @param MetaFileDb Database containing meta-files
53 # @param BuildConfig Configuration of build
54 # @param ToolDefinition Tool chain definitions
55 # @param FlashDefinitionFile File of flash definition
56 # @param Fds FD list to be generated
57 # @param Fvs FV list to be generated
58 # @param Caps Capsule list to be generated
59 # @param SkuId SKU id from command line
61 def _InitWorker(self
, WorkspaceDir
, ActivePlatform
, Target
, Toolchain
, ArchList
, MetaFileDb
,
62 BuildConfig
, ToolDefinition
, FlashDefinitionFile
='', Fds
=None, Fvs
=None, Caps
=None, SkuId
='', UniFlag
=None,
63 Progress
=None, BuildModule
=None):
64 self
.BuildDatabase
= MetaFileDb
65 self
.MetaFile
= ActivePlatform
66 self
.WorkspaceDir
= WorkspaceDir
67 self
.Platform
= self
.BuildDatabase
[self
.MetaFile
, TAB_ARCH_COMMON
, Target
, Toolchain
]
68 GlobalData
.gActivePlatform
= self
.Platform
69 self
.BuildTarget
= Target
70 self
.ToolChain
= Toolchain
71 self
.ArchList
= ArchList
73 self
.UniFlag
= UniFlag
75 self
.TargetTxt
= BuildConfig
76 self
.ToolDef
= ToolDefinition
77 self
.FdfFile
= FlashDefinitionFile
78 self
.FdTargetList
= Fds
if Fds
else []
79 self
.FvTargetList
= Fvs
if Fvs
else []
80 self
.CapTargetList
= Caps
if Caps
else []
81 self
.AutoGenObjectList
= []
84 # there's many relative directory operations, so ...
85 os
.chdir(self
.WorkspaceDir
)
88 self
.ValidateBuildTarget()
92 EdkLogger
.info('%-16s = %s' % ("Architecture(s)", ' '.join(self
.ArchList
)))
93 EdkLogger
.info('%-16s = %s' % ("Build target", self
.BuildTarget
))
94 EdkLogger
.info('%-16s = %s' % ("Toolchain", self
.ToolChain
))
96 EdkLogger
.info('\n%-24s = %s' % ("Active Platform", self
.Platform
))
98 EdkLogger
.info('%-24s = %s' % ("Active Module", BuildModule
))
101 EdkLogger
.info('%-24s = %s' % ("Flash Image Definition", self
.FdfFile
))
103 EdkLogger
.verbose("\nFLASH_DEFINITION = %s" % self
.FdfFile
)
106 Progress
.Start("\nProcessing meta-data")
108 # Mark now build in AutoGen Phase
110 GlobalData
.gAutoGenPhase
= True
111 self
.ProcessModuleFromPdf()
112 self
.ProcessPcdType()
113 self
.ProcessMixedPcd()
114 self
.VerifyPcdsFromFDF()
115 self
.CollectAllPcds()
116 for Pa
in self
.AutoGenObjectList
:
117 Pa
.FillData_LibConstPcd()
118 self
.GeneratePkgLevelHash()
120 # Check PCDs token value conflict in each DEC file.
122 self
._CheckAllPcdsTokenValueConflict
()
124 # Check PCD type and definition between DSC and DEC
126 self
._CheckPcdDefineAndType
()
128 self
.CreateBuildOptionsFile()
129 self
.CreatePcdTokenNumberFile()
130 self
.CreateModuleHashInfo()
131 GlobalData
.gAutoGenPhase
= False
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
) is '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
,
253 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
254 if BuildData
.Arch
!= Arch
:
256 if BuildData
.MetaFile
.Ext
== '.inf':
257 for key
in BuildData
.Pcds
:
258 if BuildData
.Pcds
[key
].Pending
:
259 if key
in Platform
.Pcds
:
260 PcdInPlatform
= Platform
.Pcds
[key
]
261 if PcdInPlatform
.Type
:
262 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
263 BuildData
.Pcds
[key
].Pending
= False
265 if BuildData
.MetaFile
in Platform
.Modules
:
266 PlatformModule
= Platform
.Modules
[str(BuildData
.MetaFile
)]
267 if key
in PlatformModule
.Pcds
:
268 PcdInPlatform
= PlatformModule
.Pcds
[key
]
269 if PcdInPlatform
.Type
:
270 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
271 BuildData
.Pcds
[key
].Pending
= False
273 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
274 if BuildData
.Pcds
[key
].Pending
:
275 if bool(BuildData
.LibraryClass
):
276 if BuildData
in set(Libs
):
277 ReferenceModules
= BuildData
.ReferenceModules
278 for ReferenceModule
in ReferenceModules
:
279 if ReferenceModule
.MetaFile
in Platform
.Modules
:
280 RefPlatformModule
= Platform
.Modules
[str(ReferenceModule
.MetaFile
)]
281 if key
in RefPlatformModule
.Pcds
:
282 PcdInReferenceModule
= RefPlatformModule
.Pcds
[key
]
283 if PcdInReferenceModule
.Type
:
284 BuildData
.Pcds
[key
].Type
= PcdInReferenceModule
.Type
285 BuildData
.Pcds
[key
].Pending
= False
288 def ProcessMixedPcd(self
):
289 for Arch
in self
.ArchList
:
290 SourcePcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set(),TAB_PCDS_DYNAMIC
:set(),TAB_PCDS_FIXED_AT_BUILD
:set()}
291 BinaryPcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set()}
292 SourcePcdDict_Keys
= SourcePcdDict
.keys()
293 BinaryPcdDict_Keys
= BinaryPcdDict
.keys()
295 # generate the SourcePcdDict and BinaryPcdDict
297 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
298 if BuildData
.Arch
!= Arch
:
300 if BuildData
.MetaFile
.Ext
== '.inf':
301 for key
in BuildData
.Pcds
:
302 if TAB_PCDS_DYNAMIC_EX
in BuildData
.Pcds
[key
].Type
:
303 if BuildData
.IsBinaryModule
:
304 BinaryPcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
306 SourcePcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
308 elif TAB_PCDS_PATCHABLE_IN_MODULE
in BuildData
.Pcds
[key
].Type
:
309 if BuildData
.MetaFile
.Ext
== '.inf':
310 if BuildData
.IsBinaryModule
:
311 BinaryPcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
313 SourcePcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
315 elif TAB_PCDS_DYNAMIC
in BuildData
.Pcds
[key
].Type
:
316 SourcePcdDict
[TAB_PCDS_DYNAMIC
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
317 elif TAB_PCDS_FIXED_AT_BUILD
in BuildData
.Pcds
[key
].Type
:
318 SourcePcdDict
[TAB_PCDS_FIXED_AT_BUILD
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
321 # A PCD can only use one type for all source modules
323 for i
in SourcePcdDict_Keys
:
324 for j
in SourcePcdDict_Keys
:
326 Intersections
= SourcePcdDict
[i
].intersection(SourcePcdDict
[j
])
327 if len(Intersections
) > 0:
331 "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
),
332 ExtraData
='\n\t'.join(str(P
[1]+'.'+P
[0]) for P
in Intersections
)
336 # intersection the BinaryPCD for Mixed PCD
338 for i
in BinaryPcdDict_Keys
:
339 for j
in BinaryPcdDict_Keys
:
341 Intersections
= BinaryPcdDict
[i
].intersection(BinaryPcdDict
[j
])
342 for item
in Intersections
:
343 NewPcd1
= (item
[0] + '_' + i
, item
[1])
344 NewPcd2
= (item
[0] + '_' + j
, item
[1])
345 if item
not in GlobalData
.MixedPcd
:
346 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
348 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
349 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
350 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
351 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
354 # intersection the SourcePCD and BinaryPCD for Mixed PCD
356 for i
in SourcePcdDict_Keys
:
357 for j
in BinaryPcdDict_Keys
:
359 Intersections
= SourcePcdDict
[i
].intersection(BinaryPcdDict
[j
])
360 for item
in Intersections
:
361 NewPcd1
= (item
[0] + '_' + i
, item
[1])
362 NewPcd2
= (item
[0] + '_' + j
, item
[1])
363 if item
not in GlobalData
.MixedPcd
:
364 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
366 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
367 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
368 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
369 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
371 BuildData
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
372 for key
in BuildData
.Pcds
:
373 for SinglePcd
in GlobalData
.MixedPcd
:
374 if (BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
) == SinglePcd
:
375 for item
in GlobalData
.MixedPcd
[SinglePcd
]:
376 Pcd_Type
= item
[0].split('_')[-1]
377 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 \
378 (Pcd_Type
== TAB_PCDS_DYNAMIC
and BuildData
.Pcds
[key
].Type
in PCD_DYNAMIC_TYPE_SET
):
379 Value
= BuildData
.Pcds
[key
]
380 Value
.TokenCName
= BuildData
.Pcds
[key
].TokenCName
+ '_' + Pcd_Type
382 newkey
= (Value
.TokenCName
, key
[1])
384 newkey
= (Value
.TokenCName
, key
[1], key
[2])
385 del BuildData
.Pcds
[key
]
386 BuildData
.Pcds
[newkey
] = Value
391 PcdSet
= self
.FdfProfile
.PcdDict
392 # handle the mixed pcd in FDF file
394 if key
in GlobalData
.MixedPcd
:
397 for item
in GlobalData
.MixedPcd
[key
]:
400 #Collect package set information from INF of FDF
404 self
.FdfFile
= self
.Platform
.FlashDefinition
407 ModuleList
= self
.FdfProfile
.InfList
411 for Arch
in self
.ArchList
:
412 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
414 for mb
in [self
.BuildDatabase
[m
, Arch
, self
.BuildTarget
, self
.ToolChain
] for m
in Platform
.Modules
]:
415 PkgSet
.update(mb
.Packages
)
416 for Inf
in ModuleList
:
417 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
418 if ModuleFile
in Platform
.Modules
:
420 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
421 PkgSet
.update(ModuleData
.Packages
)
422 Pkgs
[Arch
] = list(PkgSet
)
425 def VerifyPcdDeclearation(self
,PcdSet
):
426 for Arch
in self
.ArchList
:
427 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
428 Pkgs
= self
.PkgSet
[Arch
]
433 DecPcds
.add((Pcd
[0], Pcd
[1]))
434 DecPcdsKey
.add((Pcd
[0], Pcd
[1], Pcd
[2]))
436 Platform
.SkuName
= self
.SkuId
437 for Name
, Guid
,Fileds
in PcdSet
:
438 if (Name
, Guid
) not in DecPcds
:
442 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid
, Name
),
443 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
444 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
447 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
448 if (Name
, Guid
, TAB_PCDS_FIXED_AT_BUILD
) in DecPcdsKey \
449 or (Name
, Guid
, TAB_PCDS_PATCHABLE_IN_MODULE
) in DecPcdsKey \
450 or (Name
, Guid
, TAB_PCDS_FEATURE_FLAG
) in DecPcdsKey
:
452 elif (Name
, Guid
, TAB_PCDS_DYNAMIC
) in DecPcdsKey
or (Name
, Guid
, TAB_PCDS_DYNAMIC_EX
) in DecPcdsKey
:
456 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid
, Name
),
457 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
458 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
460 def CollectAllPcds(self
):
462 for Arch
in self
.ArchList
:
463 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
465 # Explicitly collect platform's dynamic PCDs
467 Pa
.CollectPlatformDynamicPcds()
468 Pa
.CollectFixedAtBuildPcds()
469 self
.AutoGenObjectList
.append(Pa
)
470 # We need to calculate the PcdTokenNumber after all Arch Pcds are collected.
471 for Arch
in self
.ArchList
:
473 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
474 self
.UpdateModuleDataPipe(Arch
, {"PCD_TNUM":Pa
.PcdTokenNumber
})
476 def UpdateModuleDataPipe(self
,arch
, attr_dict
):
477 for (Target
, Toolchain
, Arch
, MetaFile
) in AutoGen
.Cache():
481 AutoGen
.Cache()[(Target
, Toolchain
, Arch
, MetaFile
)].DataPipe
.DataContainer
= attr_dict
485 # Generate Package level hash value
487 def GeneratePkgLevelHash(self
):
488 for Arch
in self
.ArchList
:
489 GlobalData
.gPackageHash
= {}
490 if GlobalData
.gUseHashCache
:
491 for Pkg
in self
.PkgSet
[Arch
]:
492 self
._GenPkgLevelHash
(Pkg
)
495 def CreateBuildOptionsFile(self
):
497 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
499 content
= 'gCommandLineDefines: '
500 content
+= str(GlobalData
.gCommandLineDefines
)
501 content
+= TAB_LINE_BREAK
502 content
+= 'BuildOptionPcd: '
503 content
+= str(GlobalData
.BuildOptionPcd
)
504 content
+= TAB_LINE_BREAK
505 content
+= 'Active Platform: '
506 content
+= str(self
.Platform
)
507 content
+= TAB_LINE_BREAK
509 content
+= 'Flash Image Definition: '
510 content
+= str(self
.FdfFile
)
511 content
+= TAB_LINE_BREAK
512 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'BuildOptions'), content
, False)
514 def CreatePcdTokenNumberFile(self
):
516 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
518 PcdTokenNumber
= 'PcdTokenNumber: '
519 Pa
= self
.AutoGenObjectList
[0]
520 if Pa
.PcdTokenNumber
:
521 if Pa
.DynamicPcdList
:
522 for Pcd
in Pa
.DynamicPcdList
:
523 PcdTokenNumber
+= TAB_LINE_BREAK
524 PcdTokenNumber
+= str((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
525 PcdTokenNumber
+= ' : '
526 PcdTokenNumber
+= str(Pa
.PcdTokenNumber
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
])
527 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'), PcdTokenNumber
, False)
529 def CreateModuleHashInfo(self
):
531 # Get set of workspace metafiles
533 AllWorkSpaceMetaFiles
= self
._GetMetaFiles
(self
.BuildTarget
, self
.ToolChain
)
536 # Retrieve latest modified time of all metafiles
539 for f
in AllWorkSpaceMetaFiles
:
540 if os
.stat(f
)[8] > SrcTimeStamp
:
541 SrcTimeStamp
= os
.stat(f
)[8]
542 self
._SrcTimeStamp
= SrcTimeStamp
544 if GlobalData
.gUseHashCache
:
546 for files
in AllWorkSpaceMetaFiles
:
547 if files
.endswith('.dec'):
549 f
= open(files
, 'rb')
553 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'AutoGen.hash'), m
.hexdigest(), False)
554 GlobalData
.gPlatformHash
= m
.hexdigest()
557 # Write metafile list to build directory
559 AutoGenFilePath
= os
.path
.join(self
.BuildDir
, 'AutoGen')
560 if os
.path
.exists (AutoGenFilePath
):
561 os
.remove(AutoGenFilePath
)
562 if not os
.path
.exists(self
.BuildDir
):
563 os
.makedirs(self
.BuildDir
)
564 with
open(os
.path
.join(self
.BuildDir
, 'AutoGen'), 'w+') as file:
565 for f
in AllWorkSpaceMetaFiles
:
569 def _GenPkgLevelHash(self
, Pkg
):
570 if Pkg
.PackageName
in GlobalData
.gPackageHash
:
573 PkgDir
= os
.path
.join(self
.BuildDir
, Pkg
.Arch
, Pkg
.PackageName
)
574 CreateDirectory(PkgDir
)
575 HashFile
= os
.path
.join(PkgDir
, Pkg
.PackageName
+ '.hash')
577 # Get .dec file's hash value
578 f
= open(Pkg
.MetaFile
.Path
, 'rb')
582 # Get include files hash value
584 for inc
in sorted(Pkg
.Includes
, key
=lambda x
: str(x
)):
585 for Root
, Dirs
, Files
in os
.walk(str(inc
)):
586 for File
in sorted(Files
):
587 File_Path
= os
.path
.join(Root
, File
)
588 f
= open(File_Path
, 'rb')
592 SaveFileOnChange(HashFile
, m
.hexdigest(), False)
593 GlobalData
.gPackageHash
[Pkg
.PackageName
] = m
.hexdigest()
595 def _GetMetaFiles(self
, Target
, Toolchain
):
596 AllWorkSpaceMetaFiles
= set()
601 AllWorkSpaceMetaFiles
.add (self
.FdfFile
.Path
)
602 for f
in GlobalData
.gFdfParser
.GetAllIncludedFile():
603 AllWorkSpaceMetaFiles
.add (f
.FileName
)
607 AllWorkSpaceMetaFiles
.add(self
.MetaFile
.Path
)
610 # add build_rule.txt & tools_def.txt
612 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultBuildRuleFile
))
613 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultToolsDefFile
))
615 # add BuildOption metafile
617 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'BuildOptions'))
619 # add PcdToken Number file for Dynamic/DynamicEx Pcd
621 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'))
623 for Pa
in self
.AutoGenObjectList
:
624 AllWorkSpaceMetaFiles
.add(Pa
.ToolDefinitionFile
)
626 for Arch
in self
.ArchList
:
630 for Package
in PlatformAutoGen(self
, self
.MetaFile
, Target
, Toolchain
, Arch
).PackageList
:
631 AllWorkSpaceMetaFiles
.add(Package
.MetaFile
.Path
)
636 for filePath
in self
.BuildDatabase
[self
.MetaFile
, Arch
, Target
, Toolchain
]._RawData
.IncludedFiles
:
637 AllWorkSpaceMetaFiles
.add(filePath
.Path
)
639 return AllWorkSpaceMetaFiles
641 def _CheckPcdDefineAndType(self
):
642 PcdTypeSet
= {TAB_PCDS_FIXED_AT_BUILD
,
643 TAB_PCDS_PATCHABLE_IN_MODULE
,
644 TAB_PCDS_FEATURE_FLAG
,
648 # This dict store PCDs which are not used by any modules with specified arches
649 UnusedPcd
= OrderedDict()
650 for Pa
in self
.AutoGenObjectList
:
651 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
652 for Pcd
in Pa
.Platform
.Pcds
:
653 PcdType
= Pa
.Platform
.Pcds
[Pcd
].Type
655 # If no PCD type, this PCD comes from FDF
659 # Try to remove Hii and Vpd suffix
660 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
661 PcdType
= TAB_PCDS_DYNAMIC_EX
662 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
663 PcdType
= TAB_PCDS_DYNAMIC
665 for Package
in Pa
.PackageList
:
666 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
667 if (Pcd
[0], Pcd
[1], PcdType
) in Package
.Pcds
:
669 for Type
in PcdTypeSet
:
670 if (Pcd
[0], Pcd
[1], Type
) in Package
.Pcds
:
674 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
675 % (Pa
.Platform
.Pcds
[Pcd
].Type
, Pcd
[1], Pcd
[0], Type
),
680 UnusedPcd
.setdefault(Pcd
, []).append(Pa
.Arch
)
682 for Pcd
in UnusedPcd
:
685 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
686 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
687 % (Pcd
[1], Pcd
[0], os
.path
.basename(str(self
.MetaFile
)), str(UnusedPcd
[Pcd
])),
692 return "%s [%s]" % (self
.MetaFile
, ", ".join(self
.ArchList
))
694 ## Return the directory to store FV files
697 return path
.join(self
.BuildDir
, TAB_FV_DIRECTORY
)
699 ## Return the directory to store all intermediate and final files built
702 return self
.AutoGenObjectList
[0].BuildDir
704 ## Return the build output directory platform specifies
707 return self
.Platform
.OutputDirectory
709 ## Return platform name
712 return self
.Platform
.PlatformName
714 ## Return meta-file GUID
717 return self
.Platform
.Guid
719 ## Return platform version
722 return self
.Platform
.Version
724 ## Return paths of tools
726 def ToolDefinition(self
):
727 return self
.AutoGenObjectList
[0].ToolDefinition
729 ## Return directory of platform makefile
731 # @retval string Makefile directory
734 def MakeFileDir(self
):
737 ## Return build command string
739 # @retval string Build command string
742 def BuildCommand(self
):
743 # BuildCommand should be all the same. So just get one from platform AutoGen
744 return self
.AutoGenObjectList
[0].BuildCommand
746 ## Check the PCDs token value conflict in each DEC file.
748 # Will cause build break and raise error message while two PCDs conflict.
752 def _CheckAllPcdsTokenValueConflict(self
):
753 for Pa
in self
.AutoGenObjectList
:
754 for Package
in Pa
.PackageList
:
755 PcdList
= list(Package
.Pcds
.values())
756 PcdList
.sort(key
=lambda x
: int(x
.TokenValue
, 0))
758 while (Count
< len(PcdList
) - 1) :
759 Item
= PcdList
[Count
]
760 ItemNext
= PcdList
[Count
+ 1]
762 # Make sure in the same token space the TokenValue should be unique
764 if (int(Item
.TokenValue
, 0) == int(ItemNext
.TokenValue
, 0)):
765 SameTokenValuePcdList
= []
766 SameTokenValuePcdList
.append(Item
)
767 SameTokenValuePcdList
.append(ItemNext
)
768 RemainPcdListLength
= len(PcdList
) - Count
- 2
769 for ValueSameCount
in range(RemainPcdListLength
):
770 if int(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
].TokenValue
, 0) == int(Item
.TokenValue
, 0):
771 SameTokenValuePcdList
.append(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
])
775 # Sort same token value PCD list with TokenGuid and TokenCName
777 SameTokenValuePcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
778 SameTokenValuePcdListCount
= 0
779 while (SameTokenValuePcdListCount
< len(SameTokenValuePcdList
) - 1):
781 TemListItem
= SameTokenValuePcdList
[SameTokenValuePcdListCount
]
782 TemListItemNext
= SameTokenValuePcdList
[SameTokenValuePcdListCount
+ 1]
784 if (TemListItem
.TokenSpaceGuidCName
== TemListItemNext
.TokenSpaceGuidCName
) and (TemListItem
.TokenCName
!= TemListItemNext
.TokenCName
):
785 for PcdItem
in GlobalData
.MixedPcd
:
786 if (TemListItem
.TokenCName
, TemListItem
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
] or \
787 (TemListItemNext
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
]:
793 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
794 % (TemListItem
.TokenValue
, TemListItem
.TokenSpaceGuidCName
, TemListItem
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
, TemListItemNext
.TokenCName
, Package
),
797 SameTokenValuePcdListCount
+= 1
798 Count
+= SameTokenValuePcdListCount
801 PcdList
= list(Package
.Pcds
.values())
802 PcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
804 while (Count
< len(PcdList
) - 1) :
805 Item
= PcdList
[Count
]
806 ItemNext
= PcdList
[Count
+ 1]
808 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
810 if (Item
.TokenSpaceGuidCName
== ItemNext
.TokenSpaceGuidCName
) and (Item
.TokenCName
== ItemNext
.TokenCName
) and (int(Item
.TokenValue
, 0) != int(ItemNext
.TokenValue
, 0)):
814 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
815 % (Item
.TokenValue
, Item
.TokenSpaceGuidCName
, Item
.TokenCName
, Package
),
819 ## Generate fds command
821 def GenFdsCommand(self
):
822 return (GenMake
.TopLevelMakefile(self
)._TEMPLATE
_.Replace(GenMake
.TopLevelMakefile(self
)._TemplateDict
)).strip()
825 def GenFdsCommandDict(self
):
827 LogLevel
= EdkLogger
.GetLevel()
828 if LogLevel
== EdkLogger
.VERBOSE
:
829 FdsCommandDict
["verbose"] = True
830 elif LogLevel
<= EdkLogger
.DEBUG_9
:
831 FdsCommandDict
["debug"] = LogLevel
- 1
832 elif LogLevel
== EdkLogger
.QUIET
:
833 FdsCommandDict
["quiet"] = True
835 if GlobalData
.gEnableGenfdsMultiThread
:
836 FdsCommandDict
["GenfdsMultiThread"] = True
837 if GlobalData
.gIgnoreSource
:
838 FdsCommandDict
["IgnoreSources"] = True
840 FdsCommandDict
["OptionPcd"] = []
841 for pcd
in GlobalData
.BuildOptionPcd
:
843 pcdname
= '.'.join(pcd
[0:3])
845 pcdname
= '.'.join(pcd
[0:2])
846 if pcd
[3].startswith('{'):
847 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + 'H' + '"' + pcd
[3] + '"')
849 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + pcd
[3])
852 # macros passed to GenFds
854 MacroDict
.update(GlobalData
.gGlobalDefines
)
855 MacroDict
.update(GlobalData
.gCommandLineDefines
)
856 for MacroName
in MacroDict
:
857 if MacroDict
[MacroName
] != "":
858 MacroList
.append('"%s=%s"' % (MacroName
, MacroDict
[MacroName
].replace('\\', '\\\\')))
860 MacroList
.append('"%s"' % MacroName
)
861 FdsCommandDict
["macro"] = MacroList
863 FdsCommandDict
["fdf_file"] = [self
.FdfFile
]
864 FdsCommandDict
["build_target"] = self
.BuildTarget
865 FdsCommandDict
["toolchain_tag"] = self
.ToolChain
866 FdsCommandDict
["active_platform"] = str(self
)
868 FdsCommandDict
["conf_directory"] = GlobalData
.gConfDirectory
869 FdsCommandDict
["build_architecture_list"] = ','.join(self
.ArchList
)
870 FdsCommandDict
["platform_build_directory"] = self
.BuildDir
872 FdsCommandDict
["fd"] = self
.FdTargetList
873 FdsCommandDict
["fv"] = self
.FvTargetList
874 FdsCommandDict
["cap"] = self
.CapTargetList
875 return FdsCommandDict
877 ## Create makefile for the platform and modules in it
879 # @param CreateDepsMakeFile Flag indicating if the makefile for
880 # modules will be created as well
882 def CreateMakeFile(self
, CreateDepsMakeFile
=False):
883 if not CreateDepsMakeFile
:
885 for Pa
in self
.AutoGenObjectList
:
886 Pa
.CreateMakeFile(CreateDepsMakeFile
)
888 ## Create autogen code for platform and modules
890 # Since there's no autogen code for platform, this method will do nothing
891 # if CreateModuleCodeFile is set to False.
893 # @param CreateDepsCodeFile Flag indicating if creating module's
894 # autogen code file or not
896 def CreateCodeFile(self
, CreateDepsCodeFile
=False):
897 if not CreateDepsCodeFile
:
899 for Pa
in self
.AutoGenObjectList
:
900 Pa
.CreateCodeFile(CreateDepsCodeFile
)
902 ## Create AsBuilt INF file the platform
904 def CreateAsBuiltInf(self
):