【EDK2】在UDK2018中实现兼容Vscode中的Edk2Code插件
原理
新版 EDK2 的确把“生成编译信息(compile_commands.json 等)”做在 BaseTools/Source/Python/build/BuildReport.py 里的 BuildReport 类里,并通过 -Y COMPILE_INFO -y BuildReport.log 开关触发。
官方 issue / 文档和扩展插件都在用这个开关(不是 REPORT_INFO)来生成 Build/…/CompileInfo/compile_commands.json 等文件。
其中-Y COMPILE_INFO -y BuildReport.log编译选项是近期才加上的,不能兼容老版本的UDK2018,很多现有的项目是基于老版EDK2,因此,需要改动做一些兼容。
代码修改
改动一:BuildReport.py
文件:
BaseTools/Source/Python/build/BuildReport.py
1)在文件顶部 import 区补充(如已有相同 import 可略过):
import json
from Common.Misc import SaveFileOnChange
from Common.DataType import TAB_COMPILER_MSFT
2)在 class BuildReport(): 内添加方法:
def GenerateCompileInfo(self):
"""
生成供 IDE/clangd/vscode 使用的编译数据库,以及辅助文件。
输出目录:<Build>/<BuildTarget>/<ToolChain>/CompileInfo/
输出文件:compile_commands.json, cscope.files, module_report.json
"""
try:
compile_commands = []
used_files = set()
module_report = []
# self.ReportList 由现有 BuildReport 逻辑维护(与原有报表一致)
for (Wa, MaList) in self.ReportList:
# 工作区已处理文件(尽可能多地记录)
try:
for fp in Wa._GetMetaFiles(Wa.BuildTarget, Wa.ToolChain):
used_files.add(fp)
except Exception:
pass
for autogen in Wa.AutoGenObjectList:
# 遍历模块与库(与新版 EDK2 的思路一致)
for module in (autogen.LibraryAutoGenList + autogen.ModuleAutoGenList):
used_files.add(module.MetaFile.Path)
# —— 可选:模块摘要(用于 module_report.json)——
md = {
"Name": module.Name,
"Arch": module.Arch,
"Path": module.MetaFile.Path,
"Guid": getattr(module, "Guid", ""),
"BuildType": getattr(module, "BuildType", ""),
"IsLibrary": getattr(module, "IsLibrary", False),
"SourceDir": getattr(module, "SourceDir", ""),
"Files": [],
"Libraries": [],
"Packages": [],
"PPI": [],
"Protocol": [],
"Pcd": []
}
for sf in module.SourceFileList:
md["Files"].append({"Name": sf.Name, "Path": sf.Path})
for libag in getattr(module, "LibraryAutoGenList", []):
md["Libraries"].append({"Path": libag.MetaFile.Path})
for pkg in getattr(module, "PackageList", []):
entry = {"Path": pkg.MetaFile.Path, "Includes": []}
for inc in getattr(pkg, "Includes", []):
entry["Includes"].append(inc.Path)
md["Packages"].append(entry)
for k in getattr(module, "PpiList", {}).keys():
md["PPI"].append({"Name": k, "Guid": module.PpiList[k]})
for k in getattr(module, "ProtocolList", {}).keys():
md["Protocol"].append({"Name": k, "Guid": module.ProtocolList[k]})
for pcd in getattr(module, "LibraryPcdList", []):
md["Pcd"].append({
"Space": getattr(pcd, "TokenSpaceGuidCName", ""),
"Name": getattr(pcd, "TokenCName", ""),
"Value": getattr(pcd, "TokenValue", ""),
"Guid": getattr(pcd, "TokenSpaceGuidValue", ""),
"DatumType": getattr(pcd, "DatumType", ""),
"Type": getattr(pcd, "Type", ""),
"DefaultValue": getattr(pcd, "DefaultValue", "")
})
module_report.append(md)
# 生成 compile_commands 项(仅 C/C++ 源)
inc_flag = "/I" if module.BuildRuleFamily == TAB_COMPILER_MSFT else "-I"
for src in module.SourceFileList:
used_files.add(src.Path)
if src.Ext not in [".c", ".cc", ".cpp", ".cxx"]:
continue
# 基于 BuildRules 获取单条编译命令模板
try:
rule_cmd = module.BuildRules[src.Ext].CommandList[0]
except Exception:
# 回退:无法解析就跳过该文件
continue
# 展开 $(VAR) 变量(与新版实现思路一致,尽量保守)
def _expand_var(m):
token = m.group(1)
parts = token.split("_")
try:
if len(parts) == 1:
return module.BuildOption[parts[0]]["PATH"]
else:
return module.BuildOption[parts[0]][parts[1]]
except Exception:
return ""
build_cmd = re.sub(r"\$\((.*?)\)", _expand_var, rule_cmd)
# 处理常见占位:${src}(包含路径列表),${dst}(输出目录)
try:
incs = getattr(module, "IncludePathList", [])
# 构造 “/Ipath1 /Ipath2 …”
inc_blob = " ".join([(inc_flag + "\"" + inc + "\"") if " " in inc else (inc_flag + inc) for inc in incs])
build_cmd = build_cmd.replace("${src}", inc_blob)
build_cmd = build_cmd.replace("${dst}", getattr(module, "OutputDir", ""))
except Exception:
pass
# 清理未展开残留形如 $(XXX) 的片段
build_cmd = re.sub(r"\$\((?:.*?)\)", "", build_cmd).strip()
# compilation database 条目
entry = {
"file": src.Path, # 保持与 EDK2 新版一致:绝对路径
"directory": src.Dir, # 编译时工作目录
"command": build_cmd # MSVC 风格 cl.exe 命令
}
compile_commands.append(entry)
# 输出目录:Build/.../CompileInfo
compile_info_dir = os.path.join(Wa.BuildDir, "CompileInfo")
if not os.path.isdir(compile_info_dir):
try:
os.makedirs(compile_info_dir)
except Exception:
pass
# 排序并写出
compile_commands.sort(key=lambda x: x["file"])
SaveFileOnChange(os.path.join(compile_info_dir, "compile_commands.json"),
json.dumps(compile_commands, indent=2), False)
SaveFileOnChange(os.path.join(compile_info_dir, "cscope.files"),
"\n".join(sorted(used_files)), False)
module_report.sort(key=lambda x: x["Path"])
SaveFileOnChange(os.path.join(compile_info_dir, "module_report.json"),
json.dumps(module_report, indent=2), False)
except Exception:
from Common import EdkLogger
import traceback, platform, sys
EdkLogger.error("BuildReport", 0, "Unknown fatal error when generating compile information",
ExtraData=getattr(self, "ReportFile", None), RaiseError=False)
EdkLogger.quiet("(Python %s on %s\n%s)" % (platform.python_version(), sys.platform, traceback.format_exc()))
3)在生成报表的入口处挂钩调用(GenerateReport 里追加判断):
找到 def GenerateReport(self, BuildDuration, AutoGenTime, MakeTime, GenFdsTime):在它写日志/报表的 try 块开头,加上:

