2 # This file is used to define each component of tools_def.txt file
4 # Copyright (c) 2007 - 2016, 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 Dictionary
import *
22 from BuildToolError
import *
23 from TargetTxtClassObject
import *
24 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
25 from Common
.Misc
import PathClass
26 from Common
.String
import NormPath
27 import Common
.GlobalData
as GlobalData
28 from Common
import GlobalData
29 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
32 # Static variables used for pattern
34 gMacroRefPattern
= re
.compile('(DEF\([^\(\)]+\))')
35 gEnvRefPattern
= re
.compile('(ENV\([^\(\)]+\))')
36 gMacroDefPattern
= re
.compile("DEFINE\s+([^\s]+)")
37 gDefaultToolsDefFile
= "tools_def.txt"
41 # This class defined content used in file tools_def.txt
43 # @param object: Inherited from object class
44 # @param Filename: Input value for full path of tools_def.txt
46 # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
47 # @var MacroDictionary: To store keys and values defined in DEFINE statement
49 class ToolDefClassObject(object):
50 def __init__(self
, FileName
=None):
51 self
.ToolsDefTxtDictionary
= {}
52 self
.MacroDictionary
= {}
53 for Env
in os
.environ
:
54 self
.MacroDictionary
["ENV(%s)" % Env
] = os
.environ
[Env
]
56 if FileName
is not None:
57 self
.LoadToolDefFile(FileName
)
61 # Load target.txt file and parse it
63 # @param Filename: Input value for full path of tools_def.txt
65 def LoadToolDefFile(self
, FileName
):
66 # set multiple workspace
67 PackagesPath
= os
.getenv("PACKAGES_PATH")
68 mws
.setWs(GlobalData
.gWorkspace
, PackagesPath
)
70 self
.ToolsDefTxtDatabase
= {
71 TAB_TOD_DEFINES_TARGET
: [],
72 TAB_TOD_DEFINES_TOOL_CHAIN_TAG
: [],
73 TAB_TOD_DEFINES_TARGET_ARCH
: [],
74 TAB_TOD_DEFINES_COMMAND_TYPE
: []
77 self
.IncludeToolDefFile(FileName
)
79 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
]))
80 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]))
81 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
]))
83 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
]))
85 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
].sort()
86 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
].sort()
87 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
].sort()
88 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
].sort()
90 KeyList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
, TAB_TOD_DEFINES_COMMAND_TYPE
]
91 for Index
in range(3, -1, -1):
92 for Key
in dict(self
.ToolsDefTxtDictionary
):
94 if List
[Index
] == '*':
95 for String
in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
97 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
98 if NewKey
not in self
.ToolsDefTxtDictionary
:
99 self
.ToolsDefTxtDictionary
[NewKey
] = self
.ToolsDefTxtDictionary
[Key
]
101 del self
.ToolsDefTxtDictionary
[Key
]
102 elif List
[Index
] not in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
103 del self
.ToolsDefTxtDictionary
[Key
]
106 ## IncludeToolDefFile
108 # Load target.txt file and parse it as if it's contents were inside the main file
110 # @param Filename: Input value for full path of tools_def.txt
112 def IncludeToolDefFile(self
, FileName
):
114 if os
.path
.isfile(FileName
):
116 F
= open(FileName
, 'r')
117 FileContent
= F
.readlines()
119 EdkLogger
.error("tools_def.txt parser", FILE_OPEN_FAILURE
, ExtraData
=FileName
)
121 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=FileName
)
123 for Index
in range(len(FileContent
)):
124 Line
= FileContent
[Index
].strip()
125 if Line
== "" or Line
[0] == '#':
128 if Line
.startswith("!include"):
129 IncFile
= Line
[8:].strip()
130 Done
, IncFile
= self
.ExpandMacros(IncFile
)
132 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
133 "Macro or Environment has not been defined",
134 ExtraData
=IncFile
[4:-1], File
=FileName
, Line
=Index
+1)
135 IncFile
= NormPath(IncFile
)
137 if not os
.path
.isabs(IncFile
):
141 IncFileTmp
= PathClass(IncFile
, GlobalData
.gWorkspace
)
142 ErrorCode
= IncFileTmp
.Validate()[0]
147 IncFileTmp
= mws
.join(GlobalData
.gWorkspace
, IncFile
)
148 if not os
.path
.exists(IncFileTmp
):
150 # try directory of current file
152 IncFileTmp
= PathClass(IncFile
, os
.path
.dirname(FileName
))
153 ErrorCode
= IncFileTmp
.Validate()[0]
155 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=IncFile
)
157 if type(IncFileTmp
) is PathClass
:
158 IncFile
= IncFileTmp
.Path
162 self
.IncludeToolDefFile(IncFile
)
165 NameValuePair
= Line
.split("=", 1)
166 if len(NameValuePair
) != 2:
167 EdkLogger
.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index
+ 1))
170 Name
= NameValuePair
[0].strip()
171 Value
= NameValuePair
[1].strip()
173 if Name
== "IDENTIFIER":
174 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found identifier statement, skipped: %s" % ((Index
+ 1), Value
))
177 MacroDefinition
= gMacroDefPattern
.findall(Name
)
178 if MacroDefinition
!= []:
179 Done
, Value
= self
.ExpandMacros(Value
)
181 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
182 "Macro or Environment has not been defined",
183 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
185 MacroName
= MacroDefinition
[0].strip()
186 self
.MacroDictionary
["DEF(%s)" % MacroName
] = Value
187 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found macro: %s = %s" % ((Index
+ 1), MacroName
, Value
))
190 Done
, Value
= self
.ExpandMacros(Value
)
192 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
193 "Macro or Environment has not been defined",
194 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
196 List
= Name
.split('_')
198 EdkLogger
.verbose("Line %d: Not a valid name of definition: %s" % ((Index
+ 1), Name
))
201 EdkLogger
.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index
+ 1), Name
))
204 self
.ToolsDefTxtDictionary
[Name
] = Value
206 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] += [List
[0]]
208 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] += [List
[1]]
210 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] += [List
[2]]
212 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] += [List
[3]]
213 if List
[4] == TAB_TOD_DEFINES_FAMILY
and List
[2] == '*' and List
[3] == '*':
214 if TAB_TOD_DEFINES_FAMILY
not in self
.ToolsDefTxtDatabase
:
215 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
] = {}
216 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
217 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
] = {}
218 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
219 elif List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
220 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
221 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
222 elif self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] != Value
:
223 EdkLogger
.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index
+ 1), Name
))
224 if List
[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY
and List
[2] == '*' and List
[3] == '*':
225 if TAB_TOD_DEFINES_BUILDRULEFAMILY
not in self
.ToolsDefTxtDatabase \
226 or List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
227 EdkLogger
.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index
+ 1), Name
))
228 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
232 # Replace defined macros with real value
234 # @param Value: The string with unreplaced macros
236 # @retval Value: The string which has been replaced with real value
238 def ExpandMacros(self
, Value
):
239 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
240 EnvReference
= gEnvRefPattern
.findall(Value
)
241 for Ref
in EnvReference
:
242 if Ref
not in self
.MacroDictionary
and Ref
.upper() not in self
.MacroDictionary
:
243 Value
= Value
.replace(Ref
, "")
245 if Ref
in self
.MacroDictionary
:
246 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
248 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
.upper()])
249 MacroReference
= gMacroRefPattern
.findall(Value
)
250 for Ref
in MacroReference
:
251 if Ref
not in self
.MacroDictionary
:
253 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
259 # Load tools_def.txt in input Conf dir
261 # @param ConfDir: Conf dir
263 # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
265 def ToolDefDict(ConfDir
):
266 Target
= TargetTxtDict(ConfDir
)
267 ToolDef
= ToolDefClassObject()
268 if DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
in Target
.TargetTxtDictionary
:
269 ToolsDefFile
= Target
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
271 ToolDef
.LoadToolDefFile(os
.path
.normpath(ToolsDefFile
))
273 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
275 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
280 # This acts like the main() function for the script, unless it is 'import'ed into another
283 if __name__
== '__main__':
284 ToolDef
= ToolDefDict(os
.getenv("WORKSPACE"))