]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/AutoGen/IncludesAutoGen.py
BaseTools:build failure in CLANGPDB tool chain
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / IncludesAutoGen.py
CommitLineData
0c3e8e99
BF
1## @file\r
2# Build cache intermediate result and state\r
3#\r
5cd3d4bc 4# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>\r
818283de 5# Copyright (c) 2020, ARM Limited. All rights reserved.<BR>\r
0c3e8e99
BF
6# SPDX-License-Identifier: BSD-2-Clause-Patent\r
7#\r
8from Common.caching import cached_property\r
9import Common.EdkLogger as EdkLogger\r
10import Common.LongFilePathOs as os\r
11from Common.BuildToolError import *\r
12from Common.Misc import SaveFileOnChange, PathClass\r
13from Common.Misc import TemplateString\r
14import sys\r
15gIsFileMap = {}\r
0c3e8e99
BF
16\r
17DEP_FILE_TAIL = "# Updated \n"\r
18\r
19class IncludesAutoGen():\r
20 """ This class is to manage the dependent files witch are used in Makefile to support incremental build.\r
21 1. C files:\r
22 1. MSVS.\r
23 cl.exe has a build option /showIncludes to display include files on stdout. Build tool captures\r
24 that messages and generate dependency files, .deps files.\r
25 2. CLANG and GCC\r
26 -MMD -MF build option are used to generate dependency files by compiler. Build tool updates the\r
27 .deps files.\r
28 2. ASL files:\r
29 1. Trim find out all the included files with asl specific include format and generate .trim.deps file.\r
30 2. ASL PP use c preprocessor to find out all included files with #include format and generate a .deps file\r
31 3. build tool updates the .deps file\r
32 3. ASM files (.asm, .s or .nasm):\r
33 1. Trim find out all the included files with asl specific include format and generate .trim.deps file.\r
34 2. ASM PP use c preprocessor to find out all included files with #include format and generate a deps file\r
35 3. build tool updates the .deps file\r
36 """\r
37 def __init__(self, makefile_folder, ModuleAuto):\r
38 self.d_folder = makefile_folder\r
39 self.makefile_folder = makefile_folder\r
40 self.module_autogen = ModuleAuto\r
41 self.ToolChainFamily = ModuleAuto.ToolChainFamily\r
42 self.workspace = ModuleAuto.WorkspaceDir\r
43\r
44 def CreateModuleDeps(self):\r
45 SaveFileOnChange(os.path.join(self.makefile_folder,"deps.txt"),"\n".join(self.DepsCollection),False)\r
46\r
47 def CreateDepsInclude(self):\r
48 deps_file = {'deps_file':self.deps_files}\r
818283de
PG
49\r
50 MakePath = self.module_autogen.BuildOption.get('MAKE', {}).get('PATH')\r
51 if not MakePath:\r
52 EdkLogger.error("build", PARAMETER_MISSING, Message="No Make path available.")\r
53 elif "nmake" in MakePath:\r
54 _INCLUDE_DEPS_TEMPLATE = TemplateString('''\r
55 ${BEGIN}\r
56 !IF EXIST(${deps_file})\r
57 !INCLUDE ${deps_file}\r
58 !ENDIF\r
59 ${END}\r
60 ''')\r
61 else:\r
62 _INCLUDE_DEPS_TEMPLATE = TemplateString('''\r
63 ${BEGIN}\r
64 -include ${deps_file}\r
65 ${END}\r
66 ''')\r
67\r
0c3e8e99
BF
68 try:\r
69 deps_include_str = _INCLUDE_DEPS_TEMPLATE.Replace(deps_file)\r
70 except Exception as e:\r
71 print(e)\r
72 SaveFileOnChange(os.path.join(self.makefile_folder,"dependency"),deps_include_str,False)\r
73\r
5cd3d4bc
BF
74 def CreateDepsTarget(self):\r
75 SaveFileOnChange(os.path.join(self.makefile_folder,"deps_target"),"\n".join([item +":" for item in self.DepsCollection]),False)\r
76\r
0c3e8e99
BF
77 @cached_property\r
78 def deps_files(self):\r
79 """ Get all .deps file under module build folder. """\r
80 deps_files = []\r
81 for root, _, files in os.walk(self.d_folder, topdown=False):\r
82 for name in files:\r
83 if not name.endswith(".deps"):\r
84 continue\r
85 abspath = os.path.join(root, name)\r
86 deps_files.append(abspath)\r
87 return deps_files\r
88\r
89 @cached_property\r
90 def DepsCollection(self):\r
91 """ Collect all the dependency files list from all .deps files under a module's build folder """\r
92 includes = set()\r
93 targetname = [item[0].Name for item in self.TargetFileList.values()]\r
94 for abspath in self.deps_files:\r
95 try:\r
96 with open(abspath,"r") as fd:\r
97 lines = fd.readlines()\r
98\r
99 firstlineitems = lines[0].split(": ")\r
100 dependency_file = firstlineitems[1].strip(" \\\n")\r
101 dependency_file = dependency_file.strip('''"''')\r
102 if dependency_file:\r
103 if os.path.normpath(dependency_file +".deps") == abspath:\r
104 continue\r
105 filename = os.path.basename(dependency_file).strip()\r
106 if filename not in self.SourceFileList and filename not in targetname:\r
107 includes.add(dependency_file.strip())\r
108\r
109 for item in lines[1:]:\r
110 if item == DEP_FILE_TAIL:\r
111 continue\r
112 dependency_file = item.strip(" \\\n")\r
113 dependency_file = dependency_file.strip('''"''')\r
422bf272
FZ
114 if dependency_file == '':\r
115 continue\r
0c3e8e99
BF
116 if os.path.normpath(dependency_file +".deps") == abspath:\r
117 continue\r
118 filename = os.path.basename(dependency_file).strip()\r
119 if filename in self.SourceFileList:\r
120 continue\r
121 if filename in targetname:\r
122 continue\r
123 includes.add(dependency_file.strip())\r
124 except Exception as e:\r
125 EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False)\r
126 continue\r
127 rt = sorted(list(set([item.strip(' " \\\n') for item in includes])))\r
128 return rt\r
129\r
130 @cached_property\r
131 def SourceFileList(self):\r
132 """ Get a map of module's source files name to module's source files path """\r
133 source = {os.path.basename(item.File):item.Path for item in self.module_autogen.SourceFileList}\r
134 middle_file = {}\r
135 for afile in source:\r
136 if afile.upper().endswith(".VFR"):\r
137 middle_file.update({afile.split(".")[0]+".c":os.path.join(self.module_autogen.DebugDir,afile.split(".")[0]+".c")})\r
138 if afile.upper().endswith((".S","ASM")):\r
139 middle_file.update({afile.split(".")[0]+".i":os.path.join(self.module_autogen.OutputDir,afile.split(".")[0]+".i")})\r
140 if afile.upper().endswith(".ASL"):\r
141 middle_file.update({afile.split(".")[0]+".i":os.path.join(self.module_autogen.OutputDir,afile.split(".")[0]+".i")})\r
142 source.update({"AutoGen.c":os.path.join(self.module_autogen.OutputDir,"AutoGen.c")})\r
143 source.update(middle_file)\r
144 return source\r
145\r
146 @cached_property\r
147 def HasNamesakeSourceFile(self):\r
148 source_base_name = set([os.path.basename(item.File) for item in self.module_autogen.SourceFileList])\r
149 rt = len(source_base_name) != len(self.module_autogen.SourceFileList)\r
150 return rt\r
151 @cached_property\r
152 def CcPPCommandPathSet(self):\r
153 rt = set()\r
154 rt.add(self.module_autogen.BuildOption.get('CC',{}).get('PATH'))\r
155 rt.add(self.module_autogen.BuildOption.get('ASLCC',{}).get('PATH'))\r
156 rt.add(self.module_autogen.BuildOption.get('ASLPP',{}).get('PATH'))\r
157 rt.add(self.module_autogen.BuildOption.get('VFRPP',{}).get('PATH'))\r
158 rt.add(self.module_autogen.BuildOption.get('PP',{}).get('PATH'))\r
159 rt.add(self.module_autogen.BuildOption.get('APP',{}).get('PATH'))\r
160 rt.discard(None)\r
161 return rt\r
162 @cached_property\r
163 def TargetFileList(self):\r
164 """ Get a map of module's target name to a tuple of module's targets path and whose input file path """\r
165 targets = {}\r
166 targets["AutoGen.obj"] = (PathClass(os.path.join(self.module_autogen.OutputDir,"AutoGen.obj")),PathClass(os.path.join(self.module_autogen.DebugDir,"AutoGen.c")))\r
167 for item in self.module_autogen.Targets.values():\r
168 for block in item:\r
169 targets[block.Target.Path] = (block.Target,block.Inputs[0])\r
170 return targets\r
171\r
172 def GetRealTarget(self,source_file_abs):\r
173 """ Get the final target file based on source file abspath """\r
174 source_target_map = {item[1].Path:item[0].Path for item in self.TargetFileList.values()}\r
175 source_name_map = {item[1].File:item[0].Path for item in self.TargetFileList.values()}\r
176 target_abs = source_target_map.get(source_file_abs)\r
177 if target_abs is None:\r
178 if source_file_abs.strip().endswith(".i"):\r
179 sourcefilename = os.path.basename(source_file_abs.strip())\r
180 for sourcefile in source_name_map:\r
181 if sourcefilename.split(".")[0] == sourcefile.split(".")[0]:\r
182 target_abs = source_name_map[sourcefile]\r
183 break\r
184 else:\r
185 target_abs = source_file_abs\r
186 else:\r
187 target_abs = source_file_abs\r
188 return target_abs\r
189\r
190 def CreateDepsFileForMsvc(self, DepList):\r
191 """ Generate dependency files, .deps file from /showIncludes output message """\r
192 if not DepList:\r
193 return\r
194 ModuleDepDict = {}\r
195 current_source = ""\r
196 SourceFileAbsPathMap = self.SourceFileList\r
197 for line in DepList:\r
198 line = line.strip()\r
199 if self.HasNamesakeSourceFile:\r
200 for cc_cmd in self.CcPPCommandPathSet:\r
201 if cc_cmd in line:\r
202 if '''"'''+cc_cmd+'''"''' in line:\r
203 cc_options = line[len(cc_cmd)+2:].split()\r
204 else:\r
205 cc_options = line[len(cc_cmd):].split()\r
206 SourceFileAbsPathMap = {os.path.basename(item):item for item in cc_options if not item.startswith("/") and os.path.exists(item)}\r
207 if line in SourceFileAbsPathMap:\r
208 current_source = line\r
209 if current_source not in ModuleDepDict:\r
210 ModuleDepDict[SourceFileAbsPathMap[current_source]] = []\r
211 elif "Note: including file:" == line.lstrip()[:21]:\r
212 if not current_source:\r
213 EdkLogger.error("build",BUILD_ERROR, "Parse /showIncludes output failed. line: %s. \n" % line, RaiseError=False)\r
214 else:\r
215 ModuleDepDict[SourceFileAbsPathMap[current_source]].append(line.lstrip()[22:].strip())\r
216\r
217 for source_abs in ModuleDepDict:\r
218 if ModuleDepDict[source_abs]:\r
219 target_abs = self.GetRealTarget(source_abs)\r
220 dep_file_name = os.path.basename(source_abs) + ".deps"\r
221 SaveFileOnChange(os.path.join(os.path.dirname(target_abs),dep_file_name)," \\\n".join([target_abs+":"] + ['''"''' + item +'''"''' for item in ModuleDepDict[source_abs]]),False)\r
222\r
223 def UpdateDepsFileforNonMsvc(self):\r
224 """ Update .deps files.\r
225 1. Update target path to absolute path.\r
226 2. Update middle target to final target.\r
227 """\r
228\r
229 for abspath in self.deps_files:\r
230 if abspath.endswith(".trim.deps"):\r
231 continue\r
232 try:\r
233 newcontent = []\r
234 with open(abspath,"r") as fd:\r
235 lines = fd.readlines()\r
236 if lines[-1] == DEP_FILE_TAIL:\r
237 continue\r
238 firstlineitems = lines[0].strip().split(" ")\r
239\r
240 if len(firstlineitems) > 2:\r
241 sourceitem = firstlineitems[1]\r
242 else:\r
243 sourceitem = lines[1].strip().split(" ")[0]\r
244\r
245 source_abs = self.SourceFileList.get(sourceitem,sourceitem)\r
246 firstlineitems[0] = self.GetRealTarget(source_abs)\r
247 p_target = firstlineitems\r
248 if not p_target[0].strip().endswith(":"):\r
249 p_target[0] += ": "\r
250\r
251 if len(p_target) == 2:\r
252 p_target[0] += lines[1]\r
253 newcontent.append(p_target[0])\r
254 newcontent.extend(lines[2:])\r
255 else:\r
256 line1 = " ".join(p_target).strip()\r
257 line1 += "\n"\r
258 newcontent.append(line1)\r
259 newcontent.extend(lines[1:])\r
260\r
261 newcontent.append("\n")\r
262 newcontent.append(DEP_FILE_TAIL)\r
263 with open(abspath,"w") as fw:\r
264 fw.write("".join(newcontent))\r
265 except Exception as e:\r
266 EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False)\r
267 continue\r
268\r
269 def UpdateDepsFileforTrim(self):\r
270 """ Update .deps file which generated by trim. """\r
271\r
272 for abspath in self.deps_files:\r
273 if not abspath.endswith(".trim.deps"):\r
274 continue\r
275 try:\r
276 newcontent = []\r
277 with open(abspath,"r") as fd:\r
278 lines = fd.readlines()\r
279 if lines[-1] == DEP_FILE_TAIL:\r
280 continue\r
281\r
282 source_abs = lines[0].strip().split(" ")[0]\r
283 targetitem = self.GetRealTarget(source_abs.strip(" :"))\r
284\r
285 targetitem += ": "\r
286 targetitem += lines[1]\r
287 newcontent.append(targetitem)\r
288 newcontent.extend(lines[2:])\r
289 newcontent.append("\n")\r
290 newcontent.append(DEP_FILE_TAIL)\r
291 with open(abspath,"w") as fw:\r
292 fw.write("".join(newcontent))\r
293 except Exception as e:\r
294 EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False)\r
295 continue\r