这是一个 Perl 脚本,它解析#ifdef 条目并组装特定文件中使用的符号列表。然后它打印出所有可能组合的笛卡尔积,该符号打开或关闭。这适用于我的 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 风格的 /* */ 注释而失败,因为我没有费心去有效地解析它们。要考虑的另一件事是,对所有要测试的符号组合可能没有意义,您可以将其构建到脚本或测试服务器中。例如,您可能有用于指定平台的互斥符号:
-DMAC
-DLINUX
-DWINDOWS
测试这些开关的组合并没有真正的意义。一种快速的解决方案是编译所有组合,并且对某些组合会失败感到满意。然后,您对正确性的测试可以是编译总是失败并使用相同的组合成功。
要记住的另一件事是并非所有组合都是有效的,因为它们中的许多不是嵌套的。我认为编译相对便宜,但如果你不小心,组合的数量会增长得非常快。你可以让脚本解析出哪些符号在同一个控制结构中(例如嵌套的#ifdefs),但这更难实现,我在这里没有这样做。