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 from __future__
import absolute_import
18 import Common
.LongFilePathOs
as os
20 from . import EdkLogger
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
.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
36 # Static variables used for pattern
38 gMacroRefPattern
= re
.compile('(DEF\([^\(\)]+\))')
39 gEnvRefPattern
= re
.compile('(ENV\([^\(\)]+\))')
40 gMacroDefPattern
= re
.compile("DEFINE\s+([^\s]+)")
41 gDefaultToolsDefFile
= "tools_def.txt"
45 # This class defined content used in file tools_def.txt
47 # @param object: Inherited from object class
48 # @param Filename: Input value for full path of tools_def.txt
50 # @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
51 # @var MacroDictionary: To store keys and values defined in DEFINE statement
53 class ToolDefClassObject(object):
54 def __init__(self
, FileName
=None):
55 self
.ToolsDefTxtDictionary
= {}
56 self
.MacroDictionary
= {}
57 for Env
in os
.environ
:
58 self
.MacroDictionary
["ENV(%s)" % Env
] = os
.environ
[Env
]
60 if FileName
is not None:
61 self
.LoadToolDefFile(FileName
)
65 # Load target.txt file and parse it
67 # @param Filename: Input value for full path of tools_def.txt
69 def LoadToolDefFile(self
, FileName
):
70 # set multiple workspace
71 PackagesPath
= os
.getenv("PACKAGES_PATH")
72 mws
.setWs(GlobalData
.gWorkspace
, PackagesPath
)
74 self
.ToolsDefTxtDatabase
= {
75 TAB_TOD_DEFINES_TARGET
: [],
76 TAB_TOD_DEFINES_TOOL_CHAIN_TAG
: [],
77 TAB_TOD_DEFINES_TARGET_ARCH
: [],
78 TAB_TOD_DEFINES_COMMAND_TYPE
: []
81 self
.IncludeToolDefFile(FileName
)
83 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
]))
84 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
]))
85 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
]))
87 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] = list(set(self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
]))
89 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
].sort()
90 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
].sort()
91 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
].sort()
92 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
].sort()
94 KeyList
= [TAB_TOD_DEFINES_TARGET
, TAB_TOD_DEFINES_TOOL_CHAIN_TAG
, TAB_TOD_DEFINES_TARGET_ARCH
, TAB_TOD_DEFINES_COMMAND_TYPE
]
95 for Index
in range(3, -1, -1):
96 # make a copy of the keys to enumerate over to prevent issues when
97 # adding/removing items from the original dict.
98 for Key
in list(self
.ToolsDefTxtDictionary
.keys()):
100 if List
[Index
] == '*':
101 for String
in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
103 NewKey
= '%s_%s_%s_%s_%s' % tuple(List
)
104 if NewKey
not in self
.ToolsDefTxtDictionary
:
105 self
.ToolsDefTxtDictionary
[NewKey
] = self
.ToolsDefTxtDictionary
[Key
]
106 del self
.ToolsDefTxtDictionary
[Key
]
107 elif List
[Index
] not in self
.ToolsDefTxtDatabase
[KeyList
[Index
]]:
108 del self
.ToolsDefTxtDictionary
[Key
]
111 ## IncludeToolDefFile
113 # Load target.txt file and parse it as if it's contents were inside the main file
115 # @param Filename: Input value for full path of tools_def.txt
117 def IncludeToolDefFile(self
, FileName
):
119 if os
.path
.isfile(FileName
):
121 F
= open(FileName
, 'r')
122 FileContent
= F
.readlines()
124 EdkLogger
.error("tools_def.txt parser", FILE_OPEN_FAILURE
, ExtraData
=FileName
)
126 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=FileName
)
128 for Index
in range(len(FileContent
)):
129 Line
= FileContent
[Index
].strip()
130 if Line
== "" or Line
[0] == '#':
133 if Line
.startswith("!include"):
134 IncFile
= Line
[8:].strip()
135 Done
, IncFile
= self
.ExpandMacros(IncFile
)
137 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
138 "Macro or Environment has not been defined",
139 ExtraData
=IncFile
[4:-1], File
=FileName
, Line
=Index
+1)
140 IncFile
= NormPath(IncFile
)
142 if not os
.path
.isabs(IncFile
):
146 IncFileTmp
= PathClass(IncFile
, GlobalData
.gWorkspace
)
147 ErrorCode
= IncFileTmp
.Validate()[0]
152 IncFileTmp
= mws
.join(GlobalData
.gWorkspace
, IncFile
)
153 if not os
.path
.exists(IncFileTmp
):
155 # try directory of current file
157 IncFileTmp
= PathClass(IncFile
, os
.path
.dirname(FileName
))
158 ErrorCode
= IncFileTmp
.Validate()[0]
160 EdkLogger
.error("tools_def.txt parser", FILE_NOT_FOUND
, ExtraData
=IncFile
)
162 if isinstance(IncFileTmp
, PathClass
):
163 IncFile
= IncFileTmp
.Path
167 self
.IncludeToolDefFile(IncFile
)
170 NameValuePair
= Line
.split("=", 1)
171 if len(NameValuePair
) != 2:
172 EdkLogger
.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index
+ 1))
175 Name
= NameValuePair
[0].strip()
176 Value
= NameValuePair
[1].strip()
178 if Name
== "IDENTIFIER":
179 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found identifier statement, skipped: %s" % ((Index
+ 1), Value
))
182 MacroDefinition
= gMacroDefPattern
.findall(Name
)
183 if MacroDefinition
!= []:
184 Done
, Value
= self
.ExpandMacros(Value
)
186 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
187 "Macro or Environment has not been defined",
188 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
190 MacroName
= MacroDefinition
[0].strip()
191 self
.MacroDictionary
["DEF(%s)" % MacroName
] = Value
192 EdkLogger
.debug(EdkLogger
.DEBUG_8
, "Line %d: Found macro: %s = %s" % ((Index
+ 1), MacroName
, Value
))
195 Done
, Value
= self
.ExpandMacros(Value
)
197 EdkLogger
.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE
,
198 "Macro or Environment has not been defined",
199 ExtraData
=Value
[4:-1], File
=FileName
, Line
=Index
+1)
201 List
= Name
.split('_')
203 EdkLogger
.verbose("Line %d: Not a valid name of definition: %s" % ((Index
+ 1), Name
))
206 EdkLogger
.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index
+ 1), Name
))
209 self
.ToolsDefTxtDictionary
[Name
] = Value
211 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET
] += [List
[0]]
213 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TOOL_CHAIN_TAG
] += [List
[1]]
215 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_TARGET_ARCH
] += [List
[2]]
217 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_COMMAND_TYPE
] += [List
[3]]
218 if List
[4] == TAB_TOD_DEFINES_FAMILY
and List
[2] == '*' and List
[3] == '*':
219 if TAB_TOD_DEFINES_FAMILY
not in self
.ToolsDefTxtDatabase
:
220 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
] = {}
221 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
222 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
] = {}
223 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
224 elif List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
225 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] = Value
226 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
227 elif self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
][List
[1]] != Value
:
228 EdkLogger
.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index
+ 1), Name
))
229 if List
[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY
and List
[2] == '*' and List
[3] == '*':
230 if TAB_TOD_DEFINES_BUILDRULEFAMILY
not in self
.ToolsDefTxtDatabase \
231 or List
[1] not in self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_FAMILY
]:
232 EdkLogger
.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index
+ 1), Name
))
233 self
.ToolsDefTxtDatabase
[TAB_TOD_DEFINES_BUILDRULEFAMILY
][List
[1]] = Value
237 # Replace defined macros with real value
239 # @param Value: The string with unreplaced macros
241 # @retval Value: The string which has been replaced with real value
243 def ExpandMacros(self
, Value
):
244 # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
245 EnvReference
= gEnvRefPattern
.findall(Value
)
246 for Ref
in EnvReference
:
247 if Ref
not in self
.MacroDictionary
and Ref
.upper() not in self
.MacroDictionary
:
248 Value
= Value
.replace(Ref
, "")
250 if Ref
in self
.MacroDictionary
:
251 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
253 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
.upper()])
254 MacroReference
= gMacroRefPattern
.findall(Value
)
255 for Ref
in MacroReference
:
256 if Ref
not in self
.MacroDictionary
:
258 Value
= Value
.replace(Ref
, self
.MacroDictionary
[Ref
])
264 # Load tools_def.txt in input Conf dir
266 # @param ConfDir: Conf dir
268 # @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
270 def ToolDefDict(ConfDir
):
271 Target
= TargetTxtDict(ConfDir
)
272 ToolDef
= ToolDefClassObject()
273 if DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
in Target
.TargetTxtDictionary
:
274 ToolsDefFile
= Target
.TargetTxtDictionary
[DataType
.TAB_TAT_DEFINES_TOOL_CHAIN_CONF
]
276 ToolDef
.LoadToolDefFile(os
.path
.normpath(ToolsDefFile
))
278 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
280 ToolDef
.LoadToolDefFile(os
.path
.normpath(os
.path
.join(ConfDir
, gDefaultToolsDefFile
)))
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"))