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 self
.GeneratePkgLevelHash()
118 # Check PCDs token value conflict in each DEC file.
120 self
._CheckAllPcdsTokenValueConflict
()
122 # Check PCD type and definition between DSC and DEC
124 self
._CheckPcdDefineAndType
()
126 self
.CreateBuildOptionsFile()
127 self
.CreatePcdTokenNumberFile()
128 self
.CreateModuleHashInfo()
129 GlobalData
.gAutoGenPhase
= False
135 if not self
.ArchList
:
136 ArchList
= set(self
.Platform
.SupArchList
)
138 ArchList
= set(self
.ArchList
) & set(self
.Platform
.SupArchList
)
140 EdkLogger
.error("build", PARAMETER_INVALID
,
141 ExtraData
= "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self
.Platform
.SupArchList
)))
142 elif self
.ArchList
and len(ArchList
) != len(self
.ArchList
):
143 SkippedArchList
= set(self
.ArchList
).symmetric_difference(set(self
.Platform
.SupArchList
))
144 EdkLogger
.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
145 % (" ".join(SkippedArchList
), " ".join(self
.Platform
.SupArchList
)))
146 self
.ArchList
= tuple(ArchList
)
148 # Validate build target
149 def ValidateBuildTarget(self
):
150 if self
.BuildTarget
not in self
.Platform
.BuildTargets
:
151 EdkLogger
.error("build", PARAMETER_INVALID
,
152 ExtraData
="Build target [%s] is not supported by the platform. [Valid target: %s]"
153 % (self
.BuildTarget
, " ".join(self
.Platform
.BuildTargets
)))
155 def FdfProfile(self
):
157 self
.FdfFile
= self
.Platform
.FlashDefinition
161 Fdf
= FdfParser(self
.FdfFile
.Path
)
163 GlobalData
.gFdfParser
= Fdf
164 if Fdf
.CurrentFdName
and Fdf
.CurrentFdName
in Fdf
.Profile
.FdDict
:
165 FdDict
= Fdf
.Profile
.FdDict
[Fdf
.CurrentFdName
]
166 for FdRegion
in FdDict
.RegionList
:
167 if str(FdRegion
.RegionType
) is 'FILE' and self
.Platform
.VpdToolGuid
in str(FdRegion
.RegionDataList
):
168 if int(FdRegion
.Offset
) % 8 != 0:
169 EdkLogger
.error("build", FORMAT_INVALID
, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion
.Offset
))
170 FdfProfile
= Fdf
.Profile
172 if self
.FdTargetList
:
173 EdkLogger
.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self
.FdTargetList
))
174 self
.FdTargetList
= []
175 if self
.FvTargetList
:
176 EdkLogger
.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self
.FvTargetList
))
177 self
.FvTargetList
= []
178 if self
.CapTargetList
:
179 EdkLogger
.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self
.CapTargetList
))
180 self
.CapTargetList
= []
184 def ProcessModuleFromPdf(self
):
187 for fvname
in self
.FvTargetList
:
188 if fvname
.upper() not in self
.FdfProfile
.FvDict
:
189 EdkLogger
.error("build", OPTION_VALUE_INVALID
,
190 "No such an FV in FDF file: %s" % fvname
)
192 # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
193 # but the path (self.MetaFile.Path) is the real path
194 for key
in self
.FdfProfile
.InfDict
:
196 MetaFile_cache
= defaultdict(set)
197 for Arch
in self
.ArchList
:
198 Current_Platform_cache
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
199 for Pkey
in Current_Platform_cache
.Modules
:
200 MetaFile_cache
[Arch
].add(Current_Platform_cache
.Modules
[Pkey
].MetaFile
)
201 for Inf
in self
.FdfProfile
.InfDict
[key
]:
202 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
203 for Arch
in self
.ArchList
:
204 if ModuleFile
in MetaFile_cache
[Arch
]:
207 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
208 if not ModuleData
.IsBinaryModule
:
209 EdkLogger
.error('build', PARSER_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile
)
212 for Arch
in self
.ArchList
:
214 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
216 for Pkey
in Platform
.Modules
:
217 MetaFileList
.add(Platform
.Modules
[Pkey
].MetaFile
)
218 for Inf
in self
.FdfProfile
.InfDict
[key
]:
219 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
220 if ModuleFile
in MetaFileList
:
222 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
223 if not ModuleData
.IsBinaryModule
:
224 EdkLogger
.error('build', PARSER_ERROR
, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile
)
228 # parse FDF file to get PCDs in it, if any
229 def VerifyPcdsFromFDF(self
):
232 PcdSet
= self
.FdfProfile
.PcdDict
233 self
.VerifyPcdDeclearation(PcdSet
)
235 def ProcessPcdType(self
):
236 for Arch
in self
.ArchList
:
237 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
239 # generate the SourcePcdDict and BinaryPcdDict
241 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
242 if BuildData
.Arch
!= Arch
:
244 if BuildData
.MetaFile
.Ext
== '.inf' and str(BuildData
) in Platform
.Modules
:
245 Libs
.extend(GetModuleLibInstances(BuildData
, Platform
,
251 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
252 if BuildData
.Arch
!= Arch
:
254 if BuildData
.MetaFile
.Ext
== '.inf':
255 for key
in BuildData
.Pcds
:
256 if BuildData
.Pcds
[key
].Pending
:
257 if key
in Platform
.Pcds
:
258 PcdInPlatform
= Platform
.Pcds
[key
]
259 if PcdInPlatform
.Type
:
260 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
261 BuildData
.Pcds
[key
].Pending
= False
263 if BuildData
.MetaFile
in Platform
.Modules
:
264 PlatformModule
= Platform
.Modules
[str(BuildData
.MetaFile
)]
265 if key
in PlatformModule
.Pcds
:
266 PcdInPlatform
= PlatformModule
.Pcds
[key
]
267 if PcdInPlatform
.Type
:
268 BuildData
.Pcds
[key
].Type
= PcdInPlatform
.Type
269 BuildData
.Pcds
[key
].Pending
= False
271 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
272 if BuildData
.Pcds
[key
].Pending
:
273 if bool(BuildData
.LibraryClass
):
274 if BuildData
in set(Libs
):
275 ReferenceModules
= BuildData
.ReferenceModules
276 for ReferenceModule
in ReferenceModules
:
277 if ReferenceModule
.MetaFile
in Platform
.Modules
:
278 RefPlatformModule
= Platform
.Modules
[str(ReferenceModule
.MetaFile
)]
279 if key
in RefPlatformModule
.Pcds
:
280 PcdInReferenceModule
= RefPlatformModule
.Pcds
[key
]
281 if PcdInReferenceModule
.Type
:
282 BuildData
.Pcds
[key
].Type
= PcdInReferenceModule
.Type
283 BuildData
.Pcds
[key
].Pending
= False
286 def ProcessMixedPcd(self
):
287 for Arch
in self
.ArchList
:
288 SourcePcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set(),TAB_PCDS_DYNAMIC
:set(),TAB_PCDS_FIXED_AT_BUILD
:set()}
289 BinaryPcdDict
= {TAB_PCDS_DYNAMIC_EX
:set(), TAB_PCDS_PATCHABLE_IN_MODULE
:set()}
290 SourcePcdDict_Keys
= SourcePcdDict
.keys()
291 BinaryPcdDict_Keys
= BinaryPcdDict
.keys()
293 # generate the SourcePcdDict and BinaryPcdDict
295 for BuildData
in list(self
.BuildDatabase
._CACHE
_.values()):
296 if BuildData
.Arch
!= Arch
:
298 if BuildData
.MetaFile
.Ext
== '.inf':
299 for key
in BuildData
.Pcds
:
300 if TAB_PCDS_DYNAMIC_EX
in BuildData
.Pcds
[key
].Type
:
301 if BuildData
.IsBinaryModule
:
302 BinaryPcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
304 SourcePcdDict
[TAB_PCDS_DYNAMIC_EX
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
306 elif TAB_PCDS_PATCHABLE_IN_MODULE
in BuildData
.Pcds
[key
].Type
:
307 if BuildData
.MetaFile
.Ext
== '.inf':
308 if BuildData
.IsBinaryModule
:
309 BinaryPcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
311 SourcePcdDict
[TAB_PCDS_PATCHABLE_IN_MODULE
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
313 elif TAB_PCDS_DYNAMIC
in BuildData
.Pcds
[key
].Type
:
314 SourcePcdDict
[TAB_PCDS_DYNAMIC
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
315 elif TAB_PCDS_FIXED_AT_BUILD
in BuildData
.Pcds
[key
].Type
:
316 SourcePcdDict
[TAB_PCDS_FIXED_AT_BUILD
].add((BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
))
319 # A PCD can only use one type for all source modules
321 for i
in SourcePcdDict_Keys
:
322 for j
in SourcePcdDict_Keys
:
324 Intersections
= SourcePcdDict
[i
].intersection(SourcePcdDict
[j
])
325 if len(Intersections
) > 0:
329 "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
),
330 ExtraData
='\n\t'.join(str(P
[1]+'.'+P
[0]) for P
in Intersections
)
334 # intersection the BinaryPCD for Mixed PCD
336 for i
in BinaryPcdDict_Keys
:
337 for j
in BinaryPcdDict_Keys
:
339 Intersections
= BinaryPcdDict
[i
].intersection(BinaryPcdDict
[j
])
340 for item
in Intersections
:
341 NewPcd1
= (item
[0] + '_' + i
, item
[1])
342 NewPcd2
= (item
[0] + '_' + j
, item
[1])
343 if item
not in GlobalData
.MixedPcd
:
344 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
346 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
347 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
348 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
349 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
352 # intersection the SourcePCD and BinaryPCD for Mixed PCD
354 for i
in SourcePcdDict_Keys
:
355 for j
in BinaryPcdDict_Keys
:
357 Intersections
= SourcePcdDict
[i
].intersection(BinaryPcdDict
[j
])
358 for item
in Intersections
:
359 NewPcd1
= (item
[0] + '_' + i
, item
[1])
360 NewPcd2
= (item
[0] + '_' + j
, item
[1])
361 if item
not in GlobalData
.MixedPcd
:
362 GlobalData
.MixedPcd
[item
] = [NewPcd1
, NewPcd2
]
364 if NewPcd1
not in GlobalData
.MixedPcd
[item
]:
365 GlobalData
.MixedPcd
[item
].append(NewPcd1
)
366 if NewPcd2
not in GlobalData
.MixedPcd
[item
]:
367 GlobalData
.MixedPcd
[item
].append(NewPcd2
)
369 BuildData
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
370 for key
in BuildData
.Pcds
:
371 for SinglePcd
in GlobalData
.MixedPcd
:
372 if (BuildData
.Pcds
[key
].TokenCName
, BuildData
.Pcds
[key
].TokenSpaceGuidCName
) == SinglePcd
:
373 for item
in GlobalData
.MixedPcd
[SinglePcd
]:
374 Pcd_Type
= item
[0].split('_')[-1]
375 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 \
376 (Pcd_Type
== TAB_PCDS_DYNAMIC
and BuildData
.Pcds
[key
].Type
in PCD_DYNAMIC_TYPE_SET
):
377 Value
= BuildData
.Pcds
[key
]
378 Value
.TokenCName
= BuildData
.Pcds
[key
].TokenCName
+ '_' + Pcd_Type
380 newkey
= (Value
.TokenCName
, key
[1])
382 newkey
= (Value
.TokenCName
, key
[1], key
[2])
383 del BuildData
.Pcds
[key
]
384 BuildData
.Pcds
[newkey
] = Value
389 PcdSet
= self
.FdfProfile
.PcdDict
390 # handle the mixed pcd in FDF file
392 if key
in GlobalData
.MixedPcd
:
395 for item
in GlobalData
.MixedPcd
[key
]:
398 #Collect package set information from INF of FDF
402 self
.FdfFile
= self
.Platform
.FlashDefinition
405 ModuleList
= self
.FdfProfile
.InfList
409 for Arch
in self
.ArchList
:
410 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
412 for mb
in [self
.BuildDatabase
[m
, Arch
, self
.BuildTarget
, self
.ToolChain
] for m
in Platform
.Modules
]:
413 PkgSet
.update(mb
.Packages
)
414 for Inf
in ModuleList
:
415 ModuleFile
= PathClass(NormPath(Inf
), GlobalData
.gWorkspace
, Arch
)
416 if ModuleFile
in Platform
.Modules
:
418 ModuleData
= self
.BuildDatabase
[ModuleFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
419 PkgSet
.update(ModuleData
.Packages
)
420 Pkgs
[Arch
] = list(PkgSet
)
423 def VerifyPcdDeclearation(self
,PcdSet
):
424 for Arch
in self
.ArchList
:
425 Platform
= self
.BuildDatabase
[self
.MetaFile
, Arch
, self
.BuildTarget
, self
.ToolChain
]
426 Pkgs
= self
.PkgSet
[Arch
]
431 DecPcds
.add((Pcd
[0], Pcd
[1]))
432 DecPcdsKey
.add((Pcd
[0], Pcd
[1], Pcd
[2]))
434 Platform
.SkuName
= self
.SkuId
435 for Name
, Guid
,Fileds
in PcdSet
:
436 if (Name
, Guid
) not in DecPcds
:
440 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid
, Name
),
441 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
442 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
445 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
446 if (Name
, Guid
, TAB_PCDS_FIXED_AT_BUILD
) in DecPcdsKey \
447 or (Name
, Guid
, TAB_PCDS_PATCHABLE_IN_MODULE
) in DecPcdsKey \
448 or (Name
, Guid
, TAB_PCDS_FEATURE_FLAG
) in DecPcdsKey
:
450 elif (Name
, Guid
, TAB_PCDS_DYNAMIC
) in DecPcdsKey
or (Name
, Guid
, TAB_PCDS_DYNAMIC_EX
) in DecPcdsKey
:
454 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid
, Name
),
455 File
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][0],
456 Line
= self
.FdfProfile
.PcdFileLineDict
[Name
, Guid
, Fileds
][1]
458 def CollectAllPcds(self
):
460 for Arch
in self
.ArchList
:
461 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
463 # Explicitly collect platform's dynamic PCDs
465 Pa
.CollectPlatformDynamicPcds()
466 Pa
.CollectFixedAtBuildPcds()
467 self
.AutoGenObjectList
.append(Pa
)
468 # We need to calculate the PcdTokenNumber after all Arch Pcds are collected.
469 for Arch
in self
.ArchList
:
471 Pa
= PlatformAutoGen(self
, self
.MetaFile
, self
.BuildTarget
, self
.ToolChain
, Arch
)
472 self
.UpdateModuleDataPipe(Arch
, {"PCD_TNUM":Pa
.PcdTokenNumber
})
474 def UpdateModuleDataPipe(self
,arch
, attr_dict
):
475 for (Target
, Toolchain
, Arch
, MetaFile
) in AutoGen
.Cache():
479 AutoGen
.Cache()[(Target
, Toolchain
, Arch
, MetaFile
)].DataPipe
.DataContainer
= attr_dict
483 # Generate Package level hash value
485 def GeneratePkgLevelHash(self
):
486 for Arch
in self
.ArchList
:
487 GlobalData
.gPackageHash
= {}
488 if GlobalData
.gUseHashCache
:
489 for Pkg
in self
.PkgSet
[Arch
]:
490 self
._GenPkgLevelHash
(Pkg
)
493 def CreateBuildOptionsFile(self
):
495 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
497 content
= 'gCommandLineDefines: '
498 content
+= str(GlobalData
.gCommandLineDefines
)
499 content
+= TAB_LINE_BREAK
500 content
+= 'BuildOptionPcd: '
501 content
+= str(GlobalData
.BuildOptionPcd
)
502 content
+= TAB_LINE_BREAK
503 content
+= 'Active Platform: '
504 content
+= str(self
.Platform
)
505 content
+= TAB_LINE_BREAK
507 content
+= 'Flash Image Definition: '
508 content
+= str(self
.FdfFile
)
509 content
+= TAB_LINE_BREAK
510 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'BuildOptions'), content
, False)
512 def CreatePcdTokenNumberFile(self
):
514 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
516 PcdTokenNumber
= 'PcdTokenNumber: '
517 Pa
= self
.AutoGenObjectList
[0]
518 if Pa
.PcdTokenNumber
:
519 if Pa
.DynamicPcdList
:
520 for Pcd
in Pa
.DynamicPcdList
:
521 PcdTokenNumber
+= TAB_LINE_BREAK
522 PcdTokenNumber
+= str((Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
))
523 PcdTokenNumber
+= ' : '
524 PcdTokenNumber
+= str(Pa
.PcdTokenNumber
[Pcd
.TokenCName
, Pcd
.TokenSpaceGuidCName
])
525 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'), PcdTokenNumber
, False)
527 def CreateModuleHashInfo(self
):
529 # Get set of workspace metafiles
531 AllWorkSpaceMetaFiles
= self
._GetMetaFiles
(self
.BuildTarget
, self
.ToolChain
)
534 # Retrieve latest modified time of all metafiles
537 for f
in AllWorkSpaceMetaFiles
:
538 if os
.stat(f
)[8] > SrcTimeStamp
:
539 SrcTimeStamp
= os
.stat(f
)[8]
540 self
._SrcTimeStamp
= SrcTimeStamp
542 if GlobalData
.gUseHashCache
:
544 for files
in AllWorkSpaceMetaFiles
:
545 if files
.endswith('.dec'):
547 f
= open(files
, 'rb')
551 SaveFileOnChange(os
.path
.join(self
.BuildDir
, 'AutoGen.hash'), m
.hexdigest(), False)
552 GlobalData
.gPlatformHash
= m
.hexdigest()
555 # Write metafile list to build directory
557 AutoGenFilePath
= os
.path
.join(self
.BuildDir
, 'AutoGen')
558 if os
.path
.exists (AutoGenFilePath
):
559 os
.remove(AutoGenFilePath
)
560 if not os
.path
.exists(self
.BuildDir
):
561 os
.makedirs(self
.BuildDir
)
562 with
open(os
.path
.join(self
.BuildDir
, 'AutoGen'), 'w+') as file:
563 for f
in AllWorkSpaceMetaFiles
:
567 def _GenPkgLevelHash(self
, Pkg
):
568 if Pkg
.PackageName
in GlobalData
.gPackageHash
:
571 PkgDir
= os
.path
.join(self
.BuildDir
, Pkg
.Arch
, Pkg
.PackageName
)
572 CreateDirectory(PkgDir
)
573 HashFile
= os
.path
.join(PkgDir
, Pkg
.PackageName
+ '.hash')
575 # Get .dec file's hash value
576 f
= open(Pkg
.MetaFile
.Path
, 'rb')
580 # Get include files hash value
582 for inc
in sorted(Pkg
.Includes
, key
=lambda x
: str(x
)):
583 for Root
, Dirs
, Files
in os
.walk(str(inc
)):
584 for File
in sorted(Files
):
585 File_Path
= os
.path
.join(Root
, File
)
586 f
= open(File_Path
, 'rb')
590 SaveFileOnChange(HashFile
, m
.hexdigest(), False)
591 GlobalData
.gPackageHash
[Pkg
.PackageName
] = m
.hexdigest()
593 def _GetMetaFiles(self
, Target
, Toolchain
):
594 AllWorkSpaceMetaFiles
= set()
599 AllWorkSpaceMetaFiles
.add (self
.FdfFile
.Path
)
600 for f
in GlobalData
.gFdfParser
.GetAllIncludedFile():
601 AllWorkSpaceMetaFiles
.add (f
.FileName
)
605 AllWorkSpaceMetaFiles
.add(self
.MetaFile
.Path
)
608 # add build_rule.txt & tools_def.txt
610 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultBuildRuleFile
))
611 AllWorkSpaceMetaFiles
.add(os
.path
.join(GlobalData
.gConfDirectory
, gDefaultToolsDefFile
))
613 # add BuildOption metafile
615 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'BuildOptions'))
617 # add PcdToken Number file for Dynamic/DynamicEx Pcd
619 AllWorkSpaceMetaFiles
.add(os
.path
.join(self
.BuildDir
, 'PcdTokenNumber'))
621 for Pa
in self
.AutoGenObjectList
:
622 AllWorkSpaceMetaFiles
.add(Pa
.ToolDefinitionFile
)
624 for Arch
in self
.ArchList
:
628 for Package
in PlatformAutoGen(self
, self
.MetaFile
, Target
, Toolchain
, Arch
).PackageList
:
629 AllWorkSpaceMetaFiles
.add(Package
.MetaFile
.Path
)
634 for filePath
in self
.BuildDatabase
[self
.MetaFile
, Arch
, Target
, Toolchain
]._RawData
.IncludedFiles
:
635 AllWorkSpaceMetaFiles
.add(filePath
.Path
)
637 return AllWorkSpaceMetaFiles
639 def _CheckPcdDefineAndType(self
):
640 PcdTypeSet
= {TAB_PCDS_FIXED_AT_BUILD
,
641 TAB_PCDS_PATCHABLE_IN_MODULE
,
642 TAB_PCDS_FEATURE_FLAG
,
646 # This dict store PCDs which are not used by any modules with specified arches
647 UnusedPcd
= OrderedDict()
648 for Pa
in self
.AutoGenObjectList
:
649 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
650 for Pcd
in Pa
.Platform
.Pcds
:
651 PcdType
= Pa
.Platform
.Pcds
[Pcd
].Type
653 # If no PCD type, this PCD comes from FDF
657 # Try to remove Hii and Vpd suffix
658 if PcdType
.startswith(TAB_PCDS_DYNAMIC_EX
):
659 PcdType
= TAB_PCDS_DYNAMIC_EX
660 elif PcdType
.startswith(TAB_PCDS_DYNAMIC
):
661 PcdType
= TAB_PCDS_DYNAMIC
663 for Package
in Pa
.PackageList
:
664 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
665 if (Pcd
[0], Pcd
[1], PcdType
) in Package
.Pcds
:
667 for Type
in PcdTypeSet
:
668 if (Pcd
[0], Pcd
[1], Type
) in Package
.Pcds
:
672 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
673 % (Pa
.Platform
.Pcds
[Pcd
].Type
, Pcd
[1], Pcd
[0], Type
),
678 UnusedPcd
.setdefault(Pcd
, []).append(Pa
.Arch
)
680 for Pcd
in UnusedPcd
:
683 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
684 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
685 % (Pcd
[1], Pcd
[0], os
.path
.basename(str(self
.MetaFile
)), str(UnusedPcd
[Pcd
])),
690 return "%s [%s]" % (self
.MetaFile
, ", ".join(self
.ArchList
))
692 ## Return the directory to store FV files
695 return path
.join(self
.BuildDir
, TAB_FV_DIRECTORY
)
697 ## Return the directory to store all intermediate and final files built
700 return self
.AutoGenObjectList
[0].BuildDir
702 ## Return the build output directory platform specifies
705 return self
.Platform
.OutputDirectory
707 ## Return platform name
710 return self
.Platform
.PlatformName
712 ## Return meta-file GUID
715 return self
.Platform
.Guid
717 ## Return platform version
720 return self
.Platform
.Version
722 ## Return paths of tools
724 def ToolDefinition(self
):
725 return self
.AutoGenObjectList
[0].ToolDefinition
727 ## Return directory of platform makefile
729 # @retval string Makefile directory
732 def MakeFileDir(self
):
735 ## Return build command string
737 # @retval string Build command string
740 def BuildCommand(self
):
741 # BuildCommand should be all the same. So just get one from platform AutoGen
742 return self
.AutoGenObjectList
[0].BuildCommand
744 ## Check the PCDs token value conflict in each DEC file.
746 # Will cause build break and raise error message while two PCDs conflict.
750 def _CheckAllPcdsTokenValueConflict(self
):
751 for Pa
in self
.AutoGenObjectList
:
752 for Package
in Pa
.PackageList
:
753 PcdList
= list(Package
.Pcds
.values())
754 PcdList
.sort(key
=lambda x
: int(x
.TokenValue
, 0))
756 while (Count
< len(PcdList
) - 1) :
757 Item
= PcdList
[Count
]
758 ItemNext
= PcdList
[Count
+ 1]
760 # Make sure in the same token space the TokenValue should be unique
762 if (int(Item
.TokenValue
, 0) == int(ItemNext
.TokenValue
, 0)):
763 SameTokenValuePcdList
= []
764 SameTokenValuePcdList
.append(Item
)
765 SameTokenValuePcdList
.append(ItemNext
)
766 RemainPcdListLength
= len(PcdList
) - Count
- 2
767 for ValueSameCount
in range(RemainPcdListLength
):
768 if int(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
].TokenValue
, 0) == int(Item
.TokenValue
, 0):
769 SameTokenValuePcdList
.append(PcdList
[len(PcdList
) - RemainPcdListLength
+ ValueSameCount
])
773 # Sort same token value PCD list with TokenGuid and TokenCName
775 SameTokenValuePcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
776 SameTokenValuePcdListCount
= 0
777 while (SameTokenValuePcdListCount
< len(SameTokenValuePcdList
) - 1):
779 TemListItem
= SameTokenValuePcdList
[SameTokenValuePcdListCount
]
780 TemListItemNext
= SameTokenValuePcdList
[SameTokenValuePcdListCount
+ 1]
782 if (TemListItem
.TokenSpaceGuidCName
== TemListItemNext
.TokenSpaceGuidCName
) and (TemListItem
.TokenCName
!= TemListItemNext
.TokenCName
):
783 for PcdItem
in GlobalData
.MixedPcd
:
784 if (TemListItem
.TokenCName
, TemListItem
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
] or \
785 (TemListItemNext
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
) in GlobalData
.MixedPcd
[PcdItem
]:
791 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
792 % (TemListItem
.TokenValue
, TemListItem
.TokenSpaceGuidCName
, TemListItem
.TokenCName
, TemListItemNext
.TokenSpaceGuidCName
, TemListItemNext
.TokenCName
, Package
),
795 SameTokenValuePcdListCount
+= 1
796 Count
+= SameTokenValuePcdListCount
799 PcdList
= list(Package
.Pcds
.values())
800 PcdList
.sort(key
=lambda x
: "%s.%s" % (x
.TokenSpaceGuidCName
, x
.TokenCName
))
802 while (Count
< len(PcdList
) - 1) :
803 Item
= PcdList
[Count
]
804 ItemNext
= PcdList
[Count
+ 1]
806 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
808 if (Item
.TokenSpaceGuidCName
== ItemNext
.TokenSpaceGuidCName
) and (Item
.TokenCName
== ItemNext
.TokenCName
) and (int(Item
.TokenValue
, 0) != int(ItemNext
.TokenValue
, 0)):
812 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
813 % (Item
.TokenValue
, Item
.TokenSpaceGuidCName
, Item
.TokenCName
, Package
),
817 ## Generate fds command
819 def GenFdsCommand(self
):
820 return (GenMake
.TopLevelMakefile(self
)._TEMPLATE
_.Replace(GenMake
.TopLevelMakefile(self
)._TemplateDict
)).strip()
823 def GenFdsCommandDict(self
):
825 LogLevel
= EdkLogger
.GetLevel()
826 if LogLevel
== EdkLogger
.VERBOSE
:
827 FdsCommandDict
["verbose"] = True
828 elif LogLevel
<= EdkLogger
.DEBUG_9
:
829 FdsCommandDict
["debug"] = LogLevel
- 1
830 elif LogLevel
== EdkLogger
.QUIET
:
831 FdsCommandDict
["quiet"] = True
833 if GlobalData
.gEnableGenfdsMultiThread
:
834 FdsCommandDict
["GenfdsMultiThread"] = True
835 if GlobalData
.gIgnoreSource
:
836 FdsCommandDict
["IgnoreSources"] = True
838 FdsCommandDict
["OptionPcd"] = []
839 for pcd
in GlobalData
.BuildOptionPcd
:
841 pcdname
= '.'.join(pcd
[0:3])
843 pcdname
= '.'.join(pcd
[0:2])
844 if pcd
[3].startswith('{'):
845 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + 'H' + '"' + pcd
[3] + '"')
847 FdsCommandDict
["OptionPcd"].append(pcdname
+ '=' + pcd
[3])
850 # macros passed to GenFds
852 MacroDict
.update(GlobalData
.gGlobalDefines
)
853 MacroDict
.update(GlobalData
.gCommandLineDefines
)
854 for MacroName
in MacroDict
:
855 if MacroDict
[MacroName
] != "":
856 MacroList
.append('"%s=%s"' % (MacroName
, MacroDict
[MacroName
].replace('\\', '\\\\')))
858 MacroList
.append('"%s"' % MacroName
)
859 FdsCommandDict
["macro"] = MacroList
861 FdsCommandDict
["fdf_file"] = [self
.FdfFile
]
862 FdsCommandDict
["build_target"] = self
.BuildTarget
863 FdsCommandDict
["toolchain_tag"] = self
.ToolChain
864 FdsCommandDict
["active_platform"] = str(self
)
866 FdsCommandDict
["conf_directory"] = GlobalData
.gConfDirectory
867 FdsCommandDict
["build_architecture_list"] = ','.join(self
.ArchList
)
868 FdsCommandDict
["platform_build_directory"] = self
.BuildDir
870 FdsCommandDict
["fd"] = self
.FdTargetList
871 FdsCommandDict
["fv"] = self
.FvTargetList
872 FdsCommandDict
["cap"] = self
.CapTargetList
873 return FdsCommandDict
875 ## Create makefile for the platform and modules in it
877 # @param CreateDepsMakeFile Flag indicating if the makefile for
878 # modules will be created as well
880 def CreateMakeFile(self
, CreateDepsMakeFile
=False):
881 if not CreateDepsMakeFile
:
883 for Pa
in self
.AutoGenObjectList
:
884 Pa
.CreateMakeFile(True)
886 ## Create autogen code for platform and modules
888 # Since there's no autogen code for platform, this method will do nothing
889 # if CreateModuleCodeFile is set to False.
891 # @param CreateDepsCodeFile Flag indicating if creating module's
892 # autogen code file or not
894 def CreateCodeFile(self
, CreateDepsCodeFile
=False):
895 if not CreateDepsCodeFile
:
897 for Pa
in self
.AutoGenObjectList
:
898 Pa
.CreateCodeFile(True)
900 ## Create AsBuilt INF file the platform
902 def CreateAsBuiltInf(self
):