2 # This file is used to define each component of tools_def.txt file
4 # Copyright (c) 2007 - 2019, 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 from __future__
import absolute_import
18 import Common
.LongFilePathOs
as os
20 from . import EdkLogger
22 from .BuildToolError
import *
23 from Common
.TargetTxtClassObject
import TargetTxtDict
24 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
25 from Common
.Misc
import PathClass
26 from Common
.StringUtils
import NormPath
27 import Common
.GlobalData
as GlobalData
28 from Common
import GlobalData
29 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
30 from .DataType
import TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
,\
31 TAB_TOD_DEFINES_TARGET_ARCH
, TAB_TOD_DEFINES_COMMAND_TYPE\
32 , TAB_TOD_DEFINES_FAMILY
, TAB_TOD_DEFINES_BUILDRULEFAMILY
,\
33 TAB_STAR
, TAB_TAT_DEFINES_TOOL_CHAIN_CONF
37 # Static variables used for pattern
39 gMacroRefPattern
= re
.compile('(DEF\([^\(\)]+\))')
40 gEnvRefPattern
= re
.compile('(ENV\([^\(\)]+\))')
41 gMacroDefPattern
= re
.compile("DEFINE\s+([^\s]+)")
42 gDefaultToolsDefFile
= "tools_def.txt"
46 # This class defined content used in file tools_def.txt
48 # @param object: Inherited from object class
49 # @param Filename: Input value for full path of tools_def.txt
51 # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
52 # @var MacroDictionary: To store keys and values defined in DEFINE statement
54 class ToolDefClassObject(object):
55 def __init__(self
, FileName
=None):
56 self
.ToolsDefTxtDictionary
= {}
57 self
.MacroDictionary
= {}
58 for Env
in os
.environ
:
59 self
.MacroDictionary
["ENV(%s)" % Env
] = os
.environ
[Env
]
61 if FileName
is not None:
62 self
.LoadToolDefFile(FileName
)
66 # Load target.txt file and parse it
68 # @param Filename: Input value for full path of tools_def.txt
70 def LoadToolDefFile(self
, FileName
):
71 # set multiple workspace
72 PackagesPath
= os
.getenv("PACKAGES_PATH")
73 mws
.setWs(GlobalData
.gWorkspace
, PackagesPath
)
75 self
.ToolsDefTxtDatabase
= {
76 TAB_TOD_DEFINES_TARGET
: [],
77 TAB_TOD_DEFINES_TOOL_CHAIN_TAG
: [],
78 TAB_TOD_DEFINES_TARGET_ARCH
: [],
79 TAB_TOD_DEFINES_COMMAND_TYPE
: []
82 self
.IncludeToolDefFile(FileName
)
84 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
]))
85 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]))
86 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
]))
88 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
]))
90 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
].sort()
91 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
].sort()
92 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
].sort()
93 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
].sort()
95 KeyList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
, TAB_TOD_DEFINES_COMMAND_TYPE
]
96 for Index
in range(3, -1, -1):
97 # make a copy of the keys to enumerate over to prevent issues when
98 # adding/removing items from the original dict.
99 for Key
in list(self
.ToolsDefTxtDictionary
.keys()):
100 List
= Key
.split('_')
101 if List
[Index
] == TAB_STAR
:
102 for String
in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
104 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
105 if NewKey
not in self
.ToolsDefTxtDictionary
:
106 self
.ToolsDefTxtDictionary
[NewKey
] = self
.ToolsDefTxtDictionary
[Key
]
107 del self
.ToolsDefTxtDictionary
[Key
]
108 elif List
[Index
] not in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
109 del self
.ToolsDefTxtDictionary
[Key
]
112 ## IncludeToolDefFile
114 # Load target.txt file and parse it as if it's contents were inside the main file
116 # @param Filename: Input value for full path of tools_def.txt
118 def IncludeToolDefFile(self
, FileName
):
120 if os
.path
.isfile(FileName
):
122 F
= open(FileName
, 'r')
123 FileContent
= F
.readlines()
125 EdkLogger
.error("tools_def.txt parser", FILE_OPEN_FAILURE
, ExtraData
=FileName
)
127 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=FileName
)
129 for Index
in range(len(FileContent
)):
130 Line
= FileContent
[Index
].strip()
131 if Line
== "" or Line
[0] == '#':
134 if Line
.startswith("!include"):
135 IncFile
= Line
[8:].strip()
136 Done
, IncFile
= self
.ExpandMacros(IncFile
)
138 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
139 "Macro or Environment has not been defined",
140 ExtraData
=IncFile
[4:-1], File
=FileName
, Line
=Index
+1)
141 IncFile
= NormPath(IncFile
)
143 if not os
.path
.isabs(IncFile
):
147 IncFileTmp
= PathClass(IncFile
, GlobalData
.gWorkspace
)
148 ErrorCode
= IncFileTmp
.Validate()[0]
153 IncFileTmp
= mws
.join(GlobalData
.gWorkspace
, IncFile
)
154 if not os
.path
.exists(IncFileTmp
):
156 # try directory of current file
158 IncFileTmp
= PathClass(IncFile
, os
.path
.dirname(FileName
))
159 ErrorCode
= IncFileTmp
.Validate()[0]
161 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=IncFile
)
163 if isinstance(IncFileTmp
, PathClass
):
164 IncFile
= IncFileTmp
.Path
168 self
.IncludeToolDefFile(IncFile
)
171 NameValuePair
= Line
.split("=", 1)
172 if len(NameValuePair
) != 2:
173 EdkLogger
.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index
+ 1))
176 Name
= NameValuePair
[0].strip()
177 Value
= NameValuePair
[1].strip()
179 if Name
== "IDENTIFIER":
180 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found identifier statement, skipped: %s" % ((Index
+ 1), Value
))
183 MacroDefinition
= gMacroDefPattern
.findall(Name
)
184 if MacroDefinition
!= []:
185 Done
, Value
= self
.ExpandMacros(Value
)
187 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
188 "Macro or Environment has not been defined",
189 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
191 MacroName
= MacroDefinition
[0].strip()
192 self
.MacroDictionary
["DEF(%s)" % MacroName
] = Value
193 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found macro: %s = %s" % ((Index
+ 1), MacroName
, Value
))
196 Done
, Value
= self
.ExpandMacros(Value
)
198 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
199 "Macro or Environment has not been defined",
200 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
202 List
= Name
.split('_')
204 EdkLogger
.verbose("Line %d: Not a valid name of definition: %s" % ((Index
+ 1), Name
))
206 elif List
[4] == TAB_STAR
:
207 EdkLogger
.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index
+ 1), Name
))
210 self
.ToolsDefTxtDictionary
[Name
] = Value
211 if List
[0] != TAB_STAR
:
212 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] += [List
[0]]
213 if List
[1] != TAB_STAR
:
214 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] += [List
[1]]
215 if List
[2] != TAB_STAR
:
216 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] += [List
[2]]
217 if List
[3] != TAB_STAR
:
218 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] += [List
[3]]
219 if List
[4] == TAB_TOD_DEFINES_FAMILY
and List
[2] == TAB_STAR
and List
[3] == TAB_STAR
:
220 if TAB_TOD_DEFINES_FAMILY
not in self
.ToolsDefTxtDatabase
:
221 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
] = {}
222 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
223 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
] = {}
224 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
225 elif List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
226 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
227 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
228 elif self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] != Value
:
229 EdkLogger
.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index
+ 1), Name
))
230 if List
[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY
and List
[2] == TAB_STAR
and List
[3] == TAB_STAR
:
231 if TAB_TOD_DEFINES_BUILDRULEFAMILY
not in self
.ToolsDefTxtDatabase \
232 or List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
233 EdkLogger
.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index
+ 1), Name
))
234 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
238 # Replace defined macros with real value
240 # @param Value: The string with unreplaced macros
242 # @retval Value: The string which has been replaced with real value
244 def ExpandMacros(self
, Value
):
245 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
246 EnvReference
= gEnvRefPattern
.findall(Value
)
247 for Ref
in EnvReference
:
248 if Ref
not in self
.MacroDictionary
and Ref
.upper() not in self
.MacroDictionary
:
249 Value
= Value
.replace(Ref
, "")
251 if Ref
in self
.MacroDictionary
:
252 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
254 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
.upper()])
255 MacroReference
= gMacroRefPattern
.findall(Value
)
256 for Ref
in MacroReference
:
257 if Ref
not in self
.MacroDictionary
:
259 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
265 # Load tools_def.txt in input Conf dir
267 # @param ConfDir: Conf dir
269 # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
271 def ToolDefDict(ConfDir
):
272 Target
= TargetTxtDict(ConfDir
)
273 ToolDef
= ToolDefClassObject()
274 if TAB_TAT_DEFINES_TOOL_CHAIN_CONF
in Target
.TargetTxtDictionary
:
275 ToolsDefFile
= Target
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
277 ToolDef
.LoadToolDefFile(os
.path
.normpath(ToolsDefFile
))
279 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
281 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
286 # This acts like the main() function for the script, unless it is 'import'ed into another
289 if __name__
== '__main__':
290 ToolDef
= ToolDefDict(os
.getenv("WORKSPACE"))