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