GCCFilter - 用于在 Visual Studio 中使用 GCC 编译的脚本






4.88/5 (18投票s)
本文介绍如何使用 Makefile 项目和一个简单的 PERL 脚本,使 Visual Studio“理解”GCC 产生的错误消息。
引言
如果有些东西更兼容,生活会更轻松。 例如,在飞越大西洋时无需电源插头适配器。 例如,不必关心你的小工具需要哪种电池。 例如,将你喜欢的 IDE 与嵌入式项目可能需要的任何编译器一起使用...
等一下,我们是软件开发人员,我们应该知道如何使事物兼容。 本文介绍如何使用 Makefile 项目和一个简单的 PERL 脚本,使 Visual Studio“理解”GCC 产生的错误消息。
虽然 Visual Studio 是一个具有众多功能的复杂 IDE,但它编译 C/C++ 代码的方式非常简单:它只是执行 Microsoft C++ 编译器 (cl.exe) 并解析其输出以获取错误/警告列表。 那么,这是否意味着我们需要完全模拟 cl.exe 版本 15 的行为(工具版本 15 典型的庞大命令行开关)? 幸运的是,有一种更简单的方法。
Makefile 项目
Visual Studio 支持一种特殊的项目类型 - makefile 项目。 它最初旨在与 Microsoft make 工具 (NMake) 一起使用,但实际上它只是运行给定的命令来构建或清理解决方案;更重要的是,它期望它以与 cl.exe 兼容的方式报告错误。
因此,让我们尝试创建一个 Visual Studio 项目,以使用 GCC 构建 ARM 固件文件。 在开始之前,创建一个批处理文件(我们称之为 build.bat),该文件要么调用 GNU make,要么只是调用 GCC 来编译你的代码。 为了简单起见,我将使用一个用于 AT91SAM7S256 微控制器的微型“LED 闪烁”演示进行说明。 在这种情况下,built.bat 文件将只包含 1 行
C:\SysGCC\arm-eabi\bin\arm-eabi-g++.exe testled.cpp ../shared/board_cstartup.o ../shared/board_lowlevel.o -nostartfiles -DAT91SAM7S256 -I../shared/at91sam7s256 -T../shared/at91sam7s256/flash_noremap.lds -o testled.elf
如果 testled.cpp 包含错误,arm-eabi-g++.exe 将报告这些错误。 因此,让我们让 Visual Studio 理解其输出,并帮助我们在错误列表中导航
1. 打开 Visual Studio。
2. 选择文件 -> 新建 -> 项目,然后选择 Visual C++ -> 常规 -> Makefile 项目。
3. 指定你的嵌入式项目所在的目录。
4. 指定 "build.bat" 作为你的命令行。
5. 将你的源文件添加到项目,以便 Visual Studio 可以识别它们
那么,当我们在源文件中犯错误并尝试构建程序时会发生什么? Visual Studio 将运行 build.bat,build.bat 将运行 GCC,GCC 将报告错误,Visual Studio 将显示其输出。
这里的问题是这些错误消息不可点击。 你可以将它们视为纯文本,但当你双击它们时,Visual Studio 不会打开源文件。 它们也不会出现在错误列表窗口中。 发生这种情况的原因是 Visual Studio 和 GCC 使用了不同的错误消息格式。 GCC 错误消息如下所示
<file_name>:row:column: error: <text>
反过来,Visual Studio 期望这样的东西
<file_name>(row,column): error: <text>
一个很小的差异,但足以让 Visual Studio 完全忽略这些消息,并让你手动搜索行号。
该脚本
解决这个问题的方法很简单。 我们将编写一个脚本,该脚本获取 built.bat 产生的输出并转换错误消息。 此外,除了插入括号并将冒号转换为逗号之外,还有更多的技巧
- 我们需要将相对路径转换为绝对路径。
- 我们需要将 cygwin 样式(或 mingw 样式)路径转换为普通的 Windows 路径。
- 我们需要将“c:/xxx”路径转换为“c:\xxx”
制作此类脚本的最快方法之一是使用 PERL 语言。 它有其优点和缺点,但它可能是制作 100 行以下必须进行一些简单文本处理的简单脚本的最简单方法之一。
首先,我们需要在 Make 项目设置中更改构建命令行
build.bat 2>&1 | E:\Perl\bin\perl.exe gccfilt.pl
如果你没有安装 perl.exe,可以通过安装 cygwin 环境来获取它。
“2>&1”构造表示“将 STDERR 与 STDOUT 连接在一起”,或者用简单的话说“也将错误消息传递到脚本”。
其次,让我们编写脚本。 我们将使用 2 个正则表达式检测 GCC 错误消息,然后尝试使用我们稍后定义的 unix2winpath() 函数转换路径
$mydir = `cmd /c cd`; chomp $mydir; foreach (<STDIN>) { if (/^([^ ]+):([0-9]+):([0-9]+): (.*)$/) { print unix2winpath($1)."($2,$3) : $4\n"; } elsif (/^(In file included from )([^ ]+):([0-9]+):([0-9]+):$/) { print unix2winpath($2)."($3,$4) : <==== Included from here (double-click to go to line)\n"; } else { print "$_"; } }
现在让我们定义路径转换函数
sub unix2winpath { my $fp = $_[0]; #Handle "c:/xxx" paths if (substr($fp,1,1) eq ':') { $fp =~ s/\//\\/g; return $fp; } #Handle relative paths if (substr($fp,0,1) ne '/') { $fp =~ s/\//\\/g; return "$mydir\\$fp"; } }
最后,我们需要将绝对路径转换为 Windows 格式。 我们将使用“mount”命令提取 Cygwin/MinGW 路径模板,而不是硬编码它们:
foreach(`mount`) { if (/^([^ \t]+) on ([^ \t]+) /) { if ($2 eq '/') { $ROOTMOUNT = $1; } else { $MOUNTS{$2} = $1; } } }
最后,让我们在 unix2winpath() 函数中使用此信息
foreach(keys %MOUNTS) { if ($fp =~ /^$_\/(.*)$/) { my $suffix = $1; $suffix =~ s/\//\\/g; return "$MOUNTS{$_}\\$suffix"; } } $fp =~ s/\//\\/g; return $ROOTMOUNT.$fp;
它来了。 GCC 消息会被即时转换,Visual Studio 处理它们的方式与处理来自 cl.exe 的消息的方式相同。 双击消息以导航到一行,或使用错误列表。 当然,不要忘记 F8 快捷键,它可以让你快速跳转到下一个错误。