]>
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 self
.SourceFileList
and 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 self
.SourceFileList
:
121 if filename
in targetname
:
123 includes
.add(dependency_file
.strip())
124 except Exception as e
:
125 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)
127 rt
= sorted(list(set([item
.strip(' " \\\n') for item
in includes
])))
131 def SourceFileList(self
):
132 """ Get a map of module's source files name to module's source files path """
133 source
= {os
.path
.basename(item
.File
):item
.Path
for item
in self
.module_autogen
.SourceFileList
}
136 if afile
.upper().endswith(".VFR"):
137 middle_file
.update({afile
.split(".")[0]+".c":os
.path
.join(self
.module_autogen
.DebugDir
,afile
.split(".")[0]+".c")})
138 if afile
.upper().endswith((".S","ASM")):
139 middle_file
.update({afile
.split(".")[0]+".i":os
.path
.join(self
.module_autogen
.OutputDir
,afile
.split(".")[0]+".i")})
140 if afile
.upper().endswith(".ASL"):
141 middle_file
.update({afile
.split(".")[0]+".i":os
.path
.join(self
.module_autogen
.OutputDir
,afile
.split(".")[0]+".i")})
142 source
.update({"AutoGen.c":os
.path
.join(self
.module_autogen
.OutputDir
,"AutoGen.c")})
143 source
.update(middle_file
)
147 def HasNamesakeSourceFile(self
):
148 source_base_name
= set([os
.path
.basename(item
.File
) for item
in self
.module_autogen
.SourceFileList
])
149 rt
= len(source_base_name
) != len(self
.module_autogen
.SourceFileList
)
152 def CcPPCommandPathSet(self
):
154 rt
.add(self
.module_autogen
.BuildOption
.get('CC',{}).get('PATH'))
155 rt
.add(self
.module_autogen
.BuildOption
.get('ASLCC',{}).get('PATH'))
156 rt
.add(self
.module_autogen
.BuildOption
.get('ASLPP',{}).get('PATH'))
157 rt
.add(self
.module_autogen
.BuildOption
.get('VFRPP',{}).get('PATH'))
158 rt
.add(self
.module_autogen
.BuildOption
.get('PP',{}).get('PATH'))
159 rt
.add(self
.module_autogen
.BuildOption
.get('APP',{}).get('PATH'))
163 def TargetFileList(self
):
164 """ Get a map of module's target name to a tuple of module's targets path and whose input file path """
166 targets
["AutoGen.obj"] = (PathClass(os
.path
.join(self
.module_autogen
.OutputDir
,"AutoGen.obj")),PathClass(os
.path
.join(self
.module_autogen
.DebugDir
,"AutoGen.c")))
167 for item
in self
.module_autogen
.Targets
.values():
169 targets
[block
.Target
.Path
] = (block
.Target
,block
.Inputs
[0])
172 def GetRealTarget(self
,source_file_abs
):
173 """ Get the final target file based on source file abspath """
174 source_target_map
= {item
[1].Path
:item
[0].Path
for item
in self
.TargetFileList
.values()}
175 source_name_map
= {item
[1].File
:item
[0].Path
for item
in self
.TargetFileList
.values()}
176 target_abs
= source_target_map
.get(source_file_abs
)
177 if target_abs
is None:
178 if source_file_abs
.strip().endswith(".i"):
179 sourcefilename
= os
.path
.basename(source_file_abs
.strip())
180 for sourcefile
in source_name_map
:
181 if sourcefilename
.split(".")[0] == sourcefile
.split(".")[0]:
182 target_abs
= source_name_map
[sourcefile
]
185 target_abs
= source_file_abs
187 target_abs
= source_file_abs
190 def CreateDepsFileForMsvc(self
, DepList
):
191 """ Generate dependency files, .deps file from /showIncludes output message """
196 SourceFileAbsPathMap
= self
.SourceFileList
199 if self
.HasNamesakeSourceFile
:
200 for cc_cmd
in self
.CcPPCommandPathSet
:
202 if '''"'''+cc_cmd
+'''"''' in line
:
203 cc_options
= line
[len(cc_cmd
)+2:].split()
205 cc_options
= line
[len(cc_cmd
):].split()
206 SourceFileAbsPathMap
= {os
.path
.basename(item
):item
for item
in cc_options
if not item
.startswith("/") and os
.path
.exists(item
)}
207 if line
in SourceFileAbsPathMap
:
208 current_source
= line
209 if current_source
not in ModuleDepDict
:
210 ModuleDepDict
[SourceFileAbsPathMap
[current_source
]] = []
211 elif "Note: including file:" == line
.lstrip()[:21]:
212 if not current_source
:
213 EdkLogger
.error("build",BUILD_ERROR
, "Parse /showIncludes output failed. line: %s. \n" % line
, RaiseError
=False)
215 ModuleDepDict
[SourceFileAbsPathMap
[current_source
]].append(line
.lstrip()[22:].strip())
217 for source_abs
in ModuleDepDict
:
218 if ModuleDepDict
[source_abs
]:
219 target_abs
= self
.GetRealTarget(source_abs
)
220 dep_file_name
= os
.path
.basename(source_abs
) + ".deps"
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)
223 def UpdateDepsFileforNonMsvc(self
):
224 """ Update .deps files.
225 1. Update target path to absolute path.
226 2. Update middle target to final target.
229 for abspath
in self
.deps_files
:
230 if abspath
.endswith(".trim.deps"):
234 with
open(abspath
,"r") as fd
:
235 lines
= fd
.readlines()
236 if lines
[-1] == DEP_FILE_TAIL
:
238 firstlineitems
= lines
[0].strip().split(" ")
240 if len(firstlineitems
) > 2:
241 sourceitem
= firstlineitems
[1]
243 sourceitem
= lines
[1].strip().split(" ")[0]
245 source_abs
= self
.SourceFileList
.get(sourceitem
,sourceitem
)
246 firstlineitems
[0] = self
.GetRealTarget(source_abs
)
247 p_target
= firstlineitems
248 if not p_target
[0].strip().endswith(":"):
251 if len(p_target
) == 2:
252 p_target
[0] += lines
[1]
253 newcontent
.append(p_target
[0])
254 newcontent
.extend(lines
[2:])
256 line1
= " ".join(p_target
).strip()
258 newcontent
.append(line1
)
259 newcontent
.extend(lines
[1:])
261 newcontent
.append("\n")
262 newcontent
.append(DEP_FILE_TAIL
)
263 with
open(abspath
,"w") as fw
:
264 fw
.write("".join(newcontent
))
265 except Exception as e
:
266 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)
269 def UpdateDepsFileforTrim(self
):
270 """ Update .deps file which generated by trim. """
272 for abspath
in self
.deps_files
:
273 if not abspath
.endswith(".trim.deps"):
277 with
open(abspath
,"r") as fd
:
278 lines
= fd
.readlines()
279 if lines
[-1] == DEP_FILE_TAIL
:
282 source_abs
= lines
[0].strip().split(" ")[0]
283 targetitem
= self
.GetRealTarget(source_abs
.strip(" :"))
286 targetitem
+= lines
[1]
287 newcontent
.append(targetitem
)
288 newcontent
.extend(lines
[2:])
289 newcontent
.append("\n")
290 newcontent
.append(DEP_FILE_TAIL
)
291 with
open(abspath
,"w") as fw
:
292 fw
.write("".join(newcontent
))
293 except Exception as e
:
294 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)