a7a1099dd78c85208448812c8da62c898a934fc6
[people/mcb30/basetools.git] / Source / Python / AutoGen / AutoGen.py
1 ## @file\r
2 # Generate AutoGen.h, AutoGen.c and *.depex files\r
3 #\r
4 # Copyright (c) 2007, Intel Corporation\r
5 # All rights reserved. This program and the accompanying materials\r
6 # are licensed and made available under the terms and conditions of the BSD License\r
7 # which accompanies this distribution.  The full text of the license may be found at\r
8 # http://opensource.org/licenses/bsd-license.php\r
9 #\r
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 #\r
13 \r
14 ## Import Modules\r
15 #\r
16 import sys\r
17 import os\r
18 import re\r
19 import os.path as path\r
20 import imp\r
21 from optparse import OptionParser\r
22 from optparse import make_option\r
23 \r
24 import Common.EdkLogger\r
25 import GenC\r
26 import GenMake\r
27 import GenDepex\r
28 \r
29 from BuildInfo import *\r
30 from StrGather import *\r
31 from BuildEngine import *\r
32 \r
33 from Common.BuildToolError import *\r
34 from Common.EdkIIWorkspaceBuild import *\r
35 from Common.EdkIIWorkspace import *\r
36 from Common.DataType import *\r
37 from Common.Misc import *\r
38 from Common.String import *\r
39 \r
40 ## Regular expression for splitting Dependency Expression stirng into tokens\r
41 gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)")\r
42 \r
43 ## Mapping Makefile type\r
44 gMakeTypeMap = {"MSFT":"nmake", "GCC":"gmake"}\r
45 \r
46 ## Default output flag for all tools\r
47 gDefaultOutputFlag = "-o "\r
48 \r
49 ## Output flags for specific tools\r
50 gOutputFlag = {\r
51     ("MSFT", "CC", "OUTPUT")      :   "/Fo",\r
52     ("MSFT", "SLINK", "OUTPUT")   :   "/OUT:",\r
53     ("MSFT", "DLINK", "OUTPUT")   :   "/OUT:",\r
54     ("MSFT", "ASMLINK", "OUTPUT") :   "/OUT:",\r
55     ("MSFT", "PCH", "OUTPUT")     :   "/Fp",\r
56     ("MSFT", "ASM", "OUTPUT")     :   "/Fo",\r
57 \r
58     ("INTEL", "CC", "OUTPUT")          :   "/Fo",\r
59     ("INTEL", "SLINK", "OUTPUT")       :   "/OUT:",\r
60     ("INTEL", "DLINK", "OUTPUT")       :   "/OUT:",\r
61     ("INTEL", "ASMLINK", "OUTPUT")     :   "/OUT:",\r
62     ("INTEL", "PCH", "OUTPUT")         :   "/Fp",\r
63     ("INTEL", "ASM", "OUTPUT")         :   "/Fo",\r
64 \r
65     ("GCC", "CC", "OUTPUT")        :   "-o ",\r
66     ("GCC", "SLINK", "OUTPUT")     :   "-cr ",\r
67     ("GCC", "DLINK", "OUTPUT")     :   "-o ",\r
68     ("GCC", "ASMLINK", "OUTPUT")   :   "-o ",\r
69     ("GCC", "PCH", "OUTPUT")       :   "-o ",\r
70     ("GCC", "ASM", "OUTPUT")       :   "-o ",\r
71 }\r
72 \r
73 ## Flag for include file search path\r
74 gIncludeFlag = {"MSFT" : "/I", "GCC" : "-I", "INTEL" : "-I"}\r
75 \r
76 ## Build rule configuration file\r
77 gBuildRuleFile = 'Conf/build_rule.txt'\r
78 \r
79 ## default file name for AutoGen\r
80 gAutoGenCodeFileName = "AutoGen.c"\r
81 gAutoGenHeaderFileName = "AutoGen.h"\r
82 gAutoGenDepexFileName = "%(module_name)s.depex"\r
83 \r
84 ## AutoGen class for platform\r
85 #\r
86 #  PlatformAutoGen class will re-organize the original information in platform\r
87 #  file in order to generate makefile for platform.\r
88 #\r
89 class PlatformAutoGen:\r
90     # database to maintain the objects of PlatformAutoGen\r
91     _Database = {}    # (platform file, BuildTarget, ToolChain) : PlatformAutoGen object\r
92 \r
93     ## The real constructor of PlatformAutoGen\r
94     #\r
95     #  This method is not supposed to be called by users of PlatformAutoGen. It's\r
96     #  only used by factory method New() to do real initialization work for an\r
97     #  object of PlatformAutoGen\r
98     #\r
99     #   @param      Workspace       EdkIIWorkspaceBuild object\r
100     #   @param      PlatformFile    Platform file (DSC file)\r
101     #   @param      Target          Build target (DEBUG, RELEASE)\r
102     #   @param      Toolchain       Name of tool chain\r
103     #   @param      ArchList        List of arch the platform supports\r
104     #\r
105     def _Init(self, Workspace, PlatformFile, Target, Toolchain, ArchList):\r
106         self.PlatformFile = str(PlatformFile)\r
107         self.Workspace = Workspace\r
108         self.WorkspaceDir = Workspace.WorkspaceDir\r
109         self.ToolChain = Toolchain\r
110         self.BuildTarget = Target\r
111         self.ArchList = ArchList\r
112 \r
113         EdkLogger.verbose("\nAutoGen platform [%s] [%s]" % (self.PlatformFile, " ".join(self.ArchList)))\r
114 \r
115         # get the original module/package/platform objects\r
116         self.ModuleDatabase = {}\r
117         for a in Workspace.Build:\r
118             self.ModuleDatabase[a] = Workspace.Build[a].ModuleDatabase\r
119 \r
120         self.PackageDatabase = {}\r
121         for a in Workspace.Build:\r
122             self.PackageDatabase[a] = Workspace.Build[a].PackageDatabase\r
123 \r
124         self.PlatformDatabase = {}\r
125         for a in Workspace.Build:\r
126             self.PlatformDatabase[a] = Workspace.Build[a].PlatformDatabase\r
127 \r
128         # flag indicating if the makefile/C-code file has been created or not\r
129         self.IsMakeFileCreated = False\r
130         self.IsCodeFileCreated = False\r
131 \r
132         #\r
133         # collect build information for the platform\r
134         #\r
135         self.BuildInfo = {}     # arch : PlatformBuildInfo Object\r
136         self.Platform = {}\r
137 \r
138         for Arch in self.ArchList:\r
139             if Arch not in self.PlatformDatabase or self.PlatformFile not in self.PlatformDatabase[Arch]:\r
140                 EdkLogger.error("AutoGen", AUTOGEN_ERROR,\r
141                                 "[%s] is not the active platform, or [%s] is not supported by the active platform!"\r
142                                 % (PlatformFile, Arch))\r
143             Platform = self.PlatformDatabase[Arch][PlatformFile]\r
144             self.Platform[Arch] = Platform\r
145             self.BuildInfo[Arch] = self.CollectBuildInfo(Platform, Arch)\r
146 \r
147     ## hash() operator\r
148     #\r
149     #  The file path of platform file will be used to represent hash value of this object\r
150     #\r
151     #   @retval int     Hash value of the file path of platform file\r
152     #\r
153     def __hash__(self):\r
154         return hash(self.PlatformFile)\r
155 \r
156     ## str() operator\r
157     #\r
158     #  The file path of platform file will be used to represent this object\r
159     #\r
160     #   @retval string  String of platform file path\r
161     #\r
162     def __str__(self):\r
163         return self.PlatformFile\r
164 \r
165     ## Factory method to create a PlatformAutoGen object\r
166     #\r
167     #   This method will check if an object of PlatformAutoGen has been created\r
168     #   for given platform. And if true, just return it. Otherwise it will create\r
169     #   a new PlatformAutoGen. That means there will be only one PlatformAutoGen\r
170     #   object for the same platform.\r
171     #\r
172     #   @param      Workspace           EdkIIWorkspaceBuild object\r
173     #   @param      Platform            Platform file (DSC file)\r
174     #   @param      Target              Build target (DEBUG, RELEASE)\r
175     #   @param      Toolchain           Name of tool chain\r
176     #   @param      ArchList            List of arch the platform supports\r
177     #   @param      ModuleAutoGenFlag   Flag indicating if creating ModuleAutoGen\r
178     #                                   objects for mdoules in the platform or not\r
179     #\r
180     #   @retval     PlatformAutoGen object\r
181     #\r
182     @staticmethod\r
183     def New(Workspace, Platform, Target, Toolchain, ArchList, ModuleAutoGenFlag=False):\r
184         # check if the object for the platform has been created\r
185         Key = (Platform, Target, Toolchain)\r
186         if Key not in PlatformAutoGen._Database:\r
187             if ArchList == None or ArchList == []:\r
188                 return None\r
189             AutoGenObject = PlatformAutoGen()\r
190             AutoGenObject._Init(Workspace, Platform, Target, Toolchain, ArchList)\r
191             PlatformAutoGen._Database[Key] = AutoGenObject\r
192         else:\r
193             AutoGenObject = PlatformAutoGen._Database[Key]\r
194 \r
195         # create ModuleAutoGen objects for modules in the platform\r
196         if ModuleAutoGenFlag:\r
197             AutoGenObject.CreateModuleAutoGen()\r
198 \r
199         return AutoGenObject\r
200 \r
201     ## Collect build information for the platform\r
202     #\r
203     #  Collect build information, such as FDF file path, dynamic pcd list,\r
204     #  package list, tool chain configuration, build rules, etc.\r
205     #\r
206     #   @param      Platform            Platform file (DSC file)\r
207     #   @param      Arch                One of arch the platform supports\r
208     #\r
209     #   @retval     PlatformBuildInfo object\r
210     #\r
211     def CollectBuildInfo(self, Platform, Arch):\r
212         Info = PlatformBuildInfo(Platform)\r
213 \r
214         Info.Arch = Arch\r
215         Info.ToolChain = self.ToolChain\r
216         Info.BuildTarget = self.BuildTarget\r
217 \r
218         Info.WorkspaceDir = self.WorkspaceDir\r
219         Info.SourceDir = path.dirname(Platform.DescFilePath)\r
220         Info.OutputDir = Platform.OutputDirectory\r
221         Info.BuildDir = path.join(Info.OutputDir, self.BuildTarget + "_" + self.ToolChain)\r
222         Info.MakeFileDir = Info.BuildDir\r
223 \r
224         if self.Workspace.Fdf != "":\r
225             Info.FdfFile= path.join(self.WorkspaceDir, self.Workspace.Fdf)\r
226 \r
227         Info.NonDynamicPcdList, Info.DynamicPcdList = self.GetPcdList(Platform, Arch)\r
228         Info.PcdTokenNumber = self.GeneratePcdTokenNumber(Platform, Info.NonDynamicPcdList, Info.DynamicPcdList)\r
229         Info.PackageList = self.PackageDatabase[Arch].values()\r
230 \r
231         self.GetToolDefinition(Info)\r
232         Info.BuildRule = self.GetBuildRule()\r
233         Info.FdTargetList = self.Workspace.FdTargetList\r
234         Info.FvTargetList = self.Workspace.FvTargetList\r
235 \r
236         return Info\r
237 \r
238     ## Return directory of platform makefile\r
239     #\r
240     #   @retval     string  Makefile directory\r
241     #\r
242     def GetMakeFileDir(self):\r
243         return os.path.join(self.WorkspaceDir, self.BuildInfo[self.ArchList[0]].MakeFileDir)\r
244 \r
245     ## Return build command string\r
246     #\r
247     #   @retval     string  Build command string\r
248     #\r
249     def GetBuildCommand(self, Arch=None):\r
250         if Arch != None:\r
251             Arch = [Arch]\r
252         else:\r
253             Arch = self.ArchList\r
254         Command = tuple()\r
255         for A in Arch:\r
256             if A in self.BuildInfo and "MAKE" in self.BuildInfo[A].ToolPath:\r
257                 Command += (self.BuildInfo[A].ToolPath["MAKE"],)\r
258                 if "MAKE" in self.BuildInfo[A].ToolOption:\r
259                     NewOption = self.BuildInfo[A].ToolOption["MAKE"].strip()\r
260                     if NewOption != '':\r
261                       Command += (NewOption,)\r
262                 break\r
263         if len(Command) == 0:\r
264             EdkLogger.error("AutoGen", OPTION_MISSING, "No MAKE command defined. Please check your tools_def.txt!")\r
265         return Command\r
266 \r
267     ## Parse build_rule.txt in $(WORKSPACE)/Conf/build_rule.txt\r
268     #\r
269     #   @retval     BuildRule object\r
270     #\r
271     def GetBuildRule(self):\r
272         return BuildRule(self.Workspace.WorkspaceFile(gBuildRuleFile))\r
273 \r
274     ## Get tool chain definition\r
275     #\r
276     #  Get each tool defition for given tool chain from tools_def.txt and platform\r
277     #\r
278     #   @param      Info    PlatformBuildInfo object to store the definition\r
279     #\r
280     def GetToolDefinition(self, Info):\r
281         ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary\r
282         ToolCodeList = self.Workspace.ToolDef.ToolsDefTxtDatabase["COMMAND_TYPE"]\r
283         for Tool in ToolCodeList:\r
284             KeyBaseString = "%s_%s_%s_%s" % (Info.BuildTarget, Info.ToolChain, Info.Arch, Tool)\r
285 \r
286             Key = "%s_PATH" % KeyBaseString\r
287             if Key not in ToolDefinition:\r
288                 continue\r
289             Path = ToolDefinition[Key]\r
290 \r
291             Key = "%s_FAMILY" % KeyBaseString\r
292             if Key in ToolDefinition:\r
293                 Family = ToolDefinition[Key]\r
294             else:\r
295                 Family = ""\r
296 \r
297             Key = "%s_FLAGS" % KeyBaseString\r
298             if Key in ToolDefinition:\r
299                 Option = ToolDefinition[Key]\r
300             else:\r
301                 Option = ""\r
302 \r
303             Key = "%s_DLL" % KeyBaseString\r
304             if Key in ToolDefinition:\r
305                 Dll = ToolDefinition[Key]\r
306                 # set the DLL path in system's PATH environment\r
307                 os.environ["PATH"] = Dll + os.pathsep + os.environ["PATH"]\r
308             else:\r
309                 Dll = ""\r
310 \r
311             Key = KeyBaseString + "_OUTPUT"\r
312             if Key in ToolDefinition:\r
313                 OutputFlag = ToolDefinition[Key]\r
314             elif (Family, Tool, "OUTPUT") in gOutputFlag:\r
315                 OutputFlag = gOutputFlag[Family, Tool, "OUTPUT"]\r
316                 if OutputFlag[0] == '"' and OutputFlag[-1] == '"':\r
317                     OutputFlag = OutputFlag[1:-1]\r
318             else:\r
319                 OutputFlag = gDefaultOutputFlag\r
320 \r
321             InputFlag = gIncludeFlag[Family]\r
322 \r
323             Info.ToolPath[Tool] = Path\r
324             Info.ToolDllPath[Tool] = Dll\r
325             Info.ToolChainFamily[Tool] = Family\r
326             Info.ToolOption[Tool] = Option\r
327             Info.OutputFlag[Tool] = OutputFlag\r
328             Info.IncludeFlag[Tool] = InputFlag\r
329 \r
330         # get tool options from platform\r
331         BuildOptions = Info.Platform.BuildOptions\r
332         for Key in BuildOptions:\r
333             Family = Key[0]\r
334             Target, Tag, Arch, Tool, Attr = Key[1].split("_")\r
335             if Tool not in Info.ToolPath:\r
336                 continue\r
337             if Family != None and Family != "" and Family != Info.ToolChainFamily[Tool]:\r
338                 continue\r
339             if Target == "*" or Target == Info.BuildTarget:\r
340                 if Tag == "*" or Tag == Info.ToolChain:\r
341                     if Arch == "*" or Arch == Info.Arch:\r
342                         Info.BuildOption[Tool] = BuildOptions[Key]\r
343         for Tool in Info.ToolOption:\r
344             if Tool not in Info.BuildOption:\r
345                 Info.BuildOption[Tool] = ""\r
346 \r
347     ## Collect dynamic PCDs\r
348     #\r
349     #  Gather dynamic PCDs list from each module and their settings from platform\r
350     #\r
351     #   @param      Platform    The object of the platform\r
352     #   @param      Arch        One of the arch the platform supports\r
353     #\r
354     #   @retval     lsit        The list of dynamic PCD\r
355     #\r
356     def GetPcdList(self, Platform, Arch):\r
357         NonDynamicPcdList = []\r
358         DynamicPcdList = []\r
359 \r
360         # for gathering error information\r
361         NotFoundPcdList = set()\r
362         NoDatumTypePcdList = set()\r
363 \r
364         for F in Platform.Modules:\r
365             M = self.ModuleDatabase[Arch][F]\r
366             for Key in M.Pcds:\r
367                 PcdFromModule = M.Pcds[Key]\r
368                 # check if the setting of the PCD is found in platform\r
369                 if not PcdFromModule.IsOverrided:\r
370                     NotFoundPcdList.add("%s [%s]" % (" | ".join(Key), F))\r
371                     continue\r
372 \r
373                 # make sure that the "VOID*" kind of datum has MaxDatumSize set\r
374                 if PcdFromModule.DatumType == "VOID*" and PcdFromModule.MaxDatumSize == None:\r
375                     NoDatumTypePcdList.add("%s [%s]" % (" | ".join(Key), F))\r
376 \r
377                 if PcdFromModule.Type in GenC.gDynamicPcd or PcdFromModule.Type in GenC.gDynamicExPcd:\r
378                     # for autogen code purpose\r
379                     if M.ModuleType in ["PEIM", "PEI_CORE"]:\r
380                         PcdFromModule.Phase = "PEI"\r
381                     if PcdFromModule not in DynamicPcdList:\r
382                         DynamicPcdList.append(PcdFromModule)\r
383                 elif PcdFromModule not in NonDynamicPcdList:\r
384                     NonDynamicPcdList.append(PcdFromModule)\r
385 \r
386         # print out error information and break the build, if error found\r
387         if len(NotFoundPcdList) > 0 or len(NoDatumTypePcdList) > 0:\r
388             NotFoundPcdListString = "\n\t\t".join(NotFoundPcdList)\r
389             NoDatumTypePcdListString = "\n\t\t".join(NoDatumTypePcdList)\r
390             EdkLogger.error("AutoGen", AUTOGEN_ERROR, "PCD setting error",\r
391                             ExtraData="\n\tPCD(s) not found in platform:\n\t\t%s"\r
392                                       "\n\tPCD(s) without MaxDatumSize:\n\t\t%s\n"\r
393                                       % (NotFoundPcdListString, NoDatumTypePcdListString))\r
394         return NonDynamicPcdList, DynamicPcdList\r
395 \r
396     ## Generate Token Number for all PCD\r
397     #\r
398     #   @param      Platform        The object of the platform\r
399     #   @param      DynamicPcdList  The list of all dynamic PCDs\r
400     #\r
401     #   @retval     dict            A dict object containing the PCD and its token number\r
402     #\r
403     def GeneratePcdTokenNumber(self, Platform, NonDynamicPcdList, DynamicPcdList):\r
404         PcdTokenNumber = sdict()\r
405         TokenNumber = 1\r
406         for Pcd in DynamicPcdList:\r
407             if Pcd.Phase == "PEI":\r
408                 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))\r
409                 PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber\r
410                 TokenNumber += 1\r
411 \r
412         for Pcd in DynamicPcdList:\r
413             if Pcd.Phase == "DXE":\r
414                 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))\r
415                 PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber\r
416                 TokenNumber += 1\r
417 \r
418         for Pcd in NonDynamicPcdList:\r
419             PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber\r
420             TokenNumber += 1\r
421         return PcdTokenNumber\r
422 \r
423     ## Create autogen object for each module in platform\r
424     #\r
425     def CreateModuleAutoGen(self):\r
426         for Arch in self.BuildInfo:\r
427             Info = self.BuildInfo[Arch]\r
428             for ModuleFile in Info.Platform.LibraryInstances:\r
429                 ModuleAutoGen.New(self.Workspace, Info.Platform, ModuleFile,\r
430                                          Info.BuildTarget, Info.ToolChain, Info.Arch)\r
431 \r
432             for ModuleFile in Info.Platform.Modules:\r
433                 ModuleAutoGen.New(self.Workspace, Info.Platform, ModuleFile,\r
434                                          Info.BuildTarget, Info.ToolChain, Info.Arch)\r
435 \r
436     ## Create makefile for the platform and mdoules in it\r
437     #\r
438     #   @param      CreateLibraryCodeFile   Flag indicating if the makefile for\r
439     #                                       modules will be created as well\r
440     #\r
441     def CreateMakeFile(self, CreateModuleMakeFile=False):\r
442         if CreateModuleMakeFile:\r
443             for Arch in self.BuildInfo:\r
444                 Info = self.BuildInfo[Arch]\r
445                 for ModuleFile in Info.Platform.LibraryInstances:\r
446                     AutoGenObject = ModuleAutoGen.New(self.Workspace, Info.Platform, ModuleFile,\r
447                                                       Info.BuildTarget, Info.ToolChain, Info.Arch)\r
448                     AutoGenObject.CreateMakeFile(False)\r
449 \r
450                 for ModuleFile in Info.Platform.Modules:\r
451                     AutoGenObject = ModuleAutoGen.New(self.Workspace, Info.Platform, ModuleFile,\r
452                                                       Info.BuildTarget, Info.ToolChain, Info.Arch)\r
453                     AutoGenObject.CreateMakeFile(False)\r
454 \r
455         # no need to create makefile for the platform more than once\r
456         if self.IsMakeFileCreated:\r
457             return\r
458 \r
459         # create makefile for platform\r
460         Makefile = GenMake.Makefile(self.BuildInfo)\r
461         if Makefile.Generate():\r
462             EdkLogger.verbose("Generated makefile for platform [%s] [%s]\n" %\r
463                            (self.PlatformFile, " ".join(self.ArchList)))\r
464         else:\r
465             EdkLogger.verbose("Skipped the generation of makefile for platform [%s] [%s]\n" %\r
466                            (self.PlatformFile, " ".join(self.ArchList)))\r
467         self.IsMakeFileCreated = True\r
468 \r
469     ## Create autogen code for platform and modules\r
470     #\r
471     #  Since there's no autogen code for platform, this method will do nothing\r
472     #  if CreateModuleCodeFile is set to False.\r
473     #\r
474     #   @param      CreateModuleCodeFile    Flag indicating if creating module's\r
475     #                                       autogen code file or not\r
476     #\r
477     def CreateCodeFile(self, CreateModuleCodeFile=False):\r
478         # only module has code to be greated, so do nothing if CreateModuleCodeFile is False\r
479         if self.IsCodeFileCreated or not CreateModuleCodeFile:\r
480             return\r
481 \r
482         for Arch in self.BuildInfo:\r
483             Info = self.BuildInfo[Arch]\r
484             for ModuleFile in Info.Platform.LibraryInstances:\r
485                 AutoGenObject = ModuleAutoGen.New(self.Workspace, Info.Platform, ModuleFile,\r
486                                                   Info.BuildTarget, Info.ToolChain, Info.Arch)\r
487                 AutoGenObject.CreateCodeFile()\r
488 \r
489             for ModuleFile in Info.Platform.Modules:\r
490                 AutoGenObject = ModuleAutoGen.New(self.Workspace, Info.Platform, ModuleFile,\r
491                                                   Info.BuildTarget, Info.ToolChain, Info.Arch)\r
492                 AutoGenObject.CreateCodeFile()\r
493         # don't do this twice\r
494         self.IsCodeFileCreated = True\r
495 \r
496     ## Test if a module is supported by the platform\r
497     #\r
498     #  An error will be raised directly if the module or its arch is not supported\r
499     #  by the platform or current configuration\r
500     #\r
501     #   @param      Module  The module file\r
502     #   @param      Arch    The arch the module will be built for\r
503     #\r
504     def CheckModule(self, Module, Arch):\r
505         if Arch not in self.Workspace.SupArchList:\r
506             EdkLogger.error("AutoGen", AUTOGEN_ERROR, "[%s] is not supported by active platform [%s] [%s]!"\r
507                                                       % (Arch, self.PlatformFile, self.Workspace.SupArchList))\r
508         if Arch not in self.ArchList:\r
509             EdkLogger.error("AutoGen", AUTOGEN_ERROR, "[%s] is not supported by current build configuration!" % Arch)\r
510 \r
511         if str(Module) not in self.ModuleDatabase[Arch]:\r
512             EdkLogger.error("AutoGen", AUTOGEN_ERROR, "Module [%s] [%s] is not required by active platform [%s]!"\r
513                                                       % (Module, Arch, self.PlatformFile))\r
514 \r
515     ## Find the package containing the module\r
516     #\r
517     # Find out the package which contains the given module, according to the path\r
518     # of the module and the package.\r
519     #\r
520     # @param  Module            The module to be found for\r
521     #\r
522     # @retval package           Package object if found\r
523     # @retval None              None if not found\r
524     #\r
525     def GetModuleOwnerPackage(self, Module):\r
526         for Arch in self.PackageDatabase:\r
527             Pdb = self.PackageDatabase[Arch]\r
528             for PackagePath in Pdb:\r
529                 PackageDir = path.dirname(PackagePath)\r
530                 #\r
531                 # if package's path is the first part of module's path, bingo!\r
532                 #\r
533                 if str(Module).find(PackageDir) == 0:\r
534                     return Pdb[PackagePath]\r
535         # nothing found\r
536         return None\r
537 \r
538     ## Get platform object\r
539     #\r
540     #   @param      PlatformFile    The file path of the platform\r
541     #   @param      Arch            One of the arch the platform supports\r
542     #\r
543     #   @retval     object          The object of the platform\r
544     #\r
545     def GetPlatformObject(self, PlatformFile, Arch):\r
546         if Arch not in self.PlatformDatabase or PlatformFile not in self.PlatformDatabase[Arch]:\r
547             return None\r
548         return self.PlatformDatabase[Arch][PlatformFile]\r
549 \r
550     ## Get package object\r
551     #\r
552     #   @param      PackageFile     The file path of the package\r
553     #   @param      Arch            One of the arch the package supports\r
554     #\r
555     #   @retval     object          The object of the package\r
556     #\r
557     def GetPackageObject(self, PackageFile, Arch):\r
558         if Arch not in self.PackageDatabase or PackageFile not in self.PackageDatabase[Arch]:\r
559             return None\r
560         return self.PackageDatabase[Arch][PackageFile]\r
561 \r
562     ## Get module object\r
563     #\r
564     #   @param      ModuleFile      The file path of the module\r
565     #   @param      Arch            One of the arch the module supports\r
566     #\r
567     #   @retval     object          The object of the module\r
568     #\r
569     def GetModuleObject(self, ModuleFile, Arch):\r
570         if Arch not in self.ModuleDatabase or ModuleFile not in self.ModuleDatabase[Arch]:\r
571             return None\r
572         return self.ModuleDatabase[Arch][ModuleFile]\r
573 \r
574     ## Add ModuleAutoGen object for a module in platform build information\r
575     #\r
576     #   @param      ModuleAutoGen   The ModuleAutoGen object for a module\r
577     #   @param      Arch            The arch of the module\r
578     #\r
579     def AddModuleAutoGen(self, ModuleAutoGen, Arch):\r
580         if ModuleAutoGen not in self.BuildInfo[Arch].ModuleAutoGenList:\r
581             self.BuildInfo[Arch].ModuleAutoGenList.append(ModuleAutoGen)\r
582 \r
583     ## Add ModuleAutoGen object for a library in platform build information\r
584     #\r
585     #   @param      LibraryAutoGen  The ModuleAutoGen object for a library module\r
586     #   @param      Arch            The arch of the library\r
587     #\r
588     def AddLibraryAutoGen(self, LibraryAutoGen, Arch):\r
589         if LibraryAutoGen not in self.BuildInfo[Arch].LibraryAutoGenList:\r
590             self.BuildInfo[Arch].LibraryAutoGenList.append(LibraryAutoGen)\r
591 \r
592 ## AutoGen class\r
593 #\r
594 # This class encapsules the AutoGen behaviors for the build tools. In addition to\r
595 # the generation of AutoGen.h and AutoGen.c, it can generate *.depex file according\r
596 # to the [depex] section in module's inf file. The result of parsing unicode file\r
597 # has been incorporated either.\r
598 #\r
599 class ModuleAutoGen(object):\r
600     # The cache for the objects of ModuleAutoGen\r
601     _Database = {}\r
602     # The cache for the object of PlatformAutoGen\r
603     _PlatformAutoGen = None\r
604 \r
605     ## The real constructor of ModuleAutoGen\r
606     #\r
607     #  This method is not supposed to be called by users of ModuleAutoGen. It's\r
608     #  only used by factory method New() to do real initialization work for an\r
609     #  object of ModuleAutoGen\r
610     #\r
611     #   @param      Workspace           EdkIIWorkspaceBuild object\r
612     #   @param      PlatformAutoGenObj  Platform file (DSC file)\r
613     #   @param      ModuleFile          The path of module file\r
614     #   @param      Target              Build target (DEBUG, RELEASE)\r
615     #   @param      Toolchain           Name of tool chain\r
616     #   @param      Arch                The arch the module supports\r
617     #\r
618     def _Init(self, Workspace, PlatformAutoGenObj, ModuleFile, Target, Toolchain, Arch):\r
619         self.ModuleFile = str(ModuleFile)\r
620         self.PlatformFile = PlatformAutoGenObj.PlatformFile\r
621 \r
622         self.Workspace = Workspace\r
623         self.WorkspaceDir = Workspace.WorkspaceDir\r
624 \r
625         self.ToolChain = Toolchain\r
626         self.ToolChainFamily = "MSFT"\r
627         self.BuildTarget = Target\r
628         self.Arch = Arch\r
629 \r
630         self.IsMakeFileCreated = False\r
631         self.IsCodeFileCreated = False\r
632 \r
633         self.PlatformAutoGen = PlatformAutoGenObj\r
634         try:\r
635             self.PlatformAutoGen.CheckModule(ModuleFile, self.Arch)\r
636         except:\r
637             return False\r
638 \r
639         #\r
640         # autogen for module\r
641         #\r
642         EdkLogger.verbose("\nAutoGen module [%s] [%s]" % (ModuleFile, self.Arch))\r
643 \r
644         self.Platform = self.PlatformAutoGen.GetPlatformObject(self.PlatformFile, self.Arch)\r
645         self.Module = self.PlatformAutoGen.GetModuleObject(self.ModuleFile, self.Arch)\r
646 \r
647         self.Package = self.PlatformAutoGen.GetModuleOwnerPackage(self.Module)\r
648 \r
649         self.AutoGenC = TemplateString()\r
650         self.AutoGenH = TemplateString()\r
651 \r
652         self.BuildInfo = self.GetModuleBuildInfo()\r
653         return True\r
654 \r
655     ## "==" operator\r
656     #\r
657     #  Use module file path and arch to do the comparison\r
658     #\r
659     #   @retval True    if the file path and arch are equal\r
660     #   @retval False   if the file path or arch are different\r
661     #\r
662     def __eq__(self, Other):\r
663         return Other != None and self.ModuleFile == Other.ModuleFile and self.Arch == Other.Arch\r
664 \r
665     ## hash() operator\r
666     #\r
667     #  The file path and arch of the module will be used to represent hash value of this object\r
668     #\r
669     #   @retval int     Hash value of the file path and arch name of the module\r
670     #\r
671     def __hash__(self):\r
672         return hash(self.ModuleFile) + hash(self.Arch)\r
673 \r
674     ## String representation of this object\r
675     #\r
676     #   @retval     string  The string of file path and arch\r
677     #\r
678     def __str__(self):\r
679         return "%s [%s]" % (self.ModuleFile, self.Arch)\r
680 \r
681     ## Factory method to create a ModuleAutoGen object\r
682     #\r
683     #   This method will check if an object of ModuleAutoGen has been created\r
684     #   for given platform. And if true, just return it. Otherwise it will create\r
685     #   a new ModuleAutoGen. That means there will be only one ModuleAutoGen\r
686     #   object for the same platform.\r
687     #\r
688     #   @param      Workspace           EdkIIWorkspaceBuild object\r
689     #   @param      Platform            Platform file (DSC file)\r
690     #   @param      Module              Module file (INF file)\r
691     #   @param      Target              Build target (DEBUG, RELEASE)\r
692     #   @param      Toolchain           Name of tool chain\r
693     #   @param      Arch                The arch of the module\r
694     #\r
695     #   @retval     ModuleAutoGen object\r
696     #\r
697     @staticmethod\r
698     def New(Workspace, Platform, Module, Target, Toolchain, Arch):\r
699         # creating module autogen needs platform's autogen\r
700         _PlatformAutoGen = PlatformAutoGen.New(Workspace, Platform, Target, Toolchain, None)\r
701         if _PlatformAutoGen == None:\r
702             EdkLogger.error("AutoGen", AUTOGEN_ERROR, "No platform AutoGen available!")\r
703 \r
704         # check if the autogen for the module has been created or not\r
705         Key = (Module, Target, Toolchain, Arch)\r
706         if Key not in ModuleAutoGen._Database:\r
707             if Arch == None or Arch == "":\r
708                 return None\r
709             AutoGenObject = ModuleAutoGen()\r
710             if AutoGenObject._Init(Workspace, _PlatformAutoGen, Module, Target, Toolchain, Arch) == False:\r
711                 return None\r
712             ModuleAutoGen._Database[Key] = AutoGenObject\r
713 \r
714             # for new ModuleAutoGen object, put it in platform's AutoGen\r
715             if AutoGenObject.BuildInfo.IsLibrary:\r
716                 _PlatformAutoGen.AddLibraryAutoGen(AutoGenObject, Arch)\r
717             else:\r
718                 _PlatformAutoGen.AddModuleAutoGen(AutoGenObject, Arch)\r
719             return AutoGenObject\r
720 \r
721         return ModuleAutoGen._Database[Key]\r
722 \r
723     ## Gather module build information\r
724     #\r
725     #   @retval     Info    The object of ModuleBuildInfo\r
726     #\r
727     def GetModuleBuildInfo(self):\r
728         Info = ModuleBuildInfo(self.Module)\r
729         self.BuildInfo = Info\r
730         Info.PlatformInfo = self.PlatformAutoGen.BuildInfo[self.Arch]\r
731 \r
732         # basic information\r
733         Info.WorkspaceDir = self.WorkspaceDir\r
734         Info.BuildTarget = self.BuildTarget\r
735         Info.ToolChain = self.ToolChain\r
736         Info.Arch = self.Arch\r
737         Info.IsBinary = False\r
738         Info.BaseName = self.Module.BaseName\r
739         Info.FileBase, Info.FileExt = path.splitext(path.basename(self.Module.DescFilePath))\r
740         Info.SourceDir = path.dirname(self.Module.DescFilePath)\r
741         Info.BuildDir = os.path.join(Info.PlatformInfo.BuildDir,\r
742                                      Info.Arch,\r
743                                      Info.SourceDir,\r
744                                      Info.FileBase)\r
745         Info.OutputDir = os.path.join(Info.BuildDir, "OUTPUT")\r
746         Info.DebugDir = os.path.join(Info.BuildDir, "DEBUG")\r
747         Info.MakeFileDir = Info.BuildDir\r
748         if os.path.isabs(Info.BuildDir):\r
749             CreateDirectory(Info.OutputDir)\r
750             CreateDirectory(Info.DebugDir)\r
751         else:\r
752             CreateDirectory(os.path.join(self.WorkspaceDir, Info.OutputDir))\r
753             CreateDirectory(os.path.join(self.WorkspaceDir, Info.DebugDir))\r
754 \r
755         for Type in self.Module.CustomMakefile:\r
756             MakeType = gMakeTypeMap[Type]\r
757             Info.CustomMakeFile[MakeType] = os.path.join(Info.SourceDir, self.Module.CustomMakefile[Type])\r
758 \r
759         if self.Module.LibraryClass != None and self.Module.LibraryClass != []:\r
760             Info.IsLibrary = True\r
761             Info.DependentLibraryList = []\r
762         else:\r
763             Info.IsLibrary = False\r
764             Info.DependentLibraryList = self.GetSortedLibraryList()\r
765 \r
766         Info.DependentPackageList = self.GetDependentPackageList()\r
767         Info.DerivedPackageList = self.GetDerivedPackageList()\r
768 \r
769         Info.BuildOption = self.GetModuleBuildOption(Info.PlatformInfo)\r
770         if "DLINK" in Info.PlatformInfo.ToolStaticLib:\r
771             Info.SystemLibraryList = Info.PlatformInfo.ToolStaticLib["DLINK"]\r
772 \r
773         Info.PcdIsDriver = self.Module.PcdIsDriver\r
774         Info.PcdList = self.GetPcdList(Info.DependentLibraryList)\r
775         Info.GuidList = self.GetGuidList()\r
776         Info.ProtocolList = self.GetProtocolGuidList()\r
777         Info.PpiList = self.GetPpiGuidList()\r
778         Info.Macro = self.GetMacroList()\r
779         Info.DepexList = self.GetDepexTokenList(Info)\r
780 \r
781         Info.IncludePathList = [Info.SourceDir, Info.DebugDir]\r
782         Info.IncludePathList.extend(self.GetIncludePathList(Info.DependentPackageList))\r
783 \r
784         Info.SourceFileList = self.GetBuildFileList(Info)\r
785         Info.AutoGenFileList = self.GetAutoGenFileList(Info)\r
786 \r
787         return Info\r
788 \r
789     ## Return the directory of the makefile\r
790     #\r
791     #   @retval     string  The directory string of module's makefile\r
792     #\r
793     def GetMakeFileDir(self):\r
794         return os.path.join(self.WorkspaceDir, self.BuildInfo.MakeFileDir)\r
795 \r
796     ## Return build command string\r
797     #\r
798     #   @retval     string  Build command string\r
799     #\r
800     def GetBuildCommand(self):\r
801         return self.PlatformAutoGen.GetBuildCommand(self.Arch)\r
802 \r
803     ## Get object list of all packages the module and its dependent libraries belong to\r
804     #\r
805     #   @retval     list    The list of package object\r
806     #\r
807     def GetDerivedPackageList(self):\r
808         PackageList = []\r
809         for M in [self.Module] + self.BuildInfo.DependentLibraryList:\r
810             for Package in M.Packages:\r
811                 if Package not in PackageList:\r
812                     PackageList.append(self.PlatformAutoGen.GetPackageObject(Package, self.Arch))\r
813         return PackageList\r
814 \r
815     ## Parse dependency expression\r
816     #\r
817     #   @param      Info    The object of ModuleBuildInfo\r
818     #   @retval     list    The token list of the dependency expression after parsed\r
819     #\r
820     def GetDepexTokenList(self, Info):\r
821         Dxs = self.Module.Depex\r
822         EdkLogger.verbose("DEPEX string = %s" % Dxs)\r
823         #\r
824         # Append depex from dependent libraries\r
825         #\r
826         for Lib in Info.DependentLibraryList:\r
827             if Lib.Depex != None and Lib.Depex != "":\r
828                 if Dxs == None or Dxs == "":\r
829                     Dxs = Lib.Depex\r
830                 else:\r
831                     Dxs += " AND (" + Lib.Depex + ")"\r
832                 EdkLogger.verbose("DEPEX string (+%s) = %s" % (Lib.BaseName, Dxs))\r
833         if Dxs == "":\r
834             return []\r
835 \r
836         TokenList = gDepexTokenPattern.findall(Dxs)\r
837         EdkLogger.debug(EdkLogger.DEBUG_8, "TokenList(raw) = %s" % (TokenList))\r
838         for I in range(0, len(TokenList)):\r
839             Token = TokenList[I].strip()\r
840             if Token.endswith(".inf"):  # module file name\r
841                 ModuleFile = os.path.normpath(Token)\r
842                 Token = gModuleDatabase[ModuleFile].Guid\r
843             elif Token.upper() in GenDepex.DependencyExpression.SupportedOpcode: # Opcode name\r
844                 Token = Token.upper()\r
845             elif Token not in ['(', ')']:   # GUID C Name\r
846                 GuidCName = Token\r
847                 for P in Info.DerivedPackageList:\r
848                     if GuidCName in P.Protocols:\r
849                         Token = P.Protocols[GuidCName]\r
850                         break\r
851                     elif GuidCName in P.Ppis:\r
852                         Token = P.Ppis[GuidCName]\r
853                         break\r
854                     elif GuidCName in P.Guids:\r
855                         Token = P.Guids[GuidCName]\r
856                         break\r
857                 else:\r
858                     PackageListString = "\n\t".join([str(P) for P in self.BuildInfo.DerivedPackageList])\r
859                     EdkLogger.error("AutoGen", AUTOGEN_ERROR,\r
860                                     "GUID [%s] used in module [%s] cannot be found in dependent packages!"\r
861                                     % (GuidCName, self.Module),\r
862                                     ExtraData=PackageListString)\r
863             TokenList[I] = Token\r
864         EdkLogger.debug(EdkLogger.DEBUG_8, "TokenList(guid) = %s" % " ".join(TokenList))\r
865         return TokenList\r
866 \r
867     ## Return the list of macro in module\r
868     #\r
869     #   @retval     list    The list of macro defined in module file\r
870     #\r
871     def GetMacroList(self):\r
872         # return ["%s %s" % (Name, self.Module.Specification[Name]) for Name in self.Module.Specification]\r
873         return self.Module.Specification\r
874 \r
875     ## Tool option for the module build\r
876     #\r
877     #   @param      PlatformInfo    The object of PlatformBuildInfo\r
878     #   @retval     dict            The dict containing valid options\r
879     #\r
880     def GetModuleBuildOption(self, PlatformInfo):\r
881         BuildOption = self.Module.BuildOptions\r
882         OptionList = {}\r
883         for Key in BuildOption:\r
884             Family = Key[0]\r
885             Target, Tag, Arch, Tool, Attr = Key[1].split("_")\r
886             # if no tool defined for the option, skip it\r
887             if Tool not in PlatformInfo.ToolPath:\r
888                 continue\r
889             # if tool chain family doesn't match, skip it\r
890             if Family != None and Family != "" and Family != PlatformInfo.ToolChainFamily[Tool]:\r
891                 continue\r
892             # expand any wildcard\r
893             if Target == "*" or Target == self.BuildTarget:\r
894                 if Tag == "*" or Tag == self.ToolChain:\r
895                     if Arch == "*" or Arch == self.Arch:\r
896                         if Tool not in OptionList:\r
897                             OptionList[Tool] = BuildOption[Key]\r
898                         else:\r
899                             # append options for the same tool\r
900                             OptionList[Tool] = OptionList[Tool] + " " + BuildOption[Key]\r
901         # for those tools that have no option in module file, give it a empty string\r
902         for Tool in PlatformInfo.ToolOption:\r
903             if Tool not in OptionList:\r
904                 OptionList[Tool] = ""\r
905 \r
906         return OptionList\r
907 \r
908     ## Return a list of files which can be built\r
909     #\r
910     #  What kind of files can be built is determined by build rules in\r
911     #  $(WORKSPACE)/Conf/build_rule.txt and toolchain family.\r
912     #\r
913     #   @param      PlatformInfo    The object of PlatformBuildInfo\r
914     #   @retval     list            The list of files which can be built later\r
915     #\r
916     def GetBuildFileList(self, Info):\r
917         # use toolchain family of CC as the primary toolchain family\r
918         ToolChainFamily = Info.PlatformInfo.ToolChainFamily["CC"]\r
919         BuildRule = Info.PlatformInfo.BuildRule\r
920         BuildFileList = []\r
921         for F in self.Module.Sources:\r
922             SourceFile = F.SourceFile\r
923             # match tool chain\r
924             if F.TagName != "" and F.TagName != self.ToolChain:\r
925                 EdkLogger.verbose("The toolchain [%s] for processing file [%s] is found, "\r
926                                   "but [%s] is needed" % (F.TagName, F.SourceFile, self.ToolChain))\r
927                 continue\r
928             # match tool chain family\r
929             if F.ToolChainFamily != "" and F.ToolChainFamily != ToolChainFamily:\r
930                 EdkLogger.verbose("The file [%s] must be built by tools of [%s], "\r
931                                   "but current toolchain family is [%s]" % (SourceFile, F.ToolChainFamily, ToolChainFamily))\r
932                 continue\r
933 \r
934             # add the file path into search path list for file including\r
935             Dir = path.dirname(SourceFile)\r
936             if Dir != "":\r
937                 Dir = path.join(self.BuildInfo.SourceDir, Dir)\r
938                 if Dir not in self.BuildInfo.IncludePathList:\r
939                     self.BuildInfo.IncludePathList.insert(0, Dir)\r
940 \r
941             # skip unknown file\r
942             Base, Ext = path.splitext(SourceFile)\r
943 \r
944             # skip file which needs a tool having no matching toolchain family\r
945             FileType, RuleObject = BuildRule.Get(Ext, ToolChainFamily)\r
946             if FileType == None:\r
947                 EdkLogger.verbose("Don't know how to process file [%s]." % SourceFile)\r
948                 continue\r
949 \r
950             # unicode must be processed by AutoGen\r
951             if FileType == "Unicode-Text-File":\r
952                 self.BuildInfo.UnicodeFileList.append(os.path.join(self.WorkspaceDir, self.BuildInfo.SourceDir, SourceFile))\r
953                 continue\r
954 \r
955             # if there's dxs file, don't use content in [depex] section to generate .depex file\r
956             if FileType == "Dependency-Expression-File":\r
957                 Info.DepexList = []\r
958 \r
959             # no command, no build\r
960             if RuleObject == None or RuleObject.CommandList == []:\r
961                 Buildable = False\r
962                 EdkLogger.verbose("No rule or command defined for building [%s], ignore file [%s]" % (FileType, SourceFile))\r
963                 continue\r
964 \r
965             BuildFileList.append([SourceFile, FileType, RuleObject])\r
966 \r
967         return BuildFileList\r
968 \r
969     ## Get the list of package object the module depends on\r
970     #\r
971     #   @retval     list    The package object list\r
972     #\r
973     def GetDependentPackageList(self):\r
974         PackageList = []\r
975         for PackageFile in self.Module.Packages:\r
976             if PackageFile in PackageList:\r
977                 continue\r
978             Package = self.PlatformAutoGen.GetPackageObject(PackageFile, self.Arch)\r
979             if Package == None:\r
980                 EdkLogger.error("AutoGen", FILE_NOT_FOUND, ExtraData=PackageFile)\r
981             PackageList.append(Package)\r
982         return PackageList\r
983 \r
984     ## Return the list of auto-generated code file\r
985     #\r
986     #   @param      BuildInfo   The object ModuleBuildInfo\r
987     #   @retval     list        The list of auto-generated file\r
988     #\r
989     def GetAutoGenFileList(self, BuildInfo):\r
990         GenC.CreateCode(BuildInfo, self.AutoGenC, self.AutoGenH)\r
991         FileList = []\r
992         if self.AutoGenC.String != "":\r
993             FileList.append("AutoGen.c")\r
994         if self.AutoGenH.String != "":\r
995             FileList.append("AutoGen.h")\r
996         return FileList\r
997 \r
998     ## Get the list of library module object\r
999     #\r
1000     #   @retval     list    The list of library module list\r
1001     #\r
1002     def GetSortedLibraryList(self):\r
1003         LibraryList = []\r
1004         for Key in self.Module.LibraryClasses:\r
1005             Library = self.PlatformAutoGen.GetModuleObject(self.Module.LibraryClasses[Key], self.Arch)\r
1006             if Library not in LibraryList:\r
1007                 LibraryList.append(Library)\r
1008         return LibraryList\r
1009 \r
1010     ## Get the list of PCD\r
1011     #\r
1012     #   @param      DependentLibraryList    The list of dependent library\r
1013     #   @retval     list                    The list of PCD\r
1014     #\r
1015     def GetPcdList(self, DependentLibraryList):\r
1016         PcdList = []\r
1017         for PcdKey in self.Module.Pcds:\r
1018             PcdList.append(self.Module.Pcds[PcdKey])\r
1019         return PcdList\r
1020 \r
1021     ## Get the GUID value mapping\r
1022     #\r
1023     #   @retval     dict    The mapping between GUID cname and its value\r
1024     #\r
1025     def GetGuidList(self):\r
1026         Guid = {}\r
1027         Key = ""\r
1028         for Key in self.Module.Guids:\r
1029             for P in self.BuildInfo.DerivedPackageList:\r
1030                 if Key in P.Guids:\r
1031                     Guid[Key] = P.Guids[Key]\r
1032                     break\r
1033                 if Key in P.Protocols:\r
1034                     Guid[Key] = P.Protocols[Key]\r
1035                     break\r
1036                 if Key in P.Ppis:\r
1037                     Guid[Key] = P.Ppis[Key]\r
1038                     break\r
1039             else:\r
1040                 PackageListString = "\t" + "\n\t".join([str(P) for P in self.BuildInfo.DerivedPackageList])\r
1041                 EdkLogger.error("AutoGen", AUTOGEN_ERROR, 'GUID [%s] used by [%s] cannot be found in dependent packages' % (Key, self.Module),\r
1042                                 ExtraData=PackageListString)\r
1043         return Guid\r
1044 \r
1045     ## Get the protocol value mapping\r
1046     #\r
1047     #   @retval     dict    The mapping between protocol cname and its value\r
1048     #\r
1049     def GetProtocolGuidList(self):\r
1050         Guid = {}\r
1051         Key = ""\r
1052         for Key in self.Module.Protocols:\r
1053             for P in self.BuildInfo.DerivedPackageList:\r
1054                 if Key in P.Guids:\r
1055                     Guid[Key] = P.Guids[Key]\r
1056                     break\r
1057                 if Key in P.Protocols:\r
1058                     Guid[Key] = P.Protocols[Key]\r
1059                     break\r
1060                 if Key in P.Ppis:\r
1061                     Guid[Key] = P.Ppis[Key]\r
1062                     break\r
1063             else:\r
1064                 PackageListString = "\t" + "\n\t".join([str(P) for P in self.BuildInfo.DerivedPackageList])\r
1065                 EdkLogger.error("AutoGen", AUTOGEN_ERROR, 'Protocol [%s] used by [%s] cannot be found in dependent packages' % (Key, self.Module),\r
1066                                 ExtraData=PackageListString)\r
1067         return Guid\r
1068 \r
1069     ## Get the PPI value mapping\r
1070     #\r
1071     #   @retval     dict    The mapping between PPI cname and its value\r
1072     #\r
1073     def GetPpiGuidList(self):\r
1074         Guid = {}\r
1075         Key = ""\r
1076         for Key in self.Module.Ppis:\r
1077             for P in self.BuildInfo.DerivedPackageList:\r
1078                 if Key in P.Guids:\r
1079                     Guid[Key] = P.Guids[Key]\r
1080                     break\r
1081                 if Key in P.Protocols:\r
1082                     Guid[Key] = P.Protocols[Key]\r
1083                     break\r
1084                 if Key in P.Ppis:\r
1085                     Guid[Key] = P.Ppis[Key]\r
1086                     break\r
1087             else:\r
1088                 PackageListString = "\t" + "\n\t".join([str(P) for P in self.BuildInfo.DerivedPackageList])\r
1089                 EdkLogger.error("AutoGen", AUTOGEN_ERROR, 'PPI [%s] used by [%s] cannot be found in dependent packages' % (Key, self.Module),\r
1090                                 ExtraData=PackageListString)\r
1091         return Guid\r
1092 \r
1093     ## Get the list of include search path\r
1094     #\r
1095     #   @param      DependentPackageList    The list of package object\r
1096     #   @retval     list                    The list path\r
1097     #\r
1098     def GetIncludePathList(self, DependentPackageList):\r
1099         IncludePathList = []\r
1100         for Inc in self.Module.Includes:\r
1101             # '.' means "relative to module directory".\r
1102             if Inc[0] == ".":\r
1103                 Inc = os.path.join(self.BuildInfo.SourceDir, Inc)\r
1104             IncludePathList.append(Inc)\r
1105             # for r8 modules\r
1106             IncludePathList.append(os.path.join(Inc, self.Arch.capitalize()))\r
1107 \r
1108         for Package in DependentPackageList:\r
1109             PackageDir = path.dirname(Package.DescFilePath)\r
1110             IncludePathList.append(PackageDir)\r
1111             for Inc in Package.Includes:\r
1112                 Inc = os.path.join(PackageDir, Inc)\r
1113                 if Inc not in IncludePathList:\r
1114                     IncludePathList.append(Inc)\r
1115         return IncludePathList\r
1116 \r
1117     ## Create makefile for the module and its dependent libraries\r
1118     #\r
1119     #   @param      CreateLibraryMakeFile   Flag indicating if or not the makefiles of\r
1120     #                                       dependent libraries will be created\r
1121     #\r
1122     def CreateMakeFile(self, CreateLibraryMakeFile=True):\r
1123         if self.IsMakeFileCreated:\r
1124             return\r
1125 \r
1126         PlatformInfo = self.BuildInfo.PlatformInfo\r
1127         if CreateLibraryMakeFile:\r
1128             for Lib in self.BuildInfo.DependentLibraryList:\r
1129                 EdkLogger.debug(EdkLogger.DEBUG_1, "###" + str(Lib))\r
1130                 LibraryAutoGen = ModuleAutoGen.New(self.Workspace, self.Platform, Lib,\r
1131                                                           self.BuildTarget, self.ToolChain, self.Arch)\r
1132                 if LibraryAutoGen not in self.BuildInfo.LibraryAutoGenList:\r
1133                     self.BuildInfo.LibraryAutoGenList.append(LibraryAutoGen)\r
1134                 LibraryAutoGen.CreateMakeFile()\r
1135 \r
1136         Makefile = GenMake.Makefile(self.BuildInfo)\r
1137         if Makefile.Generate():\r
1138             EdkLogger.verbose("Generated makefile for module %s [%s]" %\r
1139                            (self.BuildInfo.Name, self.BuildInfo.Arch))\r
1140         else:\r
1141             EdkLogger.verbose("Skipped the generation of makefile for module %s [%s]" %\r
1142                               (self.BuildInfo.Name, self.BuildInfo.Arch))\r
1143 \r
1144         self.IsMakeFileCreated = True\r
1145 \r
1146     ## Create autogen code for the module and its dependent libraries\r
1147     #\r
1148     #   @param      CreateLibraryCodeFile   Flag indicating if or not the code of\r
1149     #                                       dependent libraries will be created\r
1150     #\r
1151     def CreateCodeFile(self, CreateLibraryCodeFile=True):\r
1152         if self.IsCodeFileCreated:\r
1153             return\r
1154 \r
1155         PlatformInfo = self.BuildInfo.PlatformInfo\r
1156         if CreateLibraryCodeFile:\r
1157             for Lib in self.BuildInfo.DependentLibraryList:\r
1158                 LibraryAutoGen = ModuleAutoGen.New(self.Workspace, self.Platform, Lib,\r
1159                                                           self.BuildTarget, self.ToolChain, self.Arch)\r
1160                 if LibraryAutoGen not in self.BuildInfo.LibraryAutoGenList:\r
1161                     self.BuildInfo.LibraryAutoGenList.append(LibraryAutoGen)\r
1162                 LibraryAutoGen.CreateCodeFile()\r
1163 \r
1164         AutoGenList = []\r
1165         IgoredAutoGenList = []\r
1166         if self.AutoGenC.String != "":\r
1167             if GenC.Generate(os.path.join(self.BuildInfo.WorkspaceDir, self.BuildInfo.DebugDir, gAutoGenCodeFileName),\r
1168                              self.AutoGenC.String):\r
1169                 AutoGenList.append(gAutoGenCodeFileName)\r
1170             else:\r
1171                 IgoredAutoGenList.append(gAutoGenCodeFileName)\r
1172 \r
1173         if self.AutoGenH.String != "":\r
1174             if GenC.Generate(os.path.join(self.BuildInfo.WorkspaceDir, self.BuildInfo.DebugDir, gAutoGenHeaderFileName),\r
1175                              self.AutoGenH.String):\r
1176                 AutoGenList.append(gAutoGenHeaderFileName)\r
1177             else:\r
1178                 IgoredAutoGenList.append(gAutoGenHeaderFileName)\r
1179 \r
1180         if self.BuildInfo.DepexList != []:\r
1181             Dpx = GenDepex.DependencyExpression(self.BuildInfo.DepexList, self.BuildInfo.ModuleType)\r
1182             DpxFile = gAutoGenDepexFileName % {"module_name" : self.BuildInfo.Name}\r
1183             if Dpx.Generate(os.path.join(self.WorkspaceDir, self.BuildInfo.OutputDir, DpxFile)):\r
1184                 AutoGenList.append(DpxFile)\r
1185             else:\r
1186                 IgoredAutoGenList.append(DpxFile)\r
1187 \r
1188         if IgoredAutoGenList == []:\r
1189             EdkLogger.verbose("Generated [%s] files for module %s [%s]" %\r
1190                            (" ".join(AutoGenList), self.BuildInfo.Name, self.BuildInfo.Arch))\r
1191         elif AutoGenList == []:\r
1192             EdkLogger.verbose("Skipped the generation of [%s] files for module %s [%s]" %\r
1193                            (" ".join(IgoredAutoGenList), self.BuildInfo.Name, self.BuildInfo.Arch))\r
1194         else:\r
1195             EdkLogger.verbose("Generated [%s] (skipped %s) files for module %s [%s]" %\r
1196                            (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.BuildInfo.Name, self.BuildInfo.Arch))\r
1197 \r
1198         self.IsCodeFileCreated = True\r
1199         return AutoGenList\r
1200 \r
1201 # Version and Copyright\r
1202 __version_number__ = "0.01"\r
1203 __version__ = "%prog Version " + __version_number__\r
1204 __copyright__ = "Copyright (c) 2007, Intel Corporation. All rights reserved."\r
1205 \r
1206 ## Parse command line options\r
1207 #\r
1208 # Using standard Python module optparse to parse command line option of this tool.\r
1209 #\r
1210 # @retval Options   A optparse.Values object containing the parsed options\r
1211 # @retval InputFile Path of file to be trimmed\r
1212 #\r
1213 def GetOptions():\r
1214     OptionList = [\r
1215         make_option("-a", "--arch", dest="Arch",\r
1216                           help="The input file is preprocessed source code, including C or assembly code"),\r
1217         make_option("-p", "--platform", dest="ActivePlatform",\r
1218                           help="The input file is preprocessed VFR file"),\r
1219         make_option("-m", "--module", dest="ActiveModule",\r
1220                           help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),\r
1221         make_option("-f", "--FDF-file", dest="FdfFile",\r
1222                           help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),\r
1223         make_option("-o", "--output", dest="OutputDirectory",\r
1224                           help="File to store the trimmed content"),\r
1225         make_option("-t", "--toolchain-tag", dest="ToolChain",\r
1226                           help=""),\r
1227         make_option("-k", "--msft", dest="MakefileType", action="store_const", const="nmake",\r
1228                           help=""),\r
1229         make_option("-g", "--gcc", dest="MakefileType", action="store_const", const="gmake",\r
1230                           help=""),\r
1231         make_option("-v", "--verbose", dest="LogLevel", action="store_const", const=EdkLogger.VERBOSE,\r
1232                           help="Run verbosely"),\r
1233         make_option("-d", "--debug", dest="LogLevel", type="int",\r
1234                           help="Run with debug information"),\r
1235         make_option("-q", "--quiet", dest="LogLevel", action="store_const", const=EdkLogger.QUIET,\r
1236                           help="Run quietly"),\r
1237         make_option("-?", action="help", help="show this help message and exit"),\r
1238     ]\r
1239 \r
1240     # use clearer usage to override default usage message\r
1241     UsageString = "%prog [-a ARCH] [-p PLATFORM] [-m MODULE] [-t TOOLCHAIN_TAG] [-k] [-g] [-v|-d <debug_level>|-q] [-o <output_directory>] [GenC|GenMake]"\r
1242 \r
1243     Parser = OptionParser(description=__copyright__, version=__version__, option_list=OptionList, usage=UsageString)\r
1244     Parser.set_defaults(Arch=[])\r
1245     Parser.set_defaults(ActivePlatform=None)\r
1246     Parser.set_defaults(ActiveModule=None)\r
1247     Parser.set_defaults(OutputDirectory="build")\r
1248     Parser.set_defaults(FdfFile=None)\r
1249     Parser.set_defaults(ToolChain="MYTOOLS")\r
1250     if sys.platform == "win32":\r
1251         Parser.set_defaults(MakefileType="nmake")\r
1252     else:\r
1253         Parser.set_defaults(MakefileType="gmake")\r
1254     Parser.set_defaults(LogLevel=EdkLogger.INFO)\r
1255 \r
1256     Options, Args = Parser.parse_args()\r
1257 \r
1258     # error check\r
1259     if len(Args) == 0:\r
1260         Options.Target = "genmake"\r
1261         sys.argv.append("genmake")\r
1262     elif len(Args) == 1:\r
1263         Options.Target = Args[0].lower()\r
1264         if Options.Target not in ["genc", "genmake"]:\r
1265             EdkLogger.error("AutoGen", OPTION_NOT_SUPPORTED, "Not supported target",\r
1266                             ExtraData="%s\n\n%s" % (Options.Target, Parser.get_usage()))\r
1267     else:\r
1268         EdkLogger.error("AutoGen", OPTION_NOT_SUPPORTED, "Too many targets",\r
1269                         ExtraData=Parser.get_usage())\r
1270 \r
1271     return Options\r
1272 \r
1273 ## Entrance method\r
1274 #\r
1275 # This method mainly dispatch specific methods per the command line options.\r
1276 # If no error found, return zero value so the caller of this tool can know\r
1277 # if it's executed successfully or not.\r
1278 #\r
1279 # @retval 0     Tool was successful\r
1280 # @retval 1     Tool failed\r
1281 #\r
1282 def Main():\r
1283     from build import build\r
1284     try:\r
1285         Option = GetOptions()\r
1286         build.main()\r
1287     except Exception, e:\r
1288         print e\r
1289         return 1\r
1290 \r
1291     return 0\r
1292 \r
1293 # This acts like the main() function for the script, unless it is 'import'ed into another script.\r
1294 if __name__ == '__main__':\r
1295     sys.exit(Main())\r