]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/IncludesAutoGen.py
2 # Build cache intermediate result and state
4 # Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
5 # Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
8 from Common
.caching
import cached_property
9 import Common
.EdkLogger
as EdkLogger
10 import Common
.LongFilePathOs
as os
11 from Common
.BuildToolError
import *
12 from Common
.Misc
import SaveFileOnChange
, PathClass
13 from Common
.Misc
import TemplateString
17 DEP_FILE_TAIL
= "# Updated \n"
19 class IncludesAutoGen():
20 """ This class is to manage the dependent files witch are used in Makefile to support incremental build.
23 cl.exe has a build option /showIncludes to display include files on stdout. Build tool captures
24 that messages and generate dependency files, .deps files.
26 -MMD -MF build option are used to generate dependency files by compiler. Build tool updates the
29 1. Trim find out all the included files with asl specific include format and generate .trim.deps file.
30 2. ASL PP use c preprocessor to find out all included files with #include format and generate a .deps file
31 3. build tool updates the .deps file
32 3. ASM files (.asm, .s or .nasm):
33 1. Trim find out all the included files with asl specific include format and generate .trim.deps file.
34 2. ASM PP use c preprocessor to find out all included files with #include format and generate a deps file
35 3. build tool updates the .deps file
37 def __init__(self
, makefile_folder
, ModuleAuto
):
38 self
.d_folder
= makefile_folder
39 self
.makefile_folder
= makefile_folder
40 self
.module_autogen
= ModuleAuto
41 self
.ToolChainFamily
= ModuleAuto
.ToolChainFamily
42 self
.workspace
= ModuleAuto
.WorkspaceDir
44 def CreateModuleDeps(self
):
45 SaveFileOnChange(os
.path
.join(self
.makefile_folder
,"deps.txt"),"\n".join(self
.DepsCollection
),False)
47 def CreateDepsInclude(self
):
48 deps_file
= {'deps_file':self
.deps_files
}
50 MakePath
= self
.module_autogen
.BuildOption
.get('MAKE', {}).get('PATH')
52 EdkLogger
.error("build", PARAMETER_MISSING
, Message
="No Make path available.")
53 elif "nmake" in MakePath
:
54 _INCLUDE_DEPS_TEMPLATE
= TemplateString('''
56 !IF EXIST(${deps_file})
62 _INCLUDE_DEPS_TEMPLATE
= TemplateString('''
69 deps_include_str
= _INCLUDE_DEPS_TEMPLATE
.Replace(deps_file
)
70 except Exception as e
:
72 SaveFileOnChange(os
.path
.join(self
.makefile_folder
,"dependency"),deps_include_str
,False)
74 def CreateDepsTarget(self
):
75 SaveFileOnChange(os
.path
.join(self
.makefile_folder
,"deps_target"),"\n".join([item
+":" for item
in self
.DepsCollection
]),False)
79 """ Get all .deps file under module build folder. """
81 for root
, _
, files
in os
.walk(self
.d_folder
, topdown
=False):
83 if not name
.endswith(".deps"):
85 abspath
= os
.path
.join(root
, name
)
86 deps_files
.append(abspath
)
90 def DepsCollection(self
):
91 """ Collect all the dependency files list from all .deps files under a module's build folder """
93 targetname
= [item
[0].Name
for item
in self
.TargetFileList
.values()]
94 for abspath
in self
.deps_files
:
96 with
open(abspath
,"r") as fd
:
97 lines
= fd
.readlines()
99 firstlineitems
= lines
[0].split(": ")
100 dependency_file
= firstlineitems
[1].strip(" \\\n")
101 dependency_file
= dependency_file
.strip('''"''')
103 if os
.path
.normpath(dependency_file
+".deps") == abspath
:
105 filename
= os
.path
.basename(dependency_file
).strip()
106 if filename
not in targetname
:
107 includes
.add(dependency_file
.strip())
109 for item
in lines
[1:]:
110 if item
== DEP_FILE_TAIL
:
112 dependency_file
= item
.strip(" \\\n")
113 dependency_file
= dependency_file
.strip('''"''')
114 if dependency_file
== '':
116 if os
.path
.normpath(dependency_file
+".deps") == abspath
:
118 filename
= os
.path
.basename(dependency_file
).strip()
119 if filename
in targetname
:
121 includes
.add(dependency_file
.strip())
122 except Exception as e
:
123 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)
125 rt
= sorted(list(set([item
.strip(' " \\\n') for item
in includes
])))
129 def SourceFileList(self
):
130 """ Get a map of module's source files name to module's source files path """
131 source
= {os
.path
.basename(item
.File
):item
.Path
for item
in self
.module_autogen
.SourceFileList
}
134 if afile
.upper().endswith(".VFR"):
135 middle_file
.update({afile
.split(".")[0]+".c":os
.path
.join(self
.module_autogen
.DebugDir
,afile
.split(".")[0]+".c")})
136 if afile
.upper().endswith((".S","ASM")):
137 middle_file
.update({afile
.split(".")[0]+".i":os
.path
.join(self
.module_autogen
.OutputDir
,afile
.split(".")[0]+".i")})
138 if afile
.upper().endswith(".ASL"):
139 middle_file
.update({afile
.split(".")[0]+".i":os
.path
.join(self
.module_autogen
.OutputDir
,afile
.split(".")[0]+".i")})
140 source
.update({"AutoGen.c":os
.path
.join(self
.module_autogen
.OutputDir
,"AutoGen.c")})
141 source
.update(middle_file
)
145 def HasNamesakeSourceFile(self
):
146 source_base_name
= set([os
.path
.basename(item
.File
) for item
in self
.module_autogen
.SourceFileList
])
147 rt
= len(source_base_name
) != len(self
.module_autogen
.SourceFileList
)
150 def CcPPCommandPathSet(self
):
152 rt
.add(self
.module_autogen
.BuildOption
.get('CC',{}).get('PATH'))
153 rt
.add(self
.module_autogen
.BuildOption
.get('ASLCC',{}).get('PATH'))
154 rt
.add(self
.module_autogen
.BuildOption
.get('ASLPP',{}).get('PATH'))
155 rt
.add(self
.module_autogen
.BuildOption
.get('VFRPP',{}).get('PATH'))
156 rt
.add(self
.module_autogen
.BuildOption
.get('PP',{}).get('PATH'))
157 rt
.add(self
.module_autogen
.BuildOption
.get('APP',{}).get('PATH'))
161 def TargetFileList(self
):
162 """ Get a map of module's target name to a tuple of module's targets path and whose input file path """
164 targets
["AutoGen.obj"] = (PathClass(os
.path
.join(self
.module_autogen
.OutputDir
,"AutoGen.obj")),PathClass(os
.path
.join(self
.module_autogen
.DebugDir
,"AutoGen.c")))
165 for item
in self
.module_autogen
.Targets
.values():
167 targets
[block
.Target
.Path
] = (block
.Target
,block
.Inputs
[0])
170 def GetRealTarget(self
,source_file_abs
):
171 """ Get the final target file based on source file abspath """
172 source_target_map
= {item
[1].Path
:item
[0].Path
for item
in self
.TargetFileList
.values()}
173 source_name_map
= {item
[1].File
:item
[0].Path
for item
in self
.TargetFileList
.values()}
174 target_abs
= source_target_map
.get(source_file_abs
)
175 if target_abs
is None:
176 if source_file_abs
.strip().endswith(".i"):
177 sourcefilename
= os
.path
.basename(source_file_abs
.strip())
178 for sourcefile
in source_name_map
:
179 if sourcefilename
.split(".")[0] == sourcefile
.split(".")[0]:
180 target_abs
= source_name_map
[sourcefile
]
183 target_abs
= source_file_abs
185 target_abs
= source_file_abs
188 def CreateDepsFileForMsvc(self
, DepList
):
189 """ Generate dependency files, .deps file from /showIncludes output message """
194 SourceFileAbsPathMap
= self
.SourceFileList
197 if self
.HasNamesakeSourceFile
:
198 for cc_cmd
in self
.CcPPCommandPathSet
:
200 if '''"'''+cc_cmd
+'''"''' in line
:
201 cc_options
= line
[len(cc_cmd
)+2:].split()
203 cc_options
= line
[len(cc_cmd
):].split()
204 for item
in cc_options
:
205 if not item
.startswith("/"):
206 if item
.endswith(".txt") and item
.startswith("@"):
207 with
open(item
[1:], "r") as file:
208 source_files
= file.readlines()[0].split()
209 SourceFileAbsPathMap
= {os
.path
.basename(file): file for file in source_files
if
210 os
.path
.exists(file)}
212 if os
.path
.exists(item
):
213 SourceFileAbsPathMap
.update({os
.path
.basename(item
): item
.strip()})
214 # SourceFileAbsPathMap = {os.path.basename(item):item for item in cc_options if not item.startswith("/") and os.path.exists(item)}
215 if line
in SourceFileAbsPathMap
:
216 current_source
= line
217 if current_source
not in ModuleDepDict
:
218 ModuleDepDict
[SourceFileAbsPathMap
[current_source
]] = []
219 elif "Note: including file:" == line
.lstrip()[:21]:
220 if not current_source
:
221 EdkLogger
.error("build",BUILD_ERROR
, "Parse /showIncludes output failed. line: %s. \n" % line
, RaiseError
=False)
223 ModuleDepDict
[SourceFileAbsPathMap
[current_source
]].append(line
.lstrip()[22:].strip())
225 for source_abs
in ModuleDepDict
:
226 if ModuleDepDict
[source_abs
]:
227 target_abs
= self
.GetRealTarget(source_abs
)
228 dep_file_name
= os
.path
.basename(source_abs
) + ".deps"
229 SaveFileOnChange(os
.path
.join(os
.path
.dirname(target_abs
),dep_file_name
)," \\\n".join([target_abs
+":"] + ['''"''' + item
+'''"''' for item
in ModuleDepDict
[source_abs
]]),False)
231 def UpdateDepsFileforNonMsvc(self
):
232 """ Update .deps files.
233 1. Update target path to absolute path.
234 2. Update middle target to final target.
237 for abspath
in self
.deps_files
:
238 if abspath
.endswith(".trim.deps"):
242 with
open(abspath
,"r") as fd
:
243 lines
= fd
.readlines()
244 if lines
[-1] == DEP_FILE_TAIL
:
246 firstlineitems
= lines
[0].strip().split(" ")
248 if len(firstlineitems
) > 2:
249 sourceitem
= firstlineitems
[1]
251 sourceitem
= lines
[1].strip().split(" ")[0]
253 source_abs
= self
.SourceFileList
.get(sourceitem
,sourceitem
)
254 firstlineitems
[0] = self
.GetRealTarget(source_abs
)
255 p_target
= firstlineitems
256 if not p_target
[0].strip().endswith(":"):
259 if len(p_target
) == 2:
260 p_target
[0] += lines
[1]
261 newcontent
.append(p_target
[0])
262 newcontent
.extend(lines
[2:])
264 line1
= " ".join(p_target
).strip()
266 newcontent
.append(line1
)
267 newcontent
.extend(lines
[1:])
269 newcontent
.append("\n")
270 newcontent
.append(DEP_FILE_TAIL
)
271 with
open(abspath
,"w") as fw
:
272 fw
.write("".join(newcontent
))
273 except Exception as e
:
274 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)
277 def UpdateDepsFileforTrim(self
):
278 """ Update .deps file which generated by trim. """
280 for abspath
in self
.deps_files
:
281 if not abspath
.endswith(".trim.deps"):
285 with
open(abspath
,"r") as fd
:
286 lines
= fd
.readlines()
287 if lines
[-1] == DEP_FILE_TAIL
:
290 source_abs
= lines
[0].strip().split(" ")[0]
291 targetitem
= self
.GetRealTarget(source_abs
.strip(" :"))
295 targetitem
+= lines
[1]
296 newcontent
.append(targetitem
)
297 newcontent
.extend(lines
[2:])
298 newcontent
.append("\n")
299 newcontent
.append(DEP_FILE_TAIL
)
300 with
open(abspath
,"w") as fw
:
301 fw
.write("".join(newcontent
))
302 except Exception as e
:
303 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)