stripcc去除C源代码中未使用的条件编译分枝(转)
来源:互联网 发布:php开源手机商城系统 编辑:程序博客网 时间:2024/04/27 18:13
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处理你的源文件。特别提醒,请在处理之前对你的源代码做备份。
下面分别以stunnel-4.20、lwip-0.5.3和kernel-2.6.20为例说明使用方法:
1,stunnel-4.20:
$ cd stunnel-4.20
$ ./configure
$ make
make通过后即可使用stripcc处理,“-d”表示处理失败时保存相关失败信息(在当前目录下的stripcc.dbg文件中),“.”表示处理执行stripcc时的当前目录下的所有源文件。
$ stripcc -d .
Backing up all source file...[OK]
Adding "#warning" to each source file...[OK]
Parsing output of the compilation..(省略若干'.')..[OK]
Striping unnecessary CCs...[OK]
再次make检验处理后源码是否正常:
$ make
2,lwip-0.5.3:
$ 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/" -d .
Backing up all source file...[OK]
Adding "#warning" to each source file...[OK]
Parsing output of the compilation..(省略若干'.')..[OK]
Striping unnecessary CCs...[OK]
再次make检验处理后源码是否正常:
$ cd proj/unixsim/
$ make
3,kernel-2.6.20:
$ cd linux-2.6.20
使用uml平台默认编译选项:
$ make menuconfig ARCH=um
为了说明stripcc的运行时间,这里使用time在编译时进行时间统计:
$ time make ARCH=um
real 4m6.178s
user 3m12.692s
sys 0m30.518s
统计使用stripcc处理前的代码量:
$ find . -type f -name "*.[ch]" | xargs wc -l | grep total
191018 total
240112 total
178362 total
183622 total
166939 total
455531 total
466098 total
323675 total
418717 total
740114 total
606878 total
626812 total
572085 total
180344 total
66175 total
64838 total
87619 total
107007 total
62556 total
101182 total
119397 total
269427 total
460149 total
425931 total
--------------
7114588(这行是我加起来的,非上面命令的直接输出)
编译耗时4分钟多(P4 2.8GHZ),共有代码711万行,然后使用stripcc处理,stripcc默认的项目编译命令为“make”,但kernel编译时使用的是“make ARCH=um”,所以这里需要使用“-c”选项告诉stripcc编译命令,其他与上面编译一致:
$ time stripcc -c "make ARCH=um" -d .
Backing up all source file...[OK]
Adding "#warning" to each source file...[OK]
Parsing output of the compilation..(省略若干'.')..[OK]
Striping unnecessary CCs...[OK]
real 8m40.420s
user 4m34.353s
sys 2m4.149s
统计经stripcc处理后的内核代码量:
$ find . -type f -name "*.[ch]" | xargs wc -l | grep total
0 total
218 total
0 total
0 total
19642 total
26707 total
8835 total
0 total
187 total
5337 total
0 total
46 total
110152 total
874 total
0 total
6407 total
0 total
0 total
2026 total
29228 total
44996 total
98737 total
--------------
421992
再次make检验处理后源码是否正常:
$ make ARCH=um
一切正常!处理耗时8分钟多(P4 2.8GHZ),大概是正常编译的两倍时间,而处理后的内核代码只剩42万行了,这个结果还算不错吧,至少从代码量上说kernel也就是一个中型软件了,如果你现在用ctags或SourceInSight等工具来浏览代码,相信会容易很多。
4,其他:
stripcc的早期版本称为nocc,考虑到sf.net已有同名项目,不便于发布,所以改名为stripcc。
stripcc及其早期版本经过了一定的测试,但难免存在bug,希望试用的朋友能将发现的问题发给我(dugang@188.com)。
这里附上一个验证过的源码列表,有些是我验证的,有些是其他朋友验证的,其中红色代表未通过,绿色代表正常通过:
ethereal-0.99.0
fcitx-3.4.2
glibc-2.4
httpd-2.2.4
js-1.60
libevent-1.2
libpcap-0.9.5
lighttpd-1.5.0-r1691
linux-2.6.20
openssl-0.9.8d
openvpn-2.0.9
privoxy-3.0.6-stable
prozilla-1.3.7.4
screen-4.0.2
SDL-1.2.11
squid-2.6.STABLE10
ssldump-0.9b3
stardict-2.4.5
stunnel-4.20
tcpdump-3.9.5
thttpd-2.25b
tor-0.1.2.7-alpha
uClibc-0.9.28
valgrind-3.2.0
vim70
除ethereal使用yacc类工具在make过程中生成C代码导致stripcc未能正常通过外,其他均正常。另外需要注意的是如果对kernel-2.6.20以上内核做x86平台处理的话,请将include/asm-i386/percpu.h的第23行和26行:
23 addl $per_cpu__/**/var, cpu;
26 movl $per_cpu__/**/var, cpu;
改为
23 addl $per_cpu__cpu_gdt_descr, cpu;
26 movl $per_cpu__cpu_gdt_descr, cpu;
也就是将"/**/var"改成"cpu_gdt_descr",然后使用就可以了,这个问题可能是因为该.h文件实际上不是C的头文件而是汇编文件(.s)的头文件引起的。
- stripcc去除C源代码中未使用的条件编译分枝(转)
- 【C++】使用条件编译的头文件
- 使用emacs去除源代码中多余的空格
- 《UNP》中源代码的编译和使用
- 《UNP》中源代码的编译和使用
- 条件编译的使用
- Youcompleteme插件使用条件编译(CompileFlags)去除警告和错误
- C语言中常见的7种条件编译语句
- c语言中条件编译相关的预编译指令
- C语言中常见的7种条件编译语句
- 黑马程序员-C语言条件编译的使用
- c++--------------条件编译的问题
- C/C++的条件编译
- C/C++的条件编译
- C语言的条件编译
- C语言的条件编译
- C语言的条件编译
- C/C++的条件编译
- 各种花代表的意义
- SQL查询语句精华
- 优秀网站源码、编程源码下载网站大集中
- 向汶川受灾人民表示诚挚慰问
- LPCTSTR类型?
- stripcc去除C源代码中未使用的条件编译分枝(转)
- 晕,时间过得真快
- 游戏制作人需要什么样的决断力?
- 永久博客地址:NealBlog.Cn
- 永久博客地址:NealBlog.Cn
- 投机智慧
- 常见数据库分页SQL语句
- delete和delete[] 的区别(转)
- Ext中读取DWR方法调用返回的XML字符串