2 # This file is used to define each component of tools_def.txt file
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 import Common
.LongFilePathOs
as os
21 from BuildToolError
import *
22 from TargetTxtClassObject
import *
23 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
24 from Common
.Misc
import PathClass
25 from Common
.String
import NormPath
26 import Common
.GlobalData
as GlobalData
27 from Common
import GlobalData
28 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
29 from DataType
import TAB_TOD_DEFINES_TARGET
,TAB_TOD_DEFINES_TOOL_CHAIN_TAG
,\
30 TAB_TOD_DEFINES_TARGET_ARCH
,TAB_TOD_DEFINES_COMMAND_TYPE\
31 ,TAB_TOD_DEFINES_FAMILY
,TAB_TOD_DEFINES_BUILDRULEFAMILY
35 # Static variables used for pattern
37 gMacroRefPattern
= re
.compile('(DEF\([^\(\)]+\))')
38 gEnvRefPattern
= re
.compile('(ENV\([^\(\)]+\))')
39 gMacroDefPattern
= re
.compile("DEFINE\s+([^\s]+)")
40 gDefaultToolsDefFile
= "tools_def.txt"
44 # This class defined content used in file tools_def.txt
46 # @param object: Inherited from object class
47 # @param Filename: Input value for full path of tools_def.txt
49 # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
50 # @var MacroDictionary: To store keys and values defined in DEFINE statement
52 class ToolDefClassObject(object):
53 def __init__(self
, FileName
=None):
54 self
.ToolsDefTxtDictionary
= {}
55 self
.MacroDictionary
= {}
56 for Env
in os
.environ
:
57 self
.MacroDictionary
["ENV(%s)" % Env
] = os
.environ
[Env
]
59 if FileName
is not None:
60 self
.LoadToolDefFile(FileName
)
64 # Load target.txt file and parse it
66 # @param Filename: Input value for full path of tools_def.txt
68 def LoadToolDefFile(self
, FileName
):
69 # set multiple workspace
70 PackagesPath
= os
.getenv("PACKAGES_PATH")
71 mws
.setWs(GlobalData
.gWorkspace
, PackagesPath
)
73 self
.ToolsDefTxtDatabase
= {
74 TAB_TOD_DEFINES_TARGET
: [],
75 TAB_TOD_DEFINES_TOOL_CHAIN_TAG
: [],
76 TAB_TOD_DEFINES_TARGET_ARCH
: [],
77 TAB_TOD_DEFINES_COMMAND_TYPE
: []
80 self
.IncludeToolDefFile(FileName
)
82 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
]))
83 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]))
84 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
]))
86 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
]))
88 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
].sort()
89 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
].sort()
90 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
].sort()
91 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
].sort()
93 KeyList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
, TAB_TOD_DEFINES_COMMAND_TYPE
]
94 for Index
in range(3, -1, -1):
95 for Key
in dict(self
.ToolsDefTxtDictionary
):
97 if List
[Index
] == '*':
98 for String
in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
100 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
101 if NewKey
not in self
.ToolsDefTxtDictionary
:
102 self
.ToolsDefTxtDictionary
[NewKey
] = self
.ToolsDefTxtDictionary
[Key
]
104 del self
.ToolsDefTxtDictionary
[Key
]
105 elif List
[Index
] not in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
106 del self
.ToolsDefTxtDictionary
[Key
]
109 ## IncludeToolDefFile
111 # Load target.txt file and parse it as if it's contents were inside the main file
113 # @param Filename: Input value for full path of tools_def.txt
115 def IncludeToolDefFile(self
, FileName
):
117 if os
.path
.isfile(FileName
):
119 F
= open(FileName
, 'r')
120 FileContent
= F
.readlines()
122 EdkLogger
.error("tools_def.txt parser", FILE_OPEN_FAILURE
, ExtraData
=FileName
)
124 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=FileName
)
126 for Index
in range(len(FileContent
)):
127 Line
= FileContent
[Index
].strip()
128 if Line
== "" or Line
[0] == '#':
131 if Line
.startswith("!include"):
132 IncFile
= Line
[8:].strip()
133 Done
, IncFile
= self
.ExpandMacros(IncFile
)
135 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
136 "Macro or Environment has not been defined",
137 ExtraData
=IncFile
[4:-1], File
=FileName
, Line
=Index
+1)
138 IncFile
= NormPath(IncFile
)
140 if not os
.path
.isabs(IncFile
):
144 IncFileTmp
= PathClass(IncFile
, GlobalData
.gWorkspace
)
145 ErrorCode
= IncFileTmp
.Validate()[0]
150 IncFileTmp
= mws
.join(GlobalData
.gWorkspace
, IncFile
)
151 if not os
.path
.exists(IncFileTmp
):
153 # try directory of current file
155 IncFileTmp
= PathClass(IncFile
, os
.path
.dirname(FileName
))
156 ErrorCode
= IncFileTmp
.Validate()[0]
158 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=IncFile
)
160 if type(IncFileTmp
) is PathClass
:
161 IncFile
= IncFileTmp
.Path
165 self
.IncludeToolDefFile(IncFile
)
168 NameValuePair
= Line
.split("=", 1)
169 if len(NameValuePair
) != 2:
170 EdkLogger
.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index
+ 1))
173 Name
= NameValuePair
[0].strip()
174 Value
= NameValuePair
[1].strip()
176 if Name
== "IDENTIFIER":
177 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found identifier statement, skipped: %s" % ((Index
+ 1), Value
))
180 MacroDefinition
= gMacroDefPattern
.findall(Name
)
181 if MacroDefinition
!= []:
182 Done
, Value
= self
.ExpandMacros(Value
)
184 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
185 "Macro or Environment has not been defined",
186 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
188 MacroName
= MacroDefinition
[0].strip()
189 self
.MacroDictionary
["DEF(%s)" % MacroName
] = Value
190 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found macro: %s = %s" % ((Index
+ 1), MacroName
, Value
))
193 Done
, Value
= self
.ExpandMacros(Value
)
195 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
196 "Macro or Environment has not been defined",
197 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
199 List
= Name
.split('_')
201 EdkLogger
.verbose("Line %d: Not a valid name of definition: %s" % ((Index
+ 1), Name
))
204 EdkLogger
.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index
+ 1), Name
))
207 self
.ToolsDefTxtDictionary
[Name
] = Value
209 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] += [List
[0]]
211 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] += [List
[1]]
213 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] += [List
[2]]
215 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] += [List
[3]]
216 if List
[4] == TAB_TOD_DEFINES_FAMILY
and List
[2] == '*' and List
[3] == '*':
217 if TAB_TOD_DEFINES_FAMILY
not in self
.ToolsDefTxtDatabase
:
218 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
] = {}
219 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
220 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
] = {}
221 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
222 elif List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
223 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
224 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
225 elif self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] != Value
:
226 EdkLogger
.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index
+ 1), Name
))
227 if List
[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY
and List
[2] == '*' and List
[3] == '*':
228 if TAB_TOD_DEFINES_BUILDRULEFAMILY
not in self
.ToolsDefTxtDatabase \
229 or List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
230 EdkLogger
.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index
+ 1), Name
))
231 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
235 # Replace defined macros with real value
237 # @param Value: The string with unreplaced macros
239 # @retval Value: The string which has been replaced with real value
241 def ExpandMacros(self
, Value
):
242 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
243 EnvReference
= gEnvRefPattern
.findall(Value
)
244 for Ref
in EnvReference
:
245 if Ref
not in self
.MacroDictionary
and Ref
.upper() not in self
.MacroDictionary
:
246 Value
= Value
.replace(Ref
, "")
248 if Ref
in self
.MacroDictionary
:
249 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
251 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
.upper()])
252 MacroReference
= gMacroRefPattern
.findall(Value
)
253 for Ref
in MacroReference
:
254 if Ref
not in self
.MacroDictionary
:
256 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
262 # Load tools_def.txt in input Conf dir
264 # @param ConfDir: Conf dir
266 # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
268 def ToolDefDict(ConfDir
):
269 Target
= TargetTxtDict(ConfDir
)
270 ToolDef
= ToolDefClassObject()
271 if DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
in Target
.TargetTxtDictionary
:
272 ToolsDefFile
= Target
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
274 ToolDef
.LoadToolDefFile(os
.path
.normpath(ToolsDefFile
))
276 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
278 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
283 # This acts like the main() function for the script, unless it is 'import'ed into another
286 if __name__
== '__main__':
287 ToolDef
= ToolDefDict(os
.getenv("WORKSPACE"))