mirror of https://github.com/acidanthera/audk.git
BaseTools: Generate compile information in build report
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2850 Add "-Y REPORT_INFO" option to build command to generate compile information as part of BuildReport. This option generates files to be used by external tools as IDE's to enhance functionality. Files are created inside build folder: <Build>/<BuildTarget>/<ToolChain>/CompileInfo Files created: * compile_commands.json - Compilation Database. To be used by IDE's to enable advance features * cscope.files - List of files used in compilation. Used by Cscope to parse C code and provide browse functionality. * module_report.json - Module data form buildReport in Json format. Signed-off-by: Guillermo Antonio Palomino Sosa <guillermo.a.palomino.sosa@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
This commit is contained in:
parent
9b94ebb0c8
commit
4ad7ea9c84
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
## Import Modules
|
## Import Modules
|
||||||
#
|
#
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
import Common.LongFilePathOs as os
|
import Common.LongFilePathOs as os
|
||||||
import re
|
import re
|
||||||
import platform
|
import platform
|
||||||
|
@ -41,6 +43,7 @@ from Common.DataType import *
|
||||||
import collections
|
import collections
|
||||||
from Common.Expression import *
|
from Common.Expression import *
|
||||||
from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
|
from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
|
||||||
|
from AutoGen.IncludesAutoGen import IncludesAutoGen
|
||||||
|
|
||||||
## Pattern to extract contents in EDK DXS files
|
## Pattern to extract contents in EDK DXS files
|
||||||
gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
|
gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)
|
||||||
|
@ -2298,6 +2301,10 @@ class BuildReport(object):
|
||||||
def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
|
def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):
|
||||||
if self.ReportFile:
|
if self.ReportFile:
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
if "COMPILE_INFO" in self.ReportType:
|
||||||
|
self.GenerateCompileInfo()
|
||||||
|
|
||||||
File = []
|
File = []
|
||||||
for (Wa, MaList) in self.ReportList:
|
for (Wa, MaList) in self.ReportList:
|
||||||
PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
|
PlatformReport(Wa, MaList, self.ReportType).GenerateReport(File, BuildDuration, AutoGenTime, MakeTime, GenFdsTime, self.ReportType)
|
||||||
|
@ -2310,7 +2317,137 @@ class BuildReport(object):
|
||||||
EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
|
EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report", ExtraData=self.ReportFile, RaiseError=False)
|
||||||
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
|
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# Generates compile data files to be used by external tools.
|
||||||
|
# Compile information will be generated in <Build>/<BuildTarget>/<ToolChain>/CompileInfo
|
||||||
|
# Files generated: compile_commands.json, cscope.files, modules_report.json
|
||||||
|
#
|
||||||
|
# @param self The object pointer
|
||||||
|
#
|
||||||
|
def GenerateCompileInfo(self):
|
||||||
|
try:
|
||||||
|
# Lists for the output elements
|
||||||
|
compile_commands = []
|
||||||
|
used_files = set()
|
||||||
|
module_report = []
|
||||||
|
|
||||||
|
for (Wa, MaList) in self.ReportList:
|
||||||
|
# Obtain list of all processed Workspace files
|
||||||
|
for file_path in Wa._GetMetaFiles(Wa.BuildTarget, Wa.ToolChain):
|
||||||
|
used_files.add(file_path)
|
||||||
|
|
||||||
|
for autoGen in Wa.AutoGenObjectList:
|
||||||
|
|
||||||
|
# Loop through all modules
|
||||||
|
for module in (autoGen.LibraryAutoGenList + autoGen.ModuleAutoGenList):
|
||||||
|
|
||||||
|
used_files.add(module.MetaFile.Path)
|
||||||
|
|
||||||
|
# Main elements of module report
|
||||||
|
module_report_data = {}
|
||||||
|
module_report_data["Name"] = module.Name
|
||||||
|
module_report_data["Arch"] = module.Arch
|
||||||
|
module_report_data["Path"] = module.MetaFile.Path
|
||||||
|
module_report_data["Guid"] = module.Guid
|
||||||
|
module_report_data["BuildType"] = module.BuildType
|
||||||
|
module_report_data["IsLibrary"] = module.IsLibrary
|
||||||
|
module_report_data["SourceDir"] = module.SourceDir
|
||||||
|
module_report_data["Files"] = []
|
||||||
|
|
||||||
|
# Files used by module
|
||||||
|
for data_file in module.SourceFileList:
|
||||||
|
module_report_data["Files"].append({"Name": data_file.Name, "Path": data_file.Path})
|
||||||
|
|
||||||
|
# Libraries used by module
|
||||||
|
module_report_data["Libraries"] = []
|
||||||
|
for data_library in module.LibraryAutoGenList:
|
||||||
|
module_report_data["Libraries"].append({"Path": data_library.MetaFile.Path})
|
||||||
|
|
||||||
|
# Packages used by module
|
||||||
|
module_report_data["Packages"] = []
|
||||||
|
for data_package in module.PackageList:
|
||||||
|
module_report_data["Packages"].append({"Path": data_package.MetaFile.Path, "Includes": []})
|
||||||
|
# Includes path used in package
|
||||||
|
for data_package_include in data_package.Includes:
|
||||||
|
module_report_data["Packages"][-1]["Includes"].append(data_package_include.Path)
|
||||||
|
|
||||||
|
# PPI's in module
|
||||||
|
module_report_data["PPI"] = []
|
||||||
|
for data_ppi in module.PpiList.keys():
|
||||||
|
module_report_data["PPI"].append({"Name": data_ppi, "Guid": module.PpiList[data_ppi]})
|
||||||
|
|
||||||
|
# Protocol's in module
|
||||||
|
module_report_data["Protocol"] = []
|
||||||
|
for data_protocol in module.ProtocolList.keys():
|
||||||
|
module_report_data["Protocol"].append({"Name": data_protocol, "Guid": module.ProtocolList[data_protocol]})
|
||||||
|
|
||||||
|
# PCD's in module
|
||||||
|
module_report_data["Pcd"] = []
|
||||||
|
for data_pcd in module.LibraryPcdList:
|
||||||
|
module_report_data["Pcd"].append({"Space": data_pcd.TokenSpaceGuidCName,
|
||||||
|
"Name": data_pcd.TokenCName,
|
||||||
|
"Value": data_pcd.TokenValue,
|
||||||
|
"Guid": data_pcd.TokenSpaceGuidValue,
|
||||||
|
"DatumType": data_pcd.DatumType,
|
||||||
|
"Type": data_pcd.Type,
|
||||||
|
"DefaultValue": data_pcd.DefaultValue})
|
||||||
|
# Add module to report
|
||||||
|
module_report.append(module_report_data)
|
||||||
|
|
||||||
|
# Include file dependencies to used files
|
||||||
|
includes_autogen = IncludesAutoGen(module.MakeFileDir, module)
|
||||||
|
for dep in includes_autogen.DepsCollection:
|
||||||
|
used_files.add(dep)
|
||||||
|
|
||||||
|
inc_flag = "-I" # Default include flag
|
||||||
|
if module.BuildRuleFamily == TAB_COMPILER_MSFT:
|
||||||
|
inc_flag = "/I"
|
||||||
|
|
||||||
|
for source in module.SourceFileList:
|
||||||
|
used_files.add(source.Path)
|
||||||
|
compile_command = {}
|
||||||
|
if source.Ext in [".c", ".cc", ".cpp"]:
|
||||||
|
#
|
||||||
|
# Generate compile command for each c file
|
||||||
|
#
|
||||||
|
compile_command["file"] = source.Path
|
||||||
|
compile_command["directory"] = source.Dir
|
||||||
|
build_command = module.BuildRules[source.Ext].CommandList[0]
|
||||||
|
build_command_variables = re.findall(r"\$\((.*?)\)", build_command)
|
||||||
|
for var in build_command_variables:
|
||||||
|
var_tokens = var.split("_")
|
||||||
|
var_main = var_tokens[0]
|
||||||
|
if len(var_tokens) == 1:
|
||||||
|
var_value = module.BuildOption[var_main]["PATH"]
|
||||||
|
else:
|
||||||
|
var_value = module.BuildOption[var_main][var_tokens[1]]
|
||||||
|
build_command = build_command.replace(f"$({var})", var_value)
|
||||||
|
include_files = f" {inc_flag}".join(module.IncludePathList)
|
||||||
|
build_command = build_command.replace("${src}", include_files)
|
||||||
|
build_command = build_command.replace("${dst}", module.OutputDir)
|
||||||
|
|
||||||
|
# Remove un defined macros
|
||||||
|
compile_command["command"] = re.sub(r"\$\(.*?\)", "", build_command)
|
||||||
|
compile_commands.append(compile_command)
|
||||||
|
|
||||||
|
# Create output folder if doesn't exist
|
||||||
|
compile_info_folder = Path(Wa.BuildDir).joinpath("CompileInfo")
|
||||||
|
compile_info_folder.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# Sort and save files
|
||||||
|
compile_commands.sort(key=lambda x: x["file"])
|
||||||
|
SaveFileOnChange(compile_info_folder.joinpath(f"compile_commands.json"),json.dumps(compile_commands, indent=2), False)
|
||||||
|
|
||||||
|
SaveFileOnChange(compile_info_folder.joinpath(f"cscope.files"), "\n".join(sorted(used_files)), False)
|
||||||
|
|
||||||
|
module_report.sort(key=lambda x: x["Path"])
|
||||||
|
SaveFileOnChange(compile_info_folder.joinpath(f"module_report.json"), json.dumps(module_report, indent=2), False)
|
||||||
|
|
||||||
|
except:
|
||||||
|
EdkLogger.error("BuildReport", CODE_ERROR, "Unknown fatal error when generating build report compile information", ExtraData=self.ReportFile, RaiseError=False)
|
||||||
|
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
|
||||||
|
|
||||||
# This acts like the main() function for the script, unless it is 'import'ed into another script.
|
# This acts like the main() function for the script, unless it is 'import'ed into another script.
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,8 @@ class MyOptionParser():
|
||||||
Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
|
Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
|
||||||
|
|
||||||
Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
|
Parser.add_option("-y", "--report-file", action="store", dest="ReportFile", help="Create/overwrite the report to the specified filename.")
|
||||||
Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER'], dest="ReportType", default=[],
|
Parser.add_option("-Y", "--report-type", action="append", type="choice", choices=['PCD', 'LIBRARY', 'FLASH', 'DEPEX', 'BUILD_FLAGS', 'FIXED_ADDRESS', 'HASH', 'EXECUTION_ORDER', 'COMPILE_INFO'], dest="ReportType", default=[],
|
||||||
help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER]. "\
|
help="Flags that control the type of build report to generate. Must be one of: [PCD, LIBRARY, FLASH, DEPEX, BUILD_FLAGS, FIXED_ADDRESS, HASH, EXECUTION_ORDER, COMPILE_INFO]. "\
|
||||||
"To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")
|
"To specify more than one flag, repeat this option on the command line and the default flag set is [PCD, LIBRARY, FLASH, DEPEX, HASH, BUILD_FLAGS, FIXED_ADDRESS]")
|
||||||
Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
|
Parser.add_option("-F", "--flag", action="store", type="string", dest="Flag",
|
||||||
help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\
|
help="Specify the specific option to parse EDK UNI file. Must be one of: [-c, -s]. -c is for EDK framework UNI file, and -s is for EDK UEFI UNI file. "\
|
||||||
|
|
Loading…
Reference in New Issue