CSharpCompilation.Emit生成的PDB与EXE、源码不配对如何解决
问题描述
我使用CSharpCompilation.Emit函数从我的.cs脚本生成exe和pdb文件,代码如下:
SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(File.ReadAllText("C:\\Temp\\Z\\Simple.cs"))); CSharpCompilation compilation = CSharpCompilation.Create("Simple.exe") .WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication)) .AddReferences( MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Windows.Forms.MessageBox).Assembly.Location) ) .AddSyntaxTrees(syntaxTree); EmitResult result = compilation.Emit("C:\\Temp\\Z\\Simple.exe", "C:\\Temp\\Z\\Simple.pdb");
但我在调试器中使用时发现PDB模块无法被正确识别,无法与我的Simple.exe和Simple.cs文件配对。当我附加到运行中的进程时,会跳转到未加载PDB的另一个Simple.exe实例。
更新:我在模块窗口中发现如下信息:
该模块是由ngen.exe工具创建的预编译二进制文件。调试器不会尝试为这类二进制文件加载符号,而是会在.NET运行时加载原始dll/exe时加载对应符号。
解决方案
根因说明
系统中存在你编译的Simple.exe对应的NGEN预编译原生镜像,.NET运行时默认会优先加载原生镜像而非你生成的IL格式exe,而原生镜像和你生成的pdb不匹配,所以调试器无法关联符号和源码,才会出现跳转到其他实例的问题。
操作步骤
- 删除对应程序集的NGEN镜像
以管理员权限打开命令提示符,执行以下命令删除已生成的Simple.exe原生镜像:ngen delete C:\Temp\Z\Simple.exe - 修改Roslyn编译配置,保证PDB和程序集完全匹配
你当前的编译配置没有显式指定调试信息格式,建议修改CSharpCompilationOptions配置,显式开启全量调试信息生成,同时注意路径前加@避免转义符导致的路径异常:SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(SourceText.From(File.ReadAllText(@"C:\Temp\Z\Simple.cs"))); CSharpCompilation compilation = CSharpCompilation.Create("Simple.exe") .WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication) // 显式指定调试信息类型为完整格式,保证PDB匹配 .WithDebugInformationKind(DebugInformationKind.Full)) .AddReferences( MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Windows.Forms.MessageBox).Assembly.Location) ) .AddSyntaxTrees(syntaxTree); EmitResult result = compilation.Emit(@"C:\Temp\Z\Simple.exe", @"C:\Temp\Z\Simple.pdb"); - 强制运行时加载IL版本程序集
如果删除NGEN镜像后仍有问题,可以在启动Simple.exe前临时设置系统环境变量禁用NGEN加载:
该环境变量会让.NET运行时强制走JIT编译你生成的IL程序集,保证和PDB匹配。set COMPLUS_ZapDisable=1 C:\Temp\Z\Simple.exe - 配置Visual Studio调试选项
打开VS的「工具」-「选项」-「调试」-「符号」,将C:\Temp\Z\目录添加到符号文件(.pdb)位置列表中,同时取消勾选「调试」-「常规」下的「启用仅我的代码」选项,避免调试器过滤掉你的程序集符号。
内容的提问来源于stack exchange,提问作者jing
相关产品推荐
相关产品推荐


