1## @file
2# This file is used to define each component of Target.txt file
3#
4# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6#
7
8##
9# Import Modules
10#
11from __future__ import print_function
12from __future__ import absolute_import
13from Common.buildoptions import BuildOption,BuildTarget
14import Common.GlobalData as GlobalData
15import Common.LongFilePathOs as os
16from . import EdkLogger
17from . import DataType
18from .BuildToolError import *
19
20from Common.LongFilePathSupport import OpenLongFilePath as open
21from Common.MultipleWorkspace import MultipleWorkspace as mws
22
23gDefaultTargetTxtFile = "target.txt"
24
25## TargetTxtClassObject
26#
27# This class defined content used in file target.txt
28#
29# @param object:             Inherited from object class
30# @param Filename:           Input value for full path of target.txt
31#
32# @var TargetTxtDictionary:  To store keys and values defined in target.txt
33#
34class TargetTxtClassObject(object):
35    def __init__(self, Filename = None):
36        self.TargetTxtDictionary = {
37            DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM                            : '',
38            DataType.TAB_TAT_DEFINES_ACTIVE_MODULE                              : '',
39            DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF                            : '',
40            DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER               : '',
41            DataType.TAB_TAT_DEFINES_TARGET                                     : [],
42            DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG                             : [],
43            DataType.TAB_TAT_DEFINES_TARGET_ARCH                                : [],
44            DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF                            : '',
45        }
46        self.ConfDirectoryPath = ""
47        if Filename is not None:
48            self.LoadTargetTxtFile(Filename)
49
50    ## LoadTargetTxtFile
51    #
52    # Load target.txt file and parse it, return a set structure to store keys and values
53    #
54    # @param Filename:  Input value for full path of target.txt
55    #
56    # @retval set() A set structure to store keys and values
57    # @retval 1     Error happenes in parsing
58    #
59    def LoadTargetTxtFile(self, Filename):
60        if os.path.exists(Filename) and os.path.isfile(Filename):
61             return self.ConvertTextFileToDict(Filename, '#', '=')
62        else:
63            EdkLogger.error("Target.txt Parser", FILE_NOT_FOUND, ExtraData=Filename)
64            return 1
65
66    ## ConvertTextFileToDict
67    #
68    # Convert a text file to a dictionary of (name:value) pairs.
69    # The data is saved to self.TargetTxtDictionary
70    #
71    # @param FileName:             Text filename
72    # @param CommentCharacter:     Comment char, be used to ignore comment content
73    # @param KeySplitCharacter:    Key split char, between key name and key value. Key1 = Value1, '=' is the key split char
74    #
75    # @retval 0 Convert successfully
76    # @retval 1 Open file failed
77    #
78    def ConvertTextFileToDict(self, FileName, CommentCharacter, KeySplitCharacter):
79        F = None
80        try:
81            F = open(FileName, 'r')
82            self.ConfDirectoryPath = os.path.dirname(FileName)
83        except:
84            EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=FileName)
85            if F is not None:
86                F.close()
87
88        for Line in F:
89            Line = Line.strip()
90            if Line.startswith(CommentCharacter) or Line == '':
91                continue
92
93            LineList = Line.split(KeySplitCharacter, 1)
94            Key = LineList[0].strip()
95            if len(LineList) == 2:
96                Value = LineList[1].strip()
97            else:
98                Value = ""
99
100            if Key in [DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM, DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF, \
101                       DataType.TAB_TAT_DEFINES_ACTIVE_MODULE, DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF]:
102                self.TargetTxtDictionary[Key] = Value.replace('\\', '/')
103                if Key == DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF and self.TargetTxtDictionary[Key]:
104                    if self.TargetTxtDictionary[Key].startswith("Conf/"):
105                        Tools_Def = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
106                        if not os.path.exists(Tools_Def) or not os.path.isfile(Tools_Def):
107                            # If Conf/Conf does not exist, try just the Conf/ directory
108                            Tools_Def = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].replace("Conf/", "", 1).strip())
109                    else:
110                        # The File pointed to by TOOL_CHAIN_CONF is not in a Conf/ directory
111                        Tools_Def = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
112                    self.TargetTxtDictionary[Key] = Tools_Def
113                if Key == DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF and self.TargetTxtDictionary[Key]:
114                    if self.TargetTxtDictionary[Key].startswith("Conf/"):
115                        Build_Rule = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
116                        if not os.path.exists(Build_Rule) or not os.path.isfile(Build_Rule):
117                            # If Conf/Conf does not exist, try just the Conf/ directory
118                            Build_Rule = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].replace("Conf/", "", 1).strip())
119                    else:
120                        # The File pointed to by BUILD_RULE_CONF is not in a Conf/ directory
121                        Build_Rule = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
122                    self.TargetTxtDictionary[Key] = Build_Rule
123            elif Key in [DataType.TAB_TAT_DEFINES_TARGET, DataType.TAB_TAT_DEFINES_TARGET_ARCH, \
124                         DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]:
125                self.TargetTxtDictionary[Key] = Value.split()
126            elif Key == DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER:
127                try:
128                    V = int(Value, 0)
129                except:
130                    EdkLogger.error("build", FORMAT_INVALID, "Invalid number of [%s]: %s." % (Key, Value),
131                                    File=FileName)
132                self.TargetTxtDictionary[Key] = Value
133            #elif Key not in GlobalData.gGlobalDefines:
134            #    GlobalData.gGlobalDefines[Key] = Value
135
136        F.close()
137        return 0
138
139## TargetTxtDict
140#
141# Load target.txt in input Conf dir
142#
143# @param ConfDir:  Conf dir
144#
145# @retval Target An instance of TargetTxtClassObject() with loaded target.txt
146#
147def TargetTxtDict():
148    Target = TargetTxtClassObject()
149    if BuildOption.ConfDirectory:
150        # Get alternate Conf location, if it is absolute, then just use the absolute directory name
151        ConfDirectoryPath = os.path.normpath(BuildOption.ConfDirectory)
152
153        if not os.path.isabs(ConfDirectoryPath):
154            # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE
155            # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf
156            ConfDirectoryPath = mws.join(os.environ["WORKSPACE"], ConfDirectoryPath)
157    else:
158        if "CONF_PATH" in os.environ:
159            ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))
160        else:
161            # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
162            ConfDirectoryPath = mws.join(os.environ["WORKSPACE"], 'Conf')
163    GlobalData.gConfDirectory = ConfDirectoryPath
164    targettxt = os.path.normpath(os.path.join(ConfDirectoryPath, gDefaultTargetTxtFile))
165    if os.path.exists(targettxt):
166        Target.LoadTargetTxtFile(targettxt)
167    return Target
168
169TargetTxt = TargetTxtDict()
170
171##
172#
173# This acts like the main() function for the script, unless it is 'import'ed into another
174# script.
175#
176if __name__ == '__main__':
177    pass
178    Target = TargetTxtDict(os.getenv("WORKSPACE"))
179    print(Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER])
180    print(Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET])
181    print(Target.TargetTxtDictionary)
182