]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/IncludesAutoGen.py
bb6e883d84ca6decc97514f95a35bd6db8714eed
2 # Build cache intermediate result and state
4 # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
7 from Common
.caching
import cached_property
8 import Common
.EdkLogger
as EdkLogger
9 import Common
.LongFilePathOs
as os
10 from Common
.BuildToolError
import *
11 from Common
.Misc
import SaveFileOnChange
, PathClass
12 from Common
.Misc
import TemplateString
15 if sys
.platform
== "win32":
16 _INCLUDE_DEPS_TEMPLATE
= TemplateString('''
18 !IF EXIST(${deps_file})
24 _INCLUDE_DEPS_TEMPLATE
= TemplateString('''
30 DEP_FILE_TAIL
= "# Updated \n"
32 class IncludesAutoGen():
33 """ This class is to manage the dependent files witch are used in Makefile to support incremental build.
36 cl.exe has a build option /showIncludes to display include files on stdout. Build tool captures
37 that messages and generate dependency files, .deps files.
39 -MMD -MF build option are used to generate dependency files by compiler. Build tool updates the
42 1. Trim find out all the included files with asl specific include format and generate .trim.deps file.
43 2. ASL PP use c preprocessor to find out all included files with #include format and generate a .deps file
44 3. build tool updates the .deps file
45 3. ASM files (.asm, .s or .nasm):
46 1. Trim find out all the included files with asl specific include format and generate .trim.deps file.
47 2. ASM PP use c preprocessor to find out all included files with #include format and generate a deps file
48 3. build tool updates the .deps file
50 def __init__(self
, makefile_folder
, ModuleAuto
):
51 self
.d_folder
= makefile_folder
52 self
.makefile_folder
= makefile_folder
53 self
.module_autogen
= ModuleAuto
54 self
.ToolChainFamily
= ModuleAuto
.ToolChainFamily
55 self
.workspace
= ModuleAuto
.WorkspaceDir
57 def CreateModuleDeps(self
):
58 SaveFileOnChange(os
.path
.join(self
.makefile_folder
,"deps.txt"),"\n".join(self
.DepsCollection
),False)
60 def CreateDepsInclude(self
):
61 deps_file
= {'deps_file':self
.deps_files
}
63 deps_include_str
= _INCLUDE_DEPS_TEMPLATE
.Replace(deps_file
)
64 except Exception as e
:
66 SaveFileOnChange(os
.path
.join(self
.makefile_folder
,"dependency"),deps_include_str
,False)
70 """ Get all .deps file under module build folder. """
72 for root
, _
, files
in os
.walk(self
.d_folder
, topdown
=False):
74 if not name
.endswith(".deps"):
76 abspath
= os
.path
.join(root
, name
)
77 deps_files
.append(abspath
)
81 def DepsCollection(self
):
82 """ Collect all the dependency files list from all .deps files under a module's build folder """
84 targetname
= [item
[0].Name
for item
in self
.TargetFileList
.values()]
85 for abspath
in self
.deps_files
:
87 with
open(abspath
,"r") as fd
:
88 lines
= fd
.readlines()
90 firstlineitems
= lines
[0].split(": ")
91 dependency_file
= firstlineitems
[1].strip(" \\\n")
92 dependency_file
= dependency_file
.strip('''"''')
94 if os
.path
.normpath(dependency_file
+".deps") == abspath
:
96 filename
= os
.path
.basename(dependency_file
).strip()
97 if filename
not in self
.SourceFileList
and filename
not in targetname
:
98 includes
.add(dependency_file
.strip())
100 for item
in lines
[1:]:
101 if item
== DEP_FILE_TAIL
:
103 dependency_file
= item
.strip(" \\\n")
104 dependency_file
= dependency_file
.strip('''"''')
105 if os
.path
.normpath(dependency_file
+".deps") == abspath
:
107 filename
= os
.path
.basename(dependency_file
).strip()
108 if filename
in self
.SourceFileList
:
110 if filename
in targetname
:
112 includes
.add(dependency_file
.strip())
113 except Exception as e
:
114 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)
116 rt
= sorted(list(set([item
.strip(' " \\\n') for item
in includes
])))
120 def SourceFileList(self
):
121 """ Get a map of module's source files name to module's source files path """
122 source
= {os
.path
.basename(item
.File
):item
.Path
for item
in self
.module_autogen
.SourceFileList
}
125 if afile
.upper().endswith(".VFR"):
126 middle_file
.update({afile
.split(".")[0]+".c":os
.path
.join(self
.module_autogen
.DebugDir
,afile
.split(".")[0]+".c")})
127 if afile
.upper().endswith((".S","ASM")):
128 middle_file
.update({afile
.split(".")[0]+".i":os
.path
.join(self
.module_autogen
.OutputDir
,afile
.split(".")[0]+".i")})
129 if afile
.upper().endswith(".ASL"):
130 middle_file
.update({afile
.split(".")[0]+".i":os
.path
.join(self
.module_autogen
.OutputDir
,afile
.split(".")[0]+".i")})
131 source
.update({"AutoGen.c":os
.path
.join(self
.module_autogen
.OutputDir
,"AutoGen.c")})
132 source
.update(middle_file
)
136 def HasNamesakeSourceFile(self
):
137 source_base_name
= set([os
.path
.basename(item
.File
) for item
in self
.module_autogen
.SourceFileList
])
138 rt
= len(source_base_name
) != len(self
.module_autogen
.SourceFileList
)
141 def CcPPCommandPathSet(self
):
143 rt
.add(self
.module_autogen
.BuildOption
.get('CC',{}).get('PATH'))
144 rt
.add(self
.module_autogen
.BuildOption
.get('ASLCC',{}).get('PATH'))
145 rt
.add(self
.module_autogen
.BuildOption
.get('ASLPP',{}).get('PATH'))
146 rt
.add(self
.module_autogen
.BuildOption
.get('VFRPP',{}).get('PATH'))
147 rt
.add(self
.module_autogen
.BuildOption
.get('PP',{}).get('PATH'))
148 rt
.add(self
.module_autogen
.BuildOption
.get('APP',{}).get('PATH'))
152 def TargetFileList(self
):
153 """ Get a map of module's target name to a tuple of module's targets path and whose input file path """
155 targets
["AutoGen.obj"] = (PathClass(os
.path
.join(self
.module_autogen
.OutputDir
,"AutoGen.obj")),PathClass(os
.path
.join(self
.module_autogen
.DebugDir
,"AutoGen.c")))
156 for item
in self
.module_autogen
.Targets
.values():
158 targets
[block
.Target
.Path
] = (block
.Target
,block
.Inputs
[0])
161 def GetRealTarget(self
,source_file_abs
):
162 """ Get the final target file based on source file abspath """
163 source_target_map
= {item
[1].Path
:item
[0].Path
for item
in self
.TargetFileList
.values()}
164 source_name_map
= {item
[1].File
:item
[0].Path
for item
in self
.TargetFileList
.values()}
165 target_abs
= source_target_map
.get(source_file_abs
)
166 if target_abs
is None:
167 if source_file_abs
.strip().endswith(".i"):
168 sourcefilename
= os
.path
.basename(source_file_abs
.strip())
169 for sourcefile
in source_name_map
:
170 if sourcefilename
.split(".")[0] == sourcefile
.split(".")[0]:
171 target_abs
= source_name_map
[sourcefile
]
174 target_abs
= source_file_abs
176 target_abs
= source_file_abs
179 def CreateDepsFileForMsvc(self
, DepList
):
180 """ Generate dependency files, .deps file from /showIncludes output message """
185 SourceFileAbsPathMap
= self
.SourceFileList
188 if self
.HasNamesakeSourceFile
:
189 for cc_cmd
in self
.CcPPCommandPathSet
:
191 if '''"'''+cc_cmd
+'''"''' in line
:
192 cc_options
= line
[len(cc_cmd
)+2:].split()
194 cc_options
= line
[len(cc_cmd
):].split()
195 SourceFileAbsPathMap
= {os
.path
.basename(item
):item
for item
in cc_options
if not item
.startswith("/") and os
.path
.exists(item
)}
196 if line
in SourceFileAbsPathMap
:
197 current_source
= line
198 if current_source
not in ModuleDepDict
:
199 ModuleDepDict
[SourceFileAbsPathMap
[current_source
]] = []
200 elif "Note: including file:" == line
.lstrip()[:21]:
201 if not current_source
:
202 EdkLogger
.error("build",BUILD_ERROR
, "Parse /showIncludes output failed. line: %s. \n" % line
, RaiseError
=False)
204 ModuleDepDict
[SourceFileAbsPathMap
[current_source
]].append(line
.lstrip()[22:].strip())
206 for source_abs
in ModuleDepDict
:
207 if ModuleDepDict
[source_abs
]:
208 target_abs
= self
.GetRealTarget(source_abs
)
209 dep_file_name
= os
.path
.basename(source_abs
) + ".deps"
210 SaveFileOnChange(os
.path
.join(os
.path
.dirname(target_abs
),dep_file_name
)," \\\n".join([target_abs
+":"] + ['''"''' + item
+'''"''' for item
in ModuleDepDict
[source_abs
]]),False)
212 def UpdateDepsFileforNonMsvc(self
):
213 """ Update .deps files.
214 1. Update target path to absolute path.
215 2. Update middle target to final target.
218 for abspath
in self
.deps_files
:
219 if abspath
.endswith(".trim.deps"):
223 with
open(abspath
,"r") as fd
:
224 lines
= fd
.readlines()
225 if lines
[-1] == DEP_FILE_TAIL
:
227 firstlineitems
= lines
[0].strip().split(" ")
229 if len(firstlineitems
) > 2:
230 sourceitem
= firstlineitems
[1]
232 sourceitem
= lines
[1].strip().split(" ")[0]
234 source_abs
= self
.SourceFileList
.get(sourceitem
,sourceitem
)
235 firstlineitems
[0] = self
.GetRealTarget(source_abs
)
236 p_target
= firstlineitems
237 if not p_target
[0].strip().endswith(":"):
240 if len(p_target
) == 2:
241 p_target
[0] += lines
[1]
242 newcontent
.append(p_target
[0])
243 newcontent
.extend(lines
[2:])
245 line1
= " ".join(p_target
).strip()
247 newcontent
.append(line1
)
248 newcontent
.extend(lines
[1:])
250 newcontent
.append("\n")
251 newcontent
.append(DEP_FILE_TAIL
)
252 with
open(abspath
,"w") as fw
:
253 fw
.write("".join(newcontent
))
254 except Exception as e
:
255 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)
258 def UpdateDepsFileforTrim(self
):
259 """ Update .deps file which generated by trim. """
261 for abspath
in self
.deps_files
:
262 if not abspath
.endswith(".trim.deps"):
266 with
open(abspath
,"r") as fd
:
267 lines
= fd
.readlines()
268 if lines
[-1] == DEP_FILE_TAIL
:
271 source_abs
= lines
[0].strip().split(" ")[0]
272 targetitem
= self
.GetRealTarget(source_abs
.strip(" :"))
275 targetitem
+= lines
[1]
276 newcontent
.append(targetitem
)
277 newcontent
.extend(lines
[2:])
278 newcontent
.append("\n")
279 newcontent
.append(DEP_FILE_TAIL
)
280 with
open(abspath
,"w") as fw
:
281 fw
.write("".join(newcontent
))
282 except Exception as e
:
283 EdkLogger
.error("build",FILE_NOT_FOUND
, "%s doesn't exist" % abspath
, ExtraData
=str(e
), RaiseError
=False)