裁掉不需要的c代码工具

 

unifdef 命令

 

用途

 

从文件中除去 ifdef 行。

 

语法

unifdef -t ] [  -l ] [  -c ] [  -DSymbol ] [  -USymbol ] [  -idSymbol ] [  -iuSymbol ] [  File ]

 

描述

 

unifdef 命令用于除去文件中的 ifdef 行,而不会进行别的操作。为了正确运行,unifdef 命令认出嵌套的 ifdefs、注释、C 语言语法的单引号和双引号,但不包括文件或不解释宏。unifdef 命令认出但并不除去注释。

 

如果没有指定 Fileunifdef 命令从标准输入得到输入,并复制输出到标准输出。

 

一旦指定 Symbol,ifdef 中的行最终被复制到输出或除去。与符号关联的 ifdef、ifndef、else、elif 和 endif 行也要除去。涉及未指定的 Ifdef 不会更改并和相关 ifdef、else、elif 和 endif 行一起拷出。如果相同符号在一个以上的自变量里出现,仅第一个出现的有意义。例如,如果 ifdef X 嵌套在另一个 ifdef X内, 内部的 ifdef 即被认为是无法识别的符号。

 

当使用 ifdef 定界非 C 语言行,如注释或未完成的代码时,有必要指定为此目的使用哪些符号。否则,unifdef 命令将试图分析 ifdef 行的引用和注释。

 

unifdef 命令不能处理 cpp 构造,例如:

 

#if defined(X) || defined(Y)

或者

#elif X

或者

#elif defined(X) || defined(Y)

 

关键字

 

unifdef 命令识别以下关键字:

  • ifdef
  • ifndef
  • else
  • endif
  • elif

 

标志

-c补充unifdef 命令的操作。即保留被除去的行,反之亦然。
-D Symbol指定定义的符号。
File指定输入源。
-id Symbolunifdef 命令不会试图识别指定的 ifdef 内的注释、单引号或双引号,但这些行将被拷出。
-iu Symbolunifdef 命令不会试图识别指定的 ifdef 内的注释、单引号或双引号。这些行不会拷出。
-l用空行替换除去的行,而不是将其删除。
-t允许 unifdef 命令用于纯文本(不是 C 语言代码): unifdef 命令不会试图识别注释、单引号和双引号。
-U Symbol指定要取消定义的符号。

退出状态

 

该命令返回以下退出值:

0输出为输入的精确副本。
1输出不是输入的精确副本。
2命令因为 EOF 过早发生、不相称的elseelifendif而失败。

示例

  1. 示例如下:

    unifdef -DA original.c > modified.c

    使 unifdef 命令阅读original.c文件,并除去 #ifdef A 行。然后除去与 #ifdef A 相关的在 #elif/#else 后的所有行,一直到 #endif。输出放在 modified.c 文件中。

  2. 示例如下:

    unifdef -UA original.c > modified.c

    使 unifdef 命令读 original.c文件,并 除去 #ifdef A,一直到其与其关联的 #elif//#else 或 #endif。对于 #elif,#elif 由 #if替换。对于 #else, #else 同与其相关的 #endif 一同删除。输出放在 modified.c 文件中。

 

文件

/usr/bin/unifdef包含unifdef命令。

相关信息

 

cpp 命令。

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 
 
 
stripcc 0.2.0发布,去除C源代码中未使用的条件编译分枝
Du XiaoGang<dugang@188.com>
1,stripcc能干什么:

    使用C语言编写的软件为了适应各种不同的平台或要求,大多会使用条件编译,这在提高了软件适应性的同时却降低了代码的可读性,比如说有如下代码片断(摘自stunnel-4.20):

void stunnel_info(int raw) {
    char line[STRLEN];


    sprintf(line, "stunnel " VERSION " on " HOST " with %s",
        SSLeay_version(SSLEAY_VERSION));
    if(raw)
        log_raw("%s", line);
    else
        s_log(LOG_NOTICE, "%s", line);

    safecopy(line, "Threading:");
#ifdef USE_UCONTEXT
    safeconcat(line, "UCONTEXT");
#endif
#ifdef USE_PTHREAD
    safeconcat(line, "PTHREAD");
#endif
#ifdef USE_WIN32
    safeconcat(line, "WIN32");
#endif
#ifdef USE_FORK
    safeconcat(line, "FORK");
#endif

#ifdef HAVE_OSSL_ENGINE_H
    safeconcat(line, " SSL:ENGINE");
#endif

    safeconcat(line, " Sockets:");
#ifdef USE_POLL
    safeconcat(line, "POLL");
#else /* defined(USE_POLL) */
    safeconcat(line, "SELECT");
#endif /* defined(USE_POLL) */
#if defined(USE_WIN32) && !defined(_WIN32_WCE)
    if(s_getaddrinfo)
        safeconcat(line, ",IPv6");
    else
        safeconcat(line, ",IPv4");
#else /* defined(USE_WIN32) */
#if defined(USE_IPv6)
    safeconcat(line, ",IPv6");
#else /* defined(USE_IPv6) */
    safeconcat(line, ",IPv4");
#endif /* defined(USE_IPv6) */
#endif /* defined(USE_WIN32) */

#ifdef USE_LIBWRAP
    safeconcat(line, " Auth:LIBWRAP");
#endif

    if(raw)
        log_raw("%s", line);
    else
        s_log(LOG_NOTICE, "%s", line);
}


    阅读该源码,你认为它的可读性怎样?你是否能很容易的从诸多条件编译分枝中找出对应自己特定平台的部分?下面再附上该代码在linux平台(Fedora Core 3)的实际有效代码(使用stripcc处理得到):
   

