我的 C 项目使用预处理程序指令来激活/停用某些功能。由于几天前在#ifdef
内进行了更改,因此发现一些不太常见的配置不再编译并不罕见。
我们使用脚本来编译最常见的配置,但我正在寻找一种工具来确保编译所有内容(在我们的情况下测试不是问题,我们只想检测ASAP没有停止编译)。通常ifdefs / ifndefs是独立的,因此通常每个模块只需编译两次(所有符号都定义,都是未定义的)。但有时ifdefs是嵌套的,所以这些模块必须编译更多次。
您是否知道搜索所有ifdef / ifndef(也是嵌套的)的工具,并给出了模块必须编译多少次(每个模块中都要定义一组预处理器符号)以确保每个源都有代码行是由编译器分析的吗?
答案 0 :(得分:4)
我不知道有什么工具可以做你想做的事。但是看看你的问题,我认为你需要的只是一个脚本,它将使用预处理器符号的所有可能组合编译源代码。
就像你说的那样..
#ifdef A
CallFnA();
#ifdef B
CallFnB();
#endif
CallFnC();
#endif
您必须使用foll组合触发构建
很想看到一些将grep
源代码并生成组合的脚本。
像
find ./ -name '*.cpp' -exec egrep -h '^#ifdef' {} \; | awk '{ print $2}' | sort | uniq
将* .cpp替换为您要搜索的任何文件。
答案 1 :(得分:2)
这是一个Perl脚本,可以解析#ifdef条目并组装特定文件中使用的符号列表。然后打印出打开或关闭该符号的所有可能组合的Cartesian Product。这适用于我的C ++项目,可能需要对您的设置进行微调。
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;
my $path = $ENV{PWD};
my $symbol_map = {};
find( make_ifdef_processor( $symbol_map ), $path );
foreach my $fn ( keys %$symbol_map ) {
my @symbols = @{ $symbol_map->{$fn} };
my @options;
foreach my $symbol (@symbols) {
push @options, [
"-D$symbol=0",
"-D$symbol=1"
];
}
my @combinations = @{ cartesian( @options ) };
foreach my $combination (@combinations) {
print "compile $fn with these symbols defined:\n";
print "\t", join ' ', ( @$combination );
print "\n";
}
}
sub make_ifdef_processor {
my $map_symbols = shift;
return sub {
my $fn = $_;
if ( $fn =~ /svn-base/ ) {
return;
}
open FILE, "<$fn" or die "Error opening file $fn ($!)";
while ( my $line = <FILE> ) {
if ( $line =~ /^\/\// ) { # skip C-style comments
next;
}
if ( $line =~ /#ifdef\s+(.*)$/ ) {
print "matched line $line\n";
my $symbol = $1;
push @{ $map_symbols->{$fn} }, $symbol;
}
}
}
}
sub cartesian {
my $first_set = shift @_;
my @product = map { [ $_ ] } @$first_set;
foreach my $set (@_) {
my @new_product;
foreach my $s (@$set) {
foreach my $list (@product) {
push @new_product, [ @$list, $s ];
}
}
@product = @new_product;
}
return \@product;
}
这肯定会失败C-style / * * / comments,因为我没有费心去解析那些。要考虑的另一件事是,对于要测试的所有符号组合可能没有意义,您可以将其构建到脚本或测试服务器中。例如,您可能具有用于指定平台的互斥符号:
-DMAC
-DLINUX
-DWINDOWS
测试打开和关闭这些组合的组合并没有多大意义。一个快速的解决方案就是编译所有组合,并且有些会失败。然后,您对正确性的测试可能是编译总是失败并且使用相同的组合成功。
要记住的另一件事是并非所有组合都有效,因为其中许多组合都不是嵌套的。我认为编译相对便宜,但如果你不小心,组合的数量会很快增长。你可以让脚本解析出哪些符号在同一个控制结构中(例如嵌套#ifdefs),但实现起来要困难得多,我在这里没有这样做。
答案 2 :(得分:1)
您可以使用unifdef -s获取预处理器条件中使用的所有预处理器符号的列表。根据围绕其他答案的讨论,这显然不是您需要的信息,但如果您也使用-d选项,则调试输出包括嵌套级别。过滤输出以生成所需的符号组合应该相当简单。
答案 3 :(得分:0)
另一种解决方案是编译所有功能并对功能进行运行时配置测试。这是一个很酷的“技巧”,因为它允许Marketing通过简单地在配置文件中设置值来销售不同的配置并节省工程时间。
否则,我建议使用脚本语言来构建所有配置。
答案 4 :(得分:0)
抱歉,我不知道有任何工具可以帮助您,但如果我必须这样做,我会选择一个简单的脚本来执行此操作: - 将所有源文件复制到另一个地方, - 在每行的开头添加一个运行编号(显然在注释中)(第一个文件的第一个代码行= 1,不要在文件之间重置), - 使用所有预定义配置进行预处理,并检查包含哪些行,哪些行不包含, - 检查哪些行已包含但哪些行丢失。
使用例如运行时间不应超过两天Perl或Python。所需要的是具有包括配置的行的文件。这应该足够快,可以在此脚本的帮助下完成。只需检查配置中没有包含哪些行,然后编辑文件,直到包含每一行。然后偶尔运行它以确保没有新的路径。
分析你想要的源代码将是一个更复杂的脚本,我不确定它是否值得这么麻烦。
答案 5 :(得分:-1)
您可以将Hudson与matrix project一起使用。 (请注意,Hudson不仅仅是一个Java测试工具,而且是一个非常灵活的构建服务器,可以构建几乎任何东西,包括C / C ++项目)。如果设置矩阵项目,则可以选择创建一个或多个轴。对于每个轴,您可以指定一个或多个值。然后,Hudson将使用变量值的所有可能组合运行构建。例如,如果指定
os=windows,linux,osx
wordsize=32,64
Hudson将建立六个组合;每个windows,linux和osx的32位和64位版本。在构建“自由样式项目”(即启动外部构建脚本)时,使用环境变量指定配置。在上面的例子中,“os”和“windows”将被指定为环境变量。
Hudson还支持过滤组合,以避免构建某些无效组合(例如,可以删除Windows 64位,但保留所有其他组合。)
(编辑帖子以提供有关矩阵项目的更多详细信息。)
答案 6 :(得分:-2)
答案 7 :(得分:-3)
可能你需要grep吗?