用于自动编译所有ifdef / ifndef指令的工具

时间:2010-01-06 11:19:59

标签: c c-preprocessor conditional-compilation

我的 C 项目使用预处理程序指令来激活/停用某些功能。由于几天前在#ifdef内进行了更改,因此发现一些不太常见的配置不再编译并不罕见。

我们使用脚本来编译最常见的配置,但我正在寻找一种工具来确保编译所有内容(在我们的情况下测试不是问题,我们只想检测ASAP没有停止编译)。通常ifdefs / ifndefs是独立的,因此通常每个模块只需编译两次(所有符号都定义,都是未定义的)。但有时ifdefs是嵌套的,所以这些模块必须编译更多次。

您是否知道搜索所有ifdef / ifndef(也是嵌套的)的工具,并给出了模块必须编译多少次(每个模块中都要定义一组预处理器符号)以确保每个源都有代码行是由编译器分析的吗?

8 个答案:

答案 0 :(得分:4)

我不知道有什么工具可以做你想做的事。但是看看你的问题,我认为你需要的只是一个脚本,它将使用预处理器符号的所有可能组合编译源代码。

就像你说的那样..

#ifdef A 
    CallFnA();
#ifdef B
    CallFnB();
#endif
    CallFnC();
#endif

您必须使用foll组合触发构建

  1. A和B都定义了
  2. 未定义和B定义(这里没有意义,但整个模块需要)
  3. 已定义且未定义B
  4. A和B均未定义
  5. 很想看到一些将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)

您可以将Hudsonmatrix 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)

嗯,我最初认为unifdef可能会有所帮助,但我们会进一步了解你的要求,不,这不会立即得到任何帮助。

答案 7 :(得分:-3)

可能你需要grep吗?