void stunnel_info(int raw) {
    char line[STRLEN];

    sprintf(line, "stunnel " VERSION " on " HOST " with %s",
        SSLeay_version(SSLEAY_VERSION));
    if(raw)
        log_raw("%s", line);
    else
        s_log(LOG_NOTICE, "%s", line);

    safecopy(line, "Threading:");
    safeconcat(line, "PTHREAD");

    safeconcat(line, " SSL:ENGINE");

    safeconcat(line, " Sockets:");
    safeconcat(line, "POLL");
    safeconcat(line, ",IPv4");

    safeconcat(line, " Auth:LIBWRAP");

    if(raw)
        log_raw("%s", line);
    else
        s_log(LOG_NOTICE, "%s", line);
}


    再次阅读,是不是感觉清楚多了?

    其他常见的情况还包括针对不同平台同一函数会有不同实现,这样当你使用ctags或者SourceInSight等工具来分析代码时也很难一下找到真正的目标,这在linux kernel等支持多平台的源代码中非常多见,比如kernel中arch目录下的代码。

    stripcc正是为了解决上述问题,简单的说, stripcc的用途就是为了提高C源代码的可读性而去除其中未被编译的条件编译分枝,但保留正常的注释以及源码风格

2,stripcc是怎么工作的:


    stripcc的工作原理很容易理解:
    1,在要处理的代码(比如*.c/*.h)中合适的位置插入gcc扩展的预编译头#warning。
    2,进而编译整个项目获取gcc编译输出并进行分析。
    3,根据分析结果确定某段代码是否使用,使用则保留,未使用则去除。

    这种工作方式相当于手动用#warning来确定某个条件编译分枝(或者整个文件)是否有效,原理上讲是相当可靠的,不会把你的有效代码删除。但 要求你的代码在使用stripcc处理之前必须能使用某种方式调用gcc成功编译

3,如何使用stripcc:

    首先是下载stripcc源码并编译,stripcc使用GPL方式发布,你可以从http://sourceforge.net/projects/stripcc处下载源码文件,获取源码后解压 、make、make install 完成编译安装。安装目录在/usr/local/bin下,可以选择自己拷贝或者修改Makefile以便放入其他位置,但请确认stripcc所在目录在你的执行目录$PATH里。

    编译安装完成后就是利用stripcc处理你的源文件。 特别提醒,请在处理之前对你的源代码做备份

    执行stripcc -h会列出stripcc的使用方法,主要是各个可选项的含义,如下:

    $ stripcc -h
    Usage: stripcc <option(s)>
    Remove CCs(Conditional Compilation Branchs) which won't be compiled from c/c++ source files under current directory.
     The options are:
      -c <str> Commands for build target program, "make" is default
      -m <str> Directory to run build commands, current directory is default
      -f       Working in fast mode (Experimental, NOT RECOMMENDED!)
      -n       Don't verify after strip
      -v       Display this program's version number
      -h       Display this output

    “-c” 用来指定项目编译使用的命令,默认是“make”,如果您的项目也是“make”编译,则可略过“-c”选项,如果是其他,比如“make vmlinux”则需要指定“ -c "make vmlinux" ”,具体可参考后文所举的Linux的例子。
    “-m” 用来指定执行编译命令(如“make”)的目录,这对一些不是在顶层目录执行编译命令的项目非常有用,可参考后文所举的lwip例子。
    “-f” 让stripcc运行在快速模式,这是stripcc-0.2.0新加入的特性,但可惜的是这个模式对项目的要求比较苛刻, 不推荐使用
    “-n” 让stripcc在处理完代码之后直接退出,而不执行验证过程,用户可以手动敲入“make”等项目编译命令自行验证,这也是0.2.0版本的新加入特性,默认为自动执行验证。
    “-v” 显示stripcc的版本信息。
    “-h” 显示上面的帮助信息。

    此外,stripcc从0.2.0版本开始支持配置文件,这很大程度上提高了用户对代码处理过程的控制度,处理代码时stripcc将在被调用的当前目录下寻找名为stripcc.conf的配置文件,该文件包含5个部分:

    [strip_exts] 表示以哪些后缀名结束的文件将被处理,默认为“.c”和“.h”。
    [strip_dirs] 表示哪些目录下的特定后缀名文件将被处理(包含子目录),默认为“.”,即当前目录。
    [dont_strip_dirs] 表示哪些目录下的文件将不被处理,即需要从[strip_dirs]目录中去掉的部分,默认为空。
    [strip_files] 表示还有哪些单独的文件应当被处理,这些文件不受后缀名的限制,默认为空。
    [dont_strip_files] 表示不应当被处理的文件。

    关于配置文件的详细写法,可以参考源码包中的stripcc.conf, 需要注意的是所有目录和文件都采用相对路径,即相对于stripcc.conf所在的目录,另外,所有路径都以“.”开始,比如“./dir/file.c”

    当stripcc在当前调用目录下找不到stripcc.conf时将会使用默认值,即递归处理当前目录下的所有“.c”和“.h”文件。

    下面分别以stunnel-4.21、lwip-0.5.3和kernel-2.6.27.7为例说明使用方法:

    1,stunnel-4.21:

    $ tar zxf stunnel-4.21.tar.gz
    $ cd stunnel-4.21
    $ ./configure
    $ make

    make通过后即可使用stripcc处理,stripcc默认处理当前目录下的所有源文件( 与0.1.*版不同,stripcc自从0.2.0版开始不需要再指定处理目录)。
    $ stripcc
    o Getting a list of files which will be stripped...
      o Failed to open config file(./stripcc.conf), use the default values.
    o Backing up files...
    o Adding "#warning"...
    o Try to build target, this operation may takes a few minutes
    o Restore files...
    o Stripping files...
    o Start to verify
    o Done!

    看到绿色的“Done!”表示处理成功。

   
    2,lwip-0.5.3:

    $ tar zxf lwip-0.5.3.tar.gz
    $ cd lwip-0.5.3

    选用lwip做示例的主要原因是lwip编译时并非在lwip的顶层源码目录下执行“make”,而是在“proj/unixsim/”目录下,这也具有一定的普遍性。
    $ cd proj/unixsim/
    $ make

    编译成功后回到顶层源码目录:
    $ cd ..
    $ cd ..

    在顶层源码目录调用stripcc进行处理,但需告诉stripcc执行“make”的目录,使用“-m”选项:
    $ stripcc -m "proj/unixsim"
    o Getting a list of files which will be stripped...
      o Failed to open config file(./stripcc.conf), use the default values.
    o Backing up files...
    o Adding "#warning"...
    o Try to build target, this operation may takes a few minutes.
    o Restore files...
    o Stripping files...
    o Start to verify
     o Done!

   
    3,kernel-2.6.27.7:

    $ tar jxf linux-2.6.27.7.tar.bz2
    $ cd linux-2.6.27.7

    使用x86平台默认编译选项并编译:
    $ make defconfig
    $ make vmlinux

    统计使用stripcc处理前的kernel代码总量:
    $ totalcode
    totalline:  8410243

    共有代码841万行,然后使用stripcc处理,stripcc默认的项目编译命令为“make”,但kernel编译时使用的是“make vmlinux”,所以这里需要使用“-c”选项告诉stripcc编译命令,其他与上面编译一致:
    $ stripcc -c "make vmlinux"
    o Getting a list of files which will be stripped...
      o Failed to open config file(./stripcc.conf), use the default values.
    o Backing up files...
    o Adding "#warning"...
      o Invalid source line(./arch/mips/kernel/sync-r4k.c: 159).
    o Try to build target, this operation may takes a few minutes.  
    o Restore files...
    o Stripping files...
    o Start to verify   
    o Done!

    统计经stripcc处理后的内核代码量:
    $ totalcode
    totalline:  1287399

    处理耗时大概是正常编译的5倍时间(包含验证过程),而处理后的内核代码只剩128万行了,大约有85%的内核代码被清除,如果现在用ctags或 SourceInSight等工具来浏览代码,相信会容易很多。事实上由于本次编译采用的是kernel默认选项,代码中仍然包含大量的您可能永远用不到的内核特性和设备驱动,如果去除这些编译选项,完全可以将kernel的代码控制在40万行以内。


4,其他:
   
    1,stripcc-0.2.0版本做了哪些主要改进?相对于0.1.*版本:
        a,支持配置文件,更加灵活的使用方式。
        b,加强了代码容错功能,stripcc-0.1.*工作时如果遇到有语法错误的C文件将自动退出,0.2.0版本会忽略该文件而继续处理。
        c,增加了快速处理模式,但不幸的是事实效果并不好,本来预想的0.2.0的最大改进只能暂时作为实验特性。

    2,stripcc-0.2.0支持哪些OS或者硬件平台?原理上stripcc-0.2.0可以支持所有的能运行GCC的POSIX平台,目前已经验证过的平台如下:
        solaris/t1000:
            -bash-3.00$ uname -a
            SunOS t1000 5.10 Generic_118833-33 sun4v sparc SUNW,Sun-Fire-T1000 Solaris

            -bash-3.00$ gcc --version
            sparc-sun-solaris2.10-gcc (GCC) 4.0.3 (gccfss)
            Copyright (C) 2006 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        solaris/x4100:
            -bash-3.00$ uname -a
            SunOS x4100 5.10 Generic_118855-33 i86pc i386 i86pc

            -bash-3.00$ gcc --version
            gcc (GCC) 3.4.3 (csl-sol210-3_4-branch+sol_rpath)
            Copyright (C) 2004 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        solaris/i386:
            -bash-3.00$ uname -a
            SunOS solaris 5.10 Generic_118855-33 i86pc i386 i86pc Solaris

            -bash-3.00$ gcc --version
            gcc (GCC) 3.4.3 (csl-sol210-3_4-branch+sol_rpath)
            Copyright (C) 2004 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        linux/x86_64:
            dugang@ubuntu:~/test$ uname -a
            Linux ubuntu 2.6.24-21-generic #1 SMP Tue Oct 21 23:09:30 UTC 2008 x86_64 GNU/Linux

            dugang@ubuntu:~/test$ gcc --version
            gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
            Copyright (C) 2007 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        freebsd/amd64:
            -bash-2.05b$ uname -a
            FreeBSD freebsd.unix-center.net 6.2-RELEASE FreeBSD 6.2-RELEASE #0: Fri Jan 12 08:43:30 UTC 2007
            root@portnoy.cse.buffalo.edu:/usr/obj/usr/src/sys/SMP  amd64

            -bash-2.05b$ gcc --version
            gcc (GCC) 3.4.6 [FreeBSD] 20060305
            Copyright (C) 2006 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        aix/powerpc:
            -bash-3.00$ uname -a
            AIX aix 3 5 00C97AC04C00 powerpc unknown AIX

            -bash-3.00$ gcc --version
            gcc (GCC) 4.2.0
            Copyright (C) 2007 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        linux/i386:
            [duxg@l151 stripcc]$ uname -a
            Linux l151 2.6.23.1-42.fc8 #1 SMP Tue Oct 30 13:55:12 EDT 2007 i686 i686 i386 GNU/Linux

            [duxg@l151 stripcc]$ gcc --version
            gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-33)
            Copyright (C) 2006 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions.  There is NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    3,stripcc对于C/C++的支持如何?
        stripcc遵循C99标准并且尽可能的支持GCC扩展特性,其中唯一与C99相悖的是对多行注释(/* ... */)的处理,C99要求保留其中的换行符,但GCC默认丢弃换行符,这里stripcc与GCC保持一致。
        C++的支持上stripcc并没有做什么工作,如果C++语言预编译等部分与C99一致,那么stripcc确实不需要做更多工作,否则只能留待将来处理,到目前为止,没有听到有C++处理方面的错误。

5,已知的问题:

    1,由于stripcc的工作原理限制,在遇到打开GCC的“-Werror”编译选项的项目时不能正常工作,所以如果stripcc提示处理失败,请先确认一下问题是不是由于该选项引起,如果是的话从Makefile中去掉该选项即可,目前见到的打开了该选项的项目有trousers等。

    2,stripcc不能处理在编译过程中自动从项目已有C源码中抽取代码组成新源码文件的项目,比如GCC/Ethereal等。但对于编译时从非C源码文件产生新源码的项目则不会有问题,比如那些使用了lex/yacc等自动编译工具的项目。

6,致谢:
   
    感谢各位朋友使用stripcc并且提出的宝贵意见。

    特别感谢为stripcc提供补丁的朋友,包括:
    fangmz
    harite.k
    xishipan

    google docs(http://docs.google.com)对于需要在linux下写文档的朋友是个不错的选择,本文档即使用google docs编写。

    unix-center(http://www.unix-center.net)提供了诸多Unix实验环境,stripcc的多平台测试从而得以轻松完成。

    最后,如果您对stripcc有什么建议或意见,请联系我:dugang@188.com,谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值