2 # This file is used to define each component of tools_def.txt file
4 # Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
11 from __future__
import absolute_import
12 import Common
.LongFilePathOs
as os
14 from . import EdkLogger
16 from .BuildToolError
import *
17 from Common
.TargetTxtClassObject
import TargetTxtDict
18 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
19 from Common
.Misc
import PathClass
20 from Common
.StringUtils
import NormPath
21 import Common
.GlobalData
as GlobalData
22 from Common
import GlobalData
23 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
24 from .DataType
import TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
,\
25 TAB_TOD_DEFINES_TARGET_ARCH
, TAB_TOD_DEFINES_COMMAND_TYPE\
26 , TAB_TOD_DEFINES_FAMILY
, TAB_TOD_DEFINES_BUILDRULEFAMILY
,\
27 TAB_STAR
, TAB_TAT_DEFINES_TOOL_CHAIN_CONF
31 # Static variables used for pattern
33 gMacroRefPattern
= re
.compile('(DEF\([^\(\)]+\))')
34 gEnvRefPattern
= re
.compile('(ENV\([^\(\)]+\))')
35 gMacroDefPattern
= re
.compile("DEFINE\s+([^\s]+)")
36 gDefaultToolsDefFile
= "tools_def.txt"
40 # This class defined content used in file tools_def.txt
42 # @param object: Inherited from object class
43 # @param Filename: Input value for full path of tools_def.txt
45 # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
46 # @var MacroDictionary: To store keys and values defined in DEFINE statement
48 class ToolDefClassObject(object):
49 def __init__(self
, FileName
=None):
50 self
.ToolsDefTxtDictionary
= {}
51 self
.MacroDictionary
= {}
52 for Env
in os
.environ
:
53 self
.MacroDictionary
["ENV(%s)" % Env
] = os
.environ
[Env
]
55 if FileName
is not None:
56 self
.LoadToolDefFile(FileName
)
60 # Load target.txt file and parse it
62 # @param Filename: Input value for full path of tools_def.txt
64 def LoadToolDefFile(self
, FileName
):
65 # set multiple workspace
66 PackagesPath
= os
.getenv("PACKAGES_PATH")
67 mws
.setWs(GlobalData
.gWorkspace
, PackagesPath
)
69 self
.ToolsDefTxtDatabase
= {
70 TAB_TOD_DEFINES_TARGET
: [],
71 TAB_TOD_DEFINES_TOOL_CHAIN_TAG
: [],
72 TAB_TOD_DEFINES_TARGET_ARCH
: [],
73 TAB_TOD_DEFINES_COMMAND_TYPE
: []
76 self
.IncludeToolDefFile(FileName
)
78 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
]))
79 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]))
80 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
]))
82 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
]))
84 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
].sort()
85 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
].sort()
86 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
].sort()
87 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
].sort()
91 # Load target.txt file and parse it as if its contents were inside the main file
93 # @param Filename: Input value for full path of tools_def.txt
95 def IncludeToolDefFile(self
, FileName
):
97 if os
.path
.isfile(FileName
):
99 F
= open(FileName
, 'r')
100 FileContent
= F
.readlines()
102 EdkLogger
.error("tools_def.txt parser", FILE_OPEN_FAILURE
, ExtraData
=FileName
)
104 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=FileName
)
106 for Index
in range(len(FileContent
)):
107 Line
= FileContent
[Index
].strip()
108 if Line
== "" or Line
[0] == '#':
111 if Line
.startswith("!include"):
112 IncFile
= Line
[8:].strip()
113 Done
, IncFile
= self
.ExpandMacros(IncFile
)
115 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
116 "Macro or Environment has not been defined",
117 ExtraData
=IncFile
[4:-1], File
=FileName
, Line
=Index
+1)
118 IncFile
= NormPath(IncFile
)
120 if not os
.path
.isabs(IncFile
):
124 IncFileTmp
= PathClass(IncFile
, GlobalData
.gWorkspace
)
125 ErrorCode
= IncFileTmp
.Validate()[0]
130 IncFileTmp
= mws
.join(GlobalData
.gWorkspace
, IncFile
)
131 if not os
.path
.exists(IncFileTmp
):
133 # try directory of current file
135 IncFileTmp
= PathClass(IncFile
, os
.path
.dirname(FileName
))
136 ErrorCode
= IncFileTmp
.Validate()[0]
138 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=IncFile
)
140 if isinstance(IncFileTmp
, PathClass
):
141 IncFile
= IncFileTmp
.Path
145 self
.IncludeToolDefFile(IncFile
)
148 NameValuePair
= Line
.split("=", 1)
149 if len(NameValuePair
) != 2:
150 EdkLogger
.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index
+ 1))
153 Name
= NameValuePair
[0].strip()
154 Value
= NameValuePair
[1].strip()
156 if Name
== "IDENTIFIER":
157 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found identifier statement, skipped: %s" % ((Index
+ 1), Value
))
160 MacroDefinition
= gMacroDefPattern
.findall(Name
)
161 if MacroDefinition
!= []:
162 Done
, Value
= self
.ExpandMacros(Value
)
164 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
165 "Macro or Environment has not been defined",
166 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
168 MacroName
= MacroDefinition
[0].strip()
169 self
.MacroDictionary
["DEF(%s)" % MacroName
] = Value
170 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found macro: %s = %s" % ((Index
+ 1), MacroName
, Value
))
173 Done
, Value
= self
.ExpandMacros(Value
)
175 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
176 "Macro or Environment has not been defined",
177 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
179 List
= Name
.split('_')
181 EdkLogger
.verbose("Line %d: Not a valid name of definition: %s" % ((Index
+ 1), Name
))
183 elif List
[4] == TAB_STAR
:
184 EdkLogger
.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index
+ 1), Name
))
187 self
.ToolsDefTxtDictionary
[Name
] = Value
188 if List
[0] != TAB_STAR
:
189 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] += [List
[0]]
190 if List
[1] != TAB_STAR
:
191 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] += [List
[1]]
192 if List
[2] != TAB_STAR
:
193 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] += [List
[2]]
194 if List
[3] != TAB_STAR
:
195 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] += [List
[3]]
196 if List
[4] == TAB_TOD_DEFINES_FAMILY
and List
[2] == TAB_STAR
and List
[3] == TAB_STAR
:
197 if TAB_TOD_DEFINES_FAMILY
not in self
.ToolsDefTxtDatabase
:
198 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
] = {}
199 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
200 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
] = {}
201 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
202 elif List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
203 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
204 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
205 elif self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] != Value
:
206 EdkLogger
.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index
+ 1), Name
))
207 if List
[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY
and List
[2] == TAB_STAR
and List
[3] == TAB_STAR
:
208 if TAB_TOD_DEFINES_BUILDRULEFAMILY
not in self
.ToolsDefTxtDatabase \
209 or List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
210 EdkLogger
.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index
+ 1), Name
))
211 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
215 # Replace defined macros with real value
217 # @param Value: The string with unreplaced macros
219 # @retval Value: The string which has been replaced with real value
221 def ExpandMacros(self
, Value
):
222 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
223 EnvReference
= gEnvRefPattern
.findall(Value
)
224 for Ref
in EnvReference
:
225 if Ref
not in self
.MacroDictionary
and Ref
.upper() not in self
.MacroDictionary
:
226 Value
= Value
.replace(Ref
, "")
228 if Ref
in self
.MacroDictionary
:
229 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
231 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
.upper()])
232 MacroReference
= gMacroRefPattern
.findall(Value
)
233 for Ref
in MacroReference
:
234 if Ref
not in self
.MacroDictionary
:
236 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
242 # Load tools_def.txt in input Conf dir
244 # @param ConfDir: Conf dir
246 # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
252 def __new__(cls
, ConfDir
, *args
, **kw
):
253 if not hasattr(cls
, '_instance'):
254 orig
= super(ToolDefDict
, cls
)
255 cls
._instance
= orig
.__new
__(cls
, *args
, **kw
)
258 def __init__(self
, ConfDir
):
259 self
.ConfDir
= ConfDir
260 if not hasattr(self
, 'ToolDef'):
265 if not self
._ToolDef
:
269 def _GetToolDef(self
):
270 TargetObj
= TargetTxtDict()
271 Target
= TargetObj
.Target
272 ToolDef
= ToolDefClassObject()
273 if TAB_TAT_DEFINES_TOOL_CHAIN_CONF
in Target
.TargetTxtDictionary
:
274 ToolsDefFile
= Target
.TargetTxtDictionary
[TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
276 ToolDef
.LoadToolDefFile(os
.path
.normpath(ToolsDefFile
))
278 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(self
.ConfDir
, gDefaultToolsDefFile
)))
280 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(self
.ConfDir
, gDefaultToolsDefFile
)))
281 self
._ToolDef
= ToolDef
285 # This acts like the main() function for the script, unless it is 'import'ed into another
288 if __name__
== '__main__':
289 ToolDef
= ToolDefDict(os
.getenv("WORKSPACE"))