2014-01-27 06:23:15 +01:00
|
|
|
## @file
|
|
|
|
# The engine for building files
|
|
|
|
#
|
2014-08-15 05:06:48 +02:00
|
|
|
# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
|
2014-01-27 06:23:15 +01:00
|
|
|
# This program and the accompanying materials
|
|
|
|
# are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
# which accompanies this distribution. The full text of the license may be found at
|
|
|
|
# http://opensource.org/licenses/bsd-license.php
|
|
|
|
#
|
|
|
|
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
#
|
|
|
|
|
|
|
|
##
|
|
|
|
# Import Modules
|
|
|
|
#
|
2014-08-15 05:06:48 +02:00
|
|
|
import Common.LongFilePathOs as os
|
2014-01-27 06:23:15 +01:00
|
|
|
import re
|
|
|
|
import copy
|
|
|
|
import string
|
2014-08-15 05:06:48 +02:00
|
|
|
from Common.LongFilePathSupport import OpenLongFilePath as open
|
2014-01-27 06:23:15 +01:00
|
|
|
|
|
|
|
from Common.GlobalData import *
|
|
|
|
from Common.BuildToolError import *
|
|
|
|
from Common.Misc import tdict, PathClass
|
|
|
|
from Common.String import NormPath
|
|
|
|
from Common.DataType import *
|
|
|
|
|
|
|
|
import Common.EdkLogger as EdkLogger
|
|
|
|
|
|
|
|
## Convert file type to file list macro name
|
|
|
|
#
|
|
|
|
# @param FileType The name of file type
|
|
|
|
#
|
|
|
|
# @retval string The name of macro
|
|
|
|
#
|
|
|
|
def FileListMacro(FileType):
|
|
|
|
return "%sS" % FileType.replace("-", "_").upper()
|
|
|
|
|
|
|
|
## Convert file type to list file macro name
|
|
|
|
#
|
|
|
|
# @param FileType The name of file type
|
|
|
|
#
|
|
|
|
# @retval string The name of macro
|
|
|
|
#
|
|
|
|
def ListFileMacro(FileType):
|
|
|
|
return "%s_LIST" % FileListMacro(FileType)
|
|
|
|
|
|
|
|
class TargetDescBlock(object):
|
|
|
|
_Cache_ = {} # {TargetFile : TargetDescBlock object}
|
|
|
|
|
|
|
|
# Factory method
|
|
|
|
def __new__(Class, Inputs, Outputs, Commands, Dependencies):
|
|
|
|
if Outputs[0] in Class._Cache_:
|
|
|
|
Tdb = Class._Cache_[Outputs[0]]
|
|
|
|
for File in Inputs:
|
|
|
|
Tdb.AddInput(File)
|
|
|
|
else:
|
|
|
|
Tdb = super(TargetDescBlock, Class).__new__(Class)
|
|
|
|
Tdb._Init(Inputs, Outputs, Commands, Dependencies)
|
|
|
|
#Class._Cache_[Outputs[0]] = Tdb
|
|
|
|
return Tdb
|
|
|
|
|
|
|
|
def _Init(self, Inputs, Outputs, Commands, Dependencies):
|
|
|
|
self.Inputs = Inputs
|
|
|
|
self.Outputs = Outputs
|
|
|
|
self.Commands = Commands
|
|
|
|
self.Dependencies = Dependencies
|
|
|
|
if self.Outputs:
|
|
|
|
self.Target = self.Outputs[0]
|
|
|
|
else:
|
|
|
|
self.Target = None
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.Target.Path
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.Target.Path)
|
|
|
|
|
|
|
|
def __eq__(self, Other):
|
|
|
|
if type(Other) == type(self):
|
|
|
|
return Other.Target.Path == self.Target.Path
|
|
|
|
else:
|
|
|
|
return str(Other) == self.Target.Path
|
|
|
|
|
|
|
|
def AddInput(self, Input):
|
|
|
|
if Input not in self.Inputs:
|
|
|
|
self.Inputs.append(Input)
|
|
|
|
|
|
|
|
def IsMultipleInput(self):
|
|
|
|
return len(self.Inputs) > 1
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def Renew():
|
|
|
|
TargetDescBlock._Cache_ = {}
|
|
|
|
|
|
|
|
## Class for one build rule
|
|
|
|
#
|
|
|
|
# This represents a build rule which can give out corresponding command list for
|
|
|
|
# building the given source file(s). The result can be used for generating the
|
|
|
|
# target for makefile.
|
|
|
|
#
|
|
|
|
class FileBuildRule:
|
|
|
|
INC_LIST_MACRO = "INC_LIST"
|
|
|
|
INC_MACRO = "INC"
|
|
|
|
|
|
|
|
## constructor
|
|
|
|
#
|
|
|
|
# @param Input The dictionary represeting input file(s) for a rule
|
|
|
|
# @param Output The list represeting output file(s) for a rule
|
|
|
|
# @param Command The list containing commands to generate the output from input
|
|
|
|
#
|
|
|
|
def __init__(self, Type, Input, Output, Command, ExtraDependency=None):
|
|
|
|
# The Input should not be empty
|
|
|
|
if not Input:
|
|
|
|
Input = []
|
|
|
|
if not Output:
|
|
|
|
Output = []
|
|
|
|
if not Command:
|
|
|
|
Command = []
|
|
|
|
|
|
|
|
self.FileListMacro = FileListMacro(Type)
|
|
|
|
self.ListFileMacro = ListFileMacro(Type)
|
|
|
|
self.IncListFileMacro = self.INC_LIST_MACRO
|
|
|
|
|
|
|
|
self.SourceFileType = Type
|
|
|
|
# source files listed not in "*" or "?" pattern format
|
|
|
|
if not ExtraDependency:
|
|
|
|
self.ExtraSourceFileList = []
|
|
|
|
else:
|
|
|
|
self.ExtraSourceFileList = ExtraDependency
|
|
|
|
|
|
|
|
#
|
|
|
|
# Search macros used in command lines for <FILE_TYPE>_LIST and INC_LIST.
|
|
|
|
# If found, generate a file to keep the input files used to get over the
|
|
|
|
# limitation of command line length
|
|
|
|
#
|
|
|
|
self.MacroList = []
|
|
|
|
self.CommandList = []
|
|
|
|
for CmdLine in Command:
|
|
|
|
self.MacroList.extend(gMacroRefPattern.findall(CmdLine))
|
|
|
|
# replace path separator with native one
|
|
|
|
self.CommandList.append(CmdLine)
|
|
|
|
|
|
|
|
# Indicate what should be generated
|
|
|
|
if self.FileListMacro in self.MacroList:
|
|
|
|
self.GenFileListMacro = True
|
|
|
|
else:
|
|
|
|
self.GenFileListMacro = False
|
|
|
|
|
|
|
|
if self.ListFileMacro in self.MacroList:
|
|
|
|
self.GenListFile = True
|
|
|
|
self.GenFileListMacro = True
|
|
|
|
else:
|
|
|
|
self.GenListFile = False
|
|
|
|
|
|
|
|
if self.INC_LIST_MACRO in self.MacroList:
|
|
|
|
self.GenIncListFile = True
|
|
|
|
else:
|
|
|
|
self.GenIncListFile = False
|
|
|
|
|
|
|
|
# Check input files
|
|
|
|
self.IsMultipleInput = False
|
|
|
|
self.SourceFileExtList = []
|
|
|
|
for File in Input:
|
|
|
|
Base, Ext = os.path.splitext(File)
|
|
|
|
if Base.find("*") >= 0:
|
|
|
|
# There's "*" in the file name
|
|
|
|
self.IsMultipleInput = True
|
|
|
|
self.GenFileListMacro = True
|
|
|
|
elif Base.find("?") < 0:
|
|
|
|
# There's no "*" and "?" in file name
|
|
|
|
self.ExtraSourceFileList.append(File)
|
|
|
|
continue
|
|
|
|
if Ext not in self.SourceFileExtList:
|
|
|
|
self.SourceFileExtList.append(Ext)
|
|
|
|
|
|
|
|
# Check output files
|
|
|
|
self.DestFileList = []
|
|
|
|
for File in Output:
|
|
|
|
self.DestFileList.append(File)
|
|
|
|
|
|
|
|
# All build targets generated by this rule for a module
|
|
|
|
self.BuildTargets = {}
|
|
|
|
|
|
|
|
## str() function support
|
|
|
|
#
|
|
|
|
# @retval string
|
|
|
|
#
|
|
|
|
def __str__(self):
|
|
|
|
SourceString = ""
|
|
|
|
SourceString += " %s %s %s" % (self.SourceFileType, " ".join(self.SourceFileExtList), self.ExtraSourceFileList)
|
|
|
|
DestString = ", ".join(self.DestFileList)
|
|
|
|
CommandString = "\n\t".join(self.CommandList)
|
|
|
|
return "%s : %s\n\t%s" % (DestString, SourceString, CommandString)
|
|
|
|
|
|
|
|
## Check if given file extension is supported by this rule
|
|
|
|
#
|
|
|
|
# @param FileExt The extension of a file
|
|
|
|
#
|
|
|
|
# @retval True If the extension is supported
|
|
|
|
# @retval False If the extension is not supported
|
|
|
|
#
|
|
|
|
def IsSupported(self, FileExt):
|
|
|
|
return FileExt in self.SourceFileExtList
|
|
|
|
|
|
|
|
def Instantiate(self, Macros={}):
|
|
|
|
NewRuleObject = copy.copy(self)
|
|
|
|
NewRuleObject.BuildTargets = {}
|
|
|
|
NewRuleObject.DestFileList = []
|
|
|
|
for File in self.DestFileList:
|
|
|
|
NewRuleObject.DestFileList.append(PathClass(NormPath(File, Macros)))
|
|
|
|
return NewRuleObject
|
|
|
|
|
|
|
|
## Apply the rule to given source file(s)
|
|
|
|
#
|
|
|
|
# @param SourceFile One file or a list of files to be built
|
|
|
|
# @param RelativeToDir The relative path of the source file
|
|
|
|
# @param PathSeparator Path separator
|
|
|
|
#
|
|
|
|
# @retval tuple (Source file in full path, List of individual sourcefiles, Destionation file, List of build commands)
|
|
|
|
#
|
2015-05-26 12:32:07 +02:00
|
|
|
def Apply(self, SourceFile, BuildRuleOrder=None):
|
2014-01-27 06:23:15 +01:00
|
|
|
if not self.CommandList or not self.DestFileList:
|
|
|
|
return None
|
|
|
|
|
|
|
|
# source file
|
|
|
|
if self.IsMultipleInput:
|
|
|
|
SrcFileName = ""
|
|
|
|
SrcFileBase = ""
|
|
|
|
SrcFileExt = ""
|
|
|
|
SrcFileDir = ""
|
|
|
|
SrcPath = ""
|
|
|
|
# SourceFile must be a list
|
|
|
|
SrcFile = "$(%s)" % self.FileListMacro
|
|
|
|
else:
|
|
|
|
SrcFileName, SrcFileBase, SrcFileExt = SourceFile.Name, SourceFile.BaseName, SourceFile.Ext
|
|
|
|
if SourceFile.Root:
|
|
|
|
SrcFileDir = SourceFile.SubDir
|
|
|
|
if SrcFileDir == "":
|
|
|
|
SrcFileDir = "."
|
|
|
|
else:
|
|
|
|
SrcFileDir = "."
|
|
|
|
SrcFile = SourceFile.Path
|
|
|
|
SrcPath = SourceFile.Dir
|
|
|
|
|
|
|
|
# destination file (the first one)
|
|
|
|
if self.DestFileList:
|
|
|
|
DestFile = self.DestFileList[0].Path
|
|
|
|
DestPath = self.DestFileList[0].Dir
|
|
|
|
DestFileName = self.DestFileList[0].Name
|
|
|
|
DestFileBase, DestFileExt = self.DestFileList[0].BaseName, self.DestFileList[0].Ext
|
|
|
|
else:
|
|
|
|
DestFile = ""
|
|
|
|
DestPath = ""
|
|
|
|
DestFileName = ""
|
|
|
|
DestFileBase = ""
|
|
|
|
DestFileExt = ""
|
|
|
|
|
|
|
|
BuildRulePlaceholderDict = {
|
|
|
|
# source file
|
|
|
|
"src" : SrcFile,
|
|
|
|
"s_path" : SrcPath,
|
|
|
|
"s_dir" : SrcFileDir,
|
|
|
|
"s_name" : SrcFileName,
|
|
|
|
"s_base" : SrcFileBase,
|
|
|
|
"s_ext" : SrcFileExt,
|
|
|
|
# destination file
|
|
|
|
"dst" : DestFile,
|
|
|
|
"d_path" : DestPath,
|
|
|
|
"d_name" : DestFileName,
|
|
|
|
"d_base" : DestFileBase,
|
|
|
|
"d_ext" : DestFileExt,
|
|
|
|
}
|
|
|
|
|
|
|
|
DstFile = []
|
|
|
|
for File in self.DestFileList:
|
|
|
|
File = string.Template(str(File)).safe_substitute(BuildRulePlaceholderDict)
|
|
|
|
File = string.Template(str(File)).safe_substitute(BuildRulePlaceholderDict)
|
|
|
|
DstFile.append(PathClass(File, IsBinary=True))
|
|
|
|
|
|
|
|
if DstFile[0] in self.BuildTargets:
|
|
|
|
TargetDesc = self.BuildTargets[DstFile[0]]
|
2015-05-26 12:32:07 +02:00
|
|
|
if BuildRuleOrder and SourceFile.Ext in BuildRuleOrder:
|
|
|
|
Index = BuildRuleOrder.index(SourceFile.Ext)
|
|
|
|
for Input in TargetDesc.Inputs:
|
|
|
|
if Input.Ext not in BuildRuleOrder or BuildRuleOrder.index(Input.Ext) > Index:
|
|
|
|
#
|
|
|
|
# Command line should be regenerated since some macros are different
|
|
|
|
#
|
|
|
|
CommandList = self._BuildCommand(BuildRulePlaceholderDict)
|
|
|
|
TargetDesc._Init([SourceFile], DstFile, CommandList, self.ExtraSourceFileList)
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
TargetDesc.AddInput(SourceFile)
|
2014-01-27 06:23:15 +01:00
|
|
|
else:
|
2015-05-26 12:32:07 +02:00
|
|
|
CommandList = self._BuildCommand(BuildRulePlaceholderDict)
|
2014-01-27 06:23:15 +01:00
|
|
|
TargetDesc = TargetDescBlock([SourceFile], DstFile, CommandList, self.ExtraSourceFileList)
|
|
|
|
TargetDesc.ListFileMacro = self.ListFileMacro
|
|
|
|
TargetDesc.FileListMacro = self.FileListMacro
|
|
|
|
TargetDesc.IncListFileMacro = self.IncListFileMacro
|
|
|
|
TargetDesc.GenFileListMacro = self.GenFileListMacro
|
|
|
|
TargetDesc.GenListFile = self.GenListFile
|
|
|
|
TargetDesc.GenIncListFile = self.GenIncListFile
|
|
|
|
self.BuildTargets[DstFile[0]] = TargetDesc
|
|
|
|
return TargetDesc
|
|
|
|
|
2015-05-26 12:32:07 +02:00
|
|
|
def _BuildCommand(self, Macros):
|
|
|
|
CommandList = []
|
|
|
|
for CommandString in self.CommandList:
|
|
|
|
CommandString = string.Template(CommandString).safe_substitute(Macros)
|
|
|
|
CommandString = string.Template(CommandString).safe_substitute(Macros)
|
|
|
|
CommandList.append(CommandString)
|
|
|
|
return CommandList
|
|
|
|
|
2014-01-27 06:23:15 +01:00
|
|
|
## Class for build rules
|
|
|
|
#
|
|
|
|
# BuildRule class parses rules defined in a file or passed by caller, and converts
|
|
|
|
# the rule into FileBuildRule object.
|
|
|
|
#
|
|
|
|
class BuildRule:
|
|
|
|
_SectionHeader = "SECTIONHEADER"
|
|
|
|
_Section = "SECTION"
|
|
|
|
_SubSectionHeader = "SUBSECTIONHEADER"
|
|
|
|
_SubSection = "SUBSECTION"
|
|
|
|
_InputFile = "INPUTFILE"
|
|
|
|
_OutputFile = "OUTPUTFILE"
|
|
|
|
_ExtraDependency = "EXTRADEPENDENCY"
|
|
|
|
_Command = "COMMAND"
|
|
|
|
_UnknownSection = "UNKNOWNSECTION"
|
|
|
|
|
|
|
|
_SubSectionList = [_InputFile, _OutputFile, _Command]
|
|
|
|
|
|
|
|
_PATH_SEP = "(+)"
|
|
|
|
_FileTypePattern = re.compile("^[_a-zA-Z][_\-0-9a-zA-Z]*$")
|
|
|
|
_BinaryFileRule = FileBuildRule(TAB_DEFAULT_BINARY_FILE, [], [os.path.join("$(OUTPUT_DIR)", "${s_name}")],
|
|
|
|
["$(CP) ${src} ${dst}"], [])
|
|
|
|
|
|
|
|
## Constructor
|
|
|
|
#
|
|
|
|
# @param File The file containing build rules in a well defined format
|
|
|
|
# @param Content The string list of build rules in a well defined format
|
|
|
|
# @param LineIndex The line number from which the parsing will begin
|
|
|
|
# @param SupportedFamily The list of supported tool chain families
|
|
|
|
#
|
|
|
|
def __init__(self, File=None, Content=None, LineIndex=0, SupportedFamily=["MSFT", "INTEL", "GCC", "RVCT"]):
|
|
|
|
self.RuleFile = File
|
|
|
|
# Read build rules from file if it's not none
|
|
|
|
if File != None:
|
|
|
|
try:
|
|
|
|
self.RuleContent = open(File, 'r').readlines()
|
|
|
|
except:
|
|
|
|
EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=File)
|
|
|
|
elif Content != None:
|
|
|
|
self.RuleContent = Content
|
|
|
|
else:
|
|
|
|
EdkLogger.error("build", PARAMETER_MISSING, ExtraData="No rule file or string given")
|
|
|
|
|
|
|
|
self.SupportedToolChainFamilyList = SupportedFamily
|
|
|
|
self.RuleDatabase = tdict(True, 4) # {FileExt, ModuleType, Arch, Family : FileBuildRule object}
|
|
|
|
self.Ext2FileType = {} # {ext : file-type}
|
|
|
|
self.FileTypeList = set()
|
|
|
|
|
|
|
|
self._LineIndex = LineIndex
|
|
|
|
self._State = ""
|
|
|
|
self._RuleInfo = tdict(True, 2) # {toolchain family : {"InputFile": {}, "OutputFile" : [], "Command" : []}}
|
|
|
|
self._FileType = ''
|
|
|
|
self._BuildTypeList = []
|
|
|
|
self._ArchList = []
|
|
|
|
self._FamilyList = []
|
|
|
|
self._TotalToolChainFamilySet = set()
|
|
|
|
self._RuleObjectList = [] # FileBuildRule object list
|
|
|
|
self._FileVersion = ""
|
|
|
|
|
|
|
|
self.Parse()
|
|
|
|
|
|
|
|
# some intrinsic rules
|
|
|
|
self.RuleDatabase[TAB_DEFAULT_BINARY_FILE, "COMMON", "COMMON", "COMMON"] = self._BinaryFileRule
|
|
|
|
self.FileTypeList.add(TAB_DEFAULT_BINARY_FILE)
|
|
|
|
|
|
|
|
## Parse the build rule strings
|
|
|
|
def Parse(self):
|
|
|
|
self._State = self._Section
|
|
|
|
for Index in range(self._LineIndex, len(self.RuleContent)):
|
|
|
|
# Clean up the line and replace path separator with native one
|
|
|
|
Line = self.RuleContent[Index].strip().replace(self._PATH_SEP, os.path.sep)
|
|
|
|
self.RuleContent[Index] = Line
|
|
|
|
|
|
|
|
# find the build_rule_version
|
|
|
|
if Line and Line[0] == "#" and Line.find(TAB_BUILD_RULE_VERSION) <> -1:
|
2015-12-01 05:22:16 +01:00
|
|
|
if Line.find("=") <> -1 and Line.find("=") < (len(Line) - 1) and (Line[(Line.find("=") + 1):]).split():
|
2014-01-27 06:23:15 +01:00
|
|
|
self._FileVersion = (Line[(Line.find("=") + 1):]).split()[0]
|
|
|
|
# skip empty or comment line
|
|
|
|
if Line == "" or Line[0] == "#":
|
|
|
|
continue
|
|
|
|
|
|
|
|
# find out section header, enclosed by []
|
|
|
|
if Line[0] == '[' and Line[-1] == ']':
|
|
|
|
# merge last section information into rule database
|
|
|
|
self.EndOfSection()
|
|
|
|
self._State = self._SectionHeader
|
|
|
|
# find out sub-section header, enclosed by <>
|
|
|
|
elif Line[0] == '<' and Line[-1] == '>':
|
|
|
|
if self._State != self._UnknownSection:
|
|
|
|
self._State = self._SubSectionHeader
|
|
|
|
|
|
|
|
# call section handler to parse each (sub)section
|
|
|
|
self._StateHandler[self._State](self, Index)
|
|
|
|
# merge last section information into rule database
|
|
|
|
self.EndOfSection()
|
|
|
|
|
|
|
|
## Parse definitions under a section
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def ParseSection(self, LineIndex):
|
|
|
|
pass
|
|
|
|
|
|
|
|
## Parse definitions under a subsection
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def ParseSubSection(self, LineIndex):
|
|
|
|
# currenly nothing here
|
|
|
|
pass
|
|
|
|
|
|
|
|
## Placeholder for not supported sections
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def SkipSection(self, LineIndex):
|
|
|
|
pass
|
|
|
|
|
|
|
|
## Merge section information just got into rule database
|
|
|
|
def EndOfSection(self):
|
|
|
|
Database = self.RuleDatabase
|
|
|
|
# if there's specific toochain family, 'COMMON' doesn't make sense any more
|
|
|
|
if len(self._TotalToolChainFamilySet) > 1 and 'COMMON' in self._TotalToolChainFamilySet:
|
|
|
|
self._TotalToolChainFamilySet.remove('COMMON')
|
|
|
|
for Family in self._TotalToolChainFamilySet:
|
|
|
|
Input = self._RuleInfo[Family, self._InputFile]
|
|
|
|
Output = self._RuleInfo[Family, self._OutputFile]
|
|
|
|
Command = self._RuleInfo[Family, self._Command]
|
|
|
|
ExtraDependency = self._RuleInfo[Family, self._ExtraDependency]
|
|
|
|
|
|
|
|
BuildRule = FileBuildRule(self._FileType, Input, Output, Command, ExtraDependency)
|
|
|
|
for BuildType in self._BuildTypeList:
|
|
|
|
for Arch in self._ArchList:
|
|
|
|
Database[self._FileType, BuildType, Arch, Family] = BuildRule
|
|
|
|
for FileExt in BuildRule.SourceFileExtList:
|
|
|
|
self.Ext2FileType[FileExt] = self._FileType
|
|
|
|
|
|
|
|
## Parse section header
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def ParseSectionHeader(self, LineIndex):
|
|
|
|
self._RuleInfo = tdict(True, 2)
|
|
|
|
self._BuildTypeList = []
|
|
|
|
self._ArchList = []
|
|
|
|
self._FamilyList = []
|
|
|
|
self._TotalToolChainFamilySet = set()
|
|
|
|
FileType = ''
|
|
|
|
RuleNameList = self.RuleContent[LineIndex][1:-1].split(',')
|
|
|
|
for RuleName in RuleNameList:
|
|
|
|
Arch = 'COMMON'
|
|
|
|
BuildType = 'COMMON'
|
|
|
|
TokenList = [Token.strip().upper() for Token in RuleName.split('.')]
|
|
|
|
# old format: Build.File-Type
|
|
|
|
if TokenList[0] == "BUILD":
|
|
|
|
if len(TokenList) == 1:
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID, "Invalid rule section",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
|
|
|
|
FileType = TokenList[1]
|
|
|
|
if FileType == '':
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID, "No file type given",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
if self._FileTypePattern.match(FileType) == None:
|
2015-12-01 05:22:16 +01:00
|
|
|
EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData="Only character, number (non-first character), '_' and '-' are allowed in file type")
|
|
|
|
# new format: File-Type.Build-Type.Arch
|
|
|
|
else:
|
|
|
|
if FileType == '':
|
|
|
|
FileType = TokenList[0]
|
|
|
|
elif FileType != TokenList[0]:
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID,
|
|
|
|
"Different file types are not allowed in the same rule section",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
if len(TokenList) > 1:
|
|
|
|
BuildType = TokenList[1]
|
|
|
|
if len(TokenList) > 2:
|
|
|
|
Arch = TokenList[2]
|
|
|
|
if BuildType not in self._BuildTypeList:
|
|
|
|
self._BuildTypeList.append(BuildType)
|
|
|
|
if Arch not in self._ArchList:
|
|
|
|
self._ArchList.append(Arch)
|
|
|
|
|
|
|
|
if 'COMMON' in self._BuildTypeList and len(self._BuildTypeList) > 1:
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID,
|
|
|
|
"Specific build types must not be mixed with common one",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
if 'COMMON' in self._ArchList and len(self._ArchList) > 1:
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID,
|
|
|
|
"Specific ARCH must not be mixed with common one",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
|
|
|
|
self._FileType = FileType
|
|
|
|
self._State = self._Section
|
|
|
|
self.FileTypeList.add(FileType)
|
|
|
|
|
|
|
|
## Parse sub-section header
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def ParseSubSectionHeader(self, LineIndex):
|
|
|
|
SectionType = ""
|
|
|
|
List = self.RuleContent[LineIndex][1:-1].split(',')
|
|
|
|
FamilyList = []
|
|
|
|
for Section in List:
|
|
|
|
TokenList = Section.split('.')
|
|
|
|
Type = TokenList[0].strip().upper()
|
|
|
|
|
|
|
|
if SectionType == "":
|
|
|
|
SectionType = Type
|
|
|
|
elif SectionType != Type:
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID,
|
|
|
|
"Two different section types are not allowed in the same sub-section",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
|
|
|
|
if len(TokenList) > 1:
|
|
|
|
Family = TokenList[1].strip().upper()
|
|
|
|
else:
|
|
|
|
Family = "COMMON"
|
|
|
|
|
|
|
|
if Family not in FamilyList:
|
|
|
|
FamilyList.append(Family)
|
|
|
|
|
|
|
|
self._FamilyList = FamilyList
|
|
|
|
self._TotalToolChainFamilySet.update(FamilyList)
|
|
|
|
self._State = SectionType.upper()
|
|
|
|
if 'COMMON' in FamilyList and len(FamilyList) > 1:
|
|
|
|
EdkLogger.error("build", FORMAT_INVALID,
|
|
|
|
"Specific tool chain family should not be mixed with general one",
|
2015-12-01 05:22:16 +01:00
|
|
|
File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData=self.RuleContent[LineIndex])
|
|
|
|
if self._State not in self._StateHandler:
|
2015-12-01 05:22:16 +01:00
|
|
|
EdkLogger.error("build", FORMAT_INVALID, File=self.RuleFile, Line=LineIndex + 1,
|
2014-01-27 06:23:15 +01:00
|
|
|
ExtraData="Unknown subsection: %s" % self.RuleContent[LineIndex])
|
|
|
|
## Parse <InputFile> sub-section
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def ParseInputFile(self, LineIndex):
|
|
|
|
FileList = [File.strip() for File in self.RuleContent[LineIndex].split(",")]
|
|
|
|
for ToolChainFamily in self._FamilyList:
|
|
|
|
InputFiles = self._RuleInfo[ToolChainFamily, self._State]
|
|
|
|
if InputFiles == None:
|
|
|
|
InputFiles = []
|
|
|
|
self._RuleInfo[ToolChainFamily, self._State] = InputFiles
|
|
|
|
InputFiles.extend(FileList)
|
|
|
|
|
|
|
|
## Parse <ExtraDependency> sub-section
|
|
|
|
#
|
|
|
|
# @param LineIndex The line index of build rule text
|
|
|
|
#
|
|
|
|
def ParseCommon(self, LineIndex):
|
|
|
|
for ToolChainFamily in self._FamilyList:
|
|
|
|
Items = self._RuleInfo[ToolChainFamily, self._State]
|
|
|
|
if Items == None:
|
|
|
|
Items = []
|
|
|
|
self._RuleInfo[ToolChainFamily, self._State] = Items
|
|
|
|
Items.append(self.RuleContent[LineIndex])
|
|
|
|
|
|
|
|
## Get a build rule via [] operator
|
|
|
|
#
|
|
|
|
# @param FileExt The extension of a file
|
|
|
|
# @param ToolChainFamily The tool chain family name
|
|
|
|
# @param BuildVersion The build version number. "*" means any rule
|
|
|
|
# is applicalbe.
|
|
|
|
#
|
|
|
|
# @retval FileType The file type string
|
|
|
|
# @retval FileBuildRule The object of FileBuildRule
|
|
|
|
#
|
|
|
|
# Key = (FileExt, ModuleType, Arch, ToolChainFamily)
|
|
|
|
def __getitem__(self, Key):
|
|
|
|
if not Key:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if Key[0] in self.Ext2FileType:
|
|
|
|
Type = self.Ext2FileType[Key[0]]
|
|
|
|
elif Key[0].upper() in self.FileTypeList:
|
|
|
|
Type = Key[0].upper()
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if len(Key) > 1:
|
|
|
|
Key = (Type,) + Key[1:]
|
|
|
|
else:
|
|
|
|
Key = (Type,)
|
|
|
|
return self.RuleDatabase[Key]
|
|
|
|
|
|
|
|
_StateHandler = {
|
|
|
|
_SectionHeader : ParseSectionHeader,
|
|
|
|
_Section : ParseSection,
|
|
|
|
_SubSectionHeader : ParseSubSectionHeader,
|
|
|
|
_SubSection : ParseSubSection,
|
|
|
|
_InputFile : ParseInputFile,
|
|
|
|
_OutputFile : ParseCommon,
|
|
|
|
_ExtraDependency : ParseCommon,
|
|
|
|
_Command : ParseCommon,
|
|
|
|
_UnknownSection : SkipSection,
|
|
|
|
}
|
|
|
|
|
|
|
|
# This acts like the main() function for the script, unless it is 'import'ed into another
|
|
|
|
# script.
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
EdkLogger.Initialize()
|
|
|
|
if len(sys.argv) > 1:
|
|
|
|
Br = BuildRule(sys.argv[1])
|
|
|
|
print str(Br[".c", "DXE_DRIVER", "IA32", "MSFT"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".c", "DXE_DRIVER", "IA32", "INTEL"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".c", "DXE_DRIVER", "IA32", "GCC"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".ac", "ACPI_TABLE", "IA32", "MSFT"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".h", "ACPI_TABLE", "IA32", "INTEL"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".ac", "ACPI_TABLE", "IA32", "MSFT"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".s", "SEC", "IPF", "COMMON"][1])
|
|
|
|
print
|
|
|
|
print str(Br[".s", "SEC"][1])
|
|
|
|
|