4)在下图所示加入一行:

改动二:build.py(给 -Y 添加 COMPILE_INFO 选项)
文件:
BaseTools/Source/Python/build/build.py
找到命令行解析对 -Y/--report-type 的定义,把允许值里加入 COMPILE_INFO。
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, COMPILE_INFO]. "\
改动三:Common/Datatype.py
文件:
BaseTools/Source/Python/Common/Datatype.py
在最后一行加上
TAB_COMPILER_MSFT = 'MSFT'
使用与验证
使用python编译
edksetup.bat执行后,build -h查看-Y选项下是否有COMPILE_INFO如果有,说明build使用的是python脚本。- 正常编译,但增加(注意要使用Python2.7编译UDK2018):
build -p <YourDsc> -a IA32 -t VS2015x86 -b DEBUG -Y COMPILE_INFO -y BuildReport.log^a359b1 - 在你的 build 产物目录(例如
Build/NT32IA32/DEBUG_VS2015x86/CompileInfo/)应出现:
compile_commands.jsoncscope.filesmodule_report.json
VS Code(MS 的 C/C++ 插件)设置 C/C++: Compile Commands 指向上面的 compile_commands.json。我推荐使用clangd,因为生成的这个json文件很大,C/C++插件总是索引很慢,知道怎么解决的大佬请留言,感谢!
安装了Edk2Code插件后,ctrl + shift + p 输入EDK2: rebuild index database,选择你编译后的./EDK2/Build目录,让 Edk2Code正确索引database。官方与社区都推荐用这个流程。
如果发现build -h的-Y没有COMPILE_INFO,则证明使用的是build.exe编译,可以将EDK2/BaseTools/Bin/Win32/build.exe重命名为1build.exe,这样EDK2会自动使用python编译。
使用build.exe编译
如果没有环境,无法使用python编译,则麻烦一些,需要将build.py 编译为build.exe。
- python注意版本是2.7.14,另外还需要安装
cx_Freeze-4.2.3.win-amd64-py2.7.msi,这个版本的cx_Freeze不好找,如果需要可以联系我。 - 备份一个
EDK2/Basetools整个目录 - 在
EDK2/Basetools/目录下,进入cmd,运行nmake /f Makefile clean,再运行nmake /f Makefile - 将编译好的
build.exe以及Genfds.exe替换原来的,这样就可以使用build.exe - 按照从这开始的操作步骤,一步步也可以生成
Build/.../CompileInfo整个文件夹。
点个赞再走!!!!!
【EDK2】在UDK2018中实现兼容Vscode中的Edk2Code插件的更多相关文章
- 排坑·IPhone&IOS中不兼容正则中的断言匹配
阅文时长 | 1.14分钟 字数统计 | 1834.4字符 主要内容 | 1.问题切入 2.什么是断言匹配 3.断言匹配的替换方案 4.声明与参考资料 『排坑·IPhone&IOS中不兼容正则 ...
- vscode开发中绝对让你惊艳的插件!!!(个人在用)
识别模版引擎 1.Apache Velocity :识别Velocity(vm) 2.Art Template Helper:识别artTemplate 点击路径跳转 1.Laravel goto v ...
- 在vscode中使用Git
用了git最方便的就是比如在公司写了很多代码后回到家打开vscode只需要点击一下pull就能全部同步过来.是不是很方便....毕竟之前我都是拿u盘拷贝回家或者存到云盘再下载下来.. 我这里用的是国内 ...
- c#兼容 PHP中的md5
原文:c#兼容 PHP中的md5 由于工作需要,需要使用C#去对一个php程序做二次开发.在登录验证的时候,发现一个小问题. 就是用C#写的md5算法得出的结果和php的md5()得出的结果有时候会不 ...
- 数据类型 text 和 varchar 在 add 运算符中不兼容
原文:数据类型 text 和 varchar 在 add 运算符中不兼容 在SQL Server2005中,使用类似下面的Update语句: 1 UPDATE tb_SmsBlacklist SET ...
- vscode中使用markdown
vscode中使用markdown vscode 是微软推出一款轻量级的文本编辑工具,类似于sublime,由于其拥有丰富的插件,安装使用也非常简单,所以深受广大程序员的喜爱. markdown 是一 ...
- 在VSCode中编辑HTML文档时,在Dom标签上写style属性时智能提示的问题
首先在VSCode中打开一个HTML文件 然后点右下角的“选择语言模式” 然后点击配置HTML语言的基础设置 然后在打开的界面中(右侧) 输入如下代码 { "editor.quickSugg ...
- 解决忽略VScode中Python插件pylint报错的问题
pylint是VScode中python自带的插件,可以帮助代码规范,美观. 但是有些报错是你不想看到的,你可以选择性的忽略. 例如,在re.compile()中,可以添加参数re.S使. 匹配任意字 ...
- v-for 在 VSCode 中出现 Elements in iteration expect to have 'v-bind:key' directives.
在 VSCode 中编辑代码时,在有 v-for 的语句下面有一条红色波浪线,鼠标放上去有提示 Elements in iteration expect to have 'v-bind:key' di ...
- VScode中python环境配置
vscode中python环境配置 想要在vscode中运行python代码必须要告诉vscode使用哪个解释器才行 方法1. 打开命令面板(Ctrl+Shift+P)输入Python: Select ...
随机推荐
- java返回数据库中层级结构数据的treeListMap写法,以动态菜单为例
说明 1.treeListMap写法,与纯算法版本比起来,treeListMap版的缺点是会查询多次数据库,而纯算法只会查询一次数据库 2.里面有不同角色分配不同的菜单相关代码,注意复制粘贴. 3.可 ...
- 【2020.11.14提高组模拟】无尽之前 (game) 题解
[2020.11.14提高组模拟]无尽之前 (game) 题解 有趣的题面 题目背景 雏见泽,一个和平的,或者说本应和平的小村庄,却因连续四年的怪死事件而蒙上了阴 影. 无一例外,每年的事件都发生在棉 ...
- HarmonyOS运动开发:精准估算室内运动的距离、速度与步幅
前言 在室内运动场景中,由于缺乏 GPS 信号,传统的基于卫星定位的运动数据追踪方法无法使用.因此,如何准确估算室内运动的距离.速度和步幅,成为了运动应用开发中的一个重要挑战.本文将结合鸿蒙(Harm ...
- helmfile调试
说明 我们在调试helmfile编排的chart时,对于helm chart正常的情况下,我们编排的helmfile渲染模版的值出了问题,可能会存在以下的报错: helmfile template E ...
- 浅析百万级分布式调度引擎——DAGScheduleX能做什么?
公交车伴随着我们的日常生活已是随处可见,不同路线的公交车根据各自的时间表有序发出,到达站点,接上站台的乘客再缓缓驶向下一站--早高峰会有短区间的加班车,发车间隔也更短,夜半时分的班次则间隔更长.这一切 ...
- 关于ant design pro的权限方案设计
访问控制(Access control)是指对访问者向受保护资源进行访问操作的控制管理.该控制管理保证被授权者可访问受保护资源,未被授权者不能访问受保护资源. 现实生活中的访问控制可以由付费或者认 ...
- Django实战:自定义中间件实现全链路操作日志记录
一.中间件 介绍 在 Django 中,中间件(Middleware)是一组轻量级.底层的插件系统,用于全局地改变 Django 的输入和输出.中间件可以在请求被处理之前和响应返回之前执行代码,从而实 ...
- 一个static关键字引发的线上故障:深度剖析静态变量与配置热更新的陷阱
引言:一个看似无害的修改 "这不可能有问题!" 我盯着屏幕上的代码变更,反复确认那个仅仅增加了static关键字的修改. 事情的起因是我们需要上线一个新的HTTP接口调用功能,为了 ...
- 前端开发系列042-基础篇之TypeScript语言特性(二)
这篇文章中我们将继续在语言特性方面展开探讨,主要介绍了TypeScript中流程控制结构.类以及接口等方面的内容,需要说明的是这篇文章中并不会就相关特性的细节深入展开,你能得到的将只有对它们进行的浅尝 ...
- 最近在做一个关于D3数据可视化的项目 知识点记录
简介 RT 跑 Minist 数据集 安装 tensorflow & tensorboard 安装 CUDA cuDnn D3 优秀的例子 gallery例子 http://github.co ...