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