加入收藏 | 设为首页 | 会员中心 | 我要投稿 | RSS
您当前的位置:首页 > 教程文章 > Linux

Linux下的常用编程工具初探

时间:2011-05-11 20:09:58  来源:  作者:

引言

Linux在很多人眼中是非常好的操作系统,不仅因为它的内核和函数库的完整源代码都是公开的,而且因为它拥有许多好用的程序开发工具。 下面就介绍几种常用的编程工具,熟悉这些工具对于开发Linux应用程序是很有必要的。当然了,像其它Linux程序一样,更详细的内容你能在man手册或info页中找到。

一.gcc编译器:

    gcc是GNU提供的优秀的软件之一,其性能不亚于任何商业编译器。它具有惊人的可移植性,而它也号称其最优化功能非常强大。gcc功能实在太多(不信的话你试一下man gcc),这里无法一一列举,只能介绍一些常用的参数。

-o filename:这可能是你最常用的一个选项了。它用来产生以指定名字的可执行输出文件。如果不指定文件名,gcc产生默认的a.out。键入./filename就可执行程序,查看结果。

$ gcc hello.c -o hello
$ ./hello
hello world!

提示:在使用gcc命令的时候不要用Tab键来补齐文件名,因为那可能会覆盖源文件。
-c: 只编译不链接,产生以.o结尾的目标文件。当然它也可以同时编译多个文件。

$ gcc -c hello.c
$ls -l hello.o
-rw-r--r-- 1 wangcong wangcong 888 6月 11 23:20 hello.o

-g/-ggdb: -g参数可以让gcc将一些调试信息加入目标文件中,而-ggdb专为gdb调试器产生足够的调试信息。如需用gdb调试程序应加上此项。注意:这会使目标文件大小增加,我们最好只在测试时使用这个参数,最后发行版中将其去除。

例如:

$ gcc hash.c -o hash -ggdb

-Idir: 要求gcc在搜寻头文件时除了默认的目录/usr/include,也要到指定的目录dir中去找。

比如,编译test.c时要用到/home/myname/test.h,我们可以:

$gcc -I/home/myname test.c -o test

-llibname: 尝试链接指定名为liblibname.a的函数库。注意-l选项的顺序是有意义的。

比如,test.c中用到了数学函数库,我们要链接libm.a,可以:

$ gcc test.c -lm -o p

-Ldir: 让gcc也要在指定的目录dir中去寻找-l指定的函数库。

例如我们要链接/home/myname/libtest.a,我们这样做:

$gcc -I/home/myname -L/home/myname -ltest test.c -o test

-On: 最优化选项。后面的n越大最优化程度越大。一般最常用的是-O2。-O0是不优化,这也是默认的。

$gcc -O2 -o foo foo.c

-Wall/-w: -Wall将打开所有警告,而-w将关闭所有警告。在编译C程序时,强烈建议你加上-Wall选项,因为gcc给出的很多警告都是相当有用的。当然还有折中的选择,具体请参阅man手册

-lefence: 将libefence.a函数库链接上,给程序加上电子篱笆,可以用来检查内存泄漏。挺有用的选项。

-S:用来产生相应的汇编源文件,默认的文件名是

filename.s

-ansi/-std=standard:standard可以是以下内容:c89,c9x,c99,gnu89,gnu9x,gnu99等。其中-std=c89就相当于-ansi。而gnuxx相当于cxx加上gnu扩展。     当然了,它也可以用来调试C++,Fortran等其它程序。 另外,即使你编译时使用了-Wall选项,也建议你使用lint检查一下你的C程序,它能给出很多有用的信息。Linux常用的lint工具是splint。[12]对GCC做了全面的介绍,绝对是首先参考。

二.管理工具make:

    make是一个通用的工程管理工具,它可以“自动化编译”,极大地提高了软件开发的效率,无怪乎它被誉为“Unix发展的一个中流砥柱”。make的使用是根据预先设定的规则来运行的,这些设定的规则记录在一个文件中,即makefile

    make命令的格式是:

make [ -f makefile ] [ option ] ... target ...

-c dir :将指定目录设为make开始运行后的工作目录。

-f filename :将指定的文件作为makefile

-k :使make尽可能地编译,即使命令调用返回一个错误,make也不会停止运行。这个功能很有用,例如,当需要移植的时候;你可以创建尽可能多的目标文件,然后可以在不用等待中间文件创建的同时,移植到不能创建的文件处
 下面简单地介绍一下makefile的基本书写规则。makefile基本书写规则如下:

    target ... : prerequisites ...

        command

        ...

target是目标文件,也就是你要产生的文件或一个标签; prerequisites是产生目标文件所需的文件列表;command是make需要执行的命令。第一个命令可以加“;”跟在倚赖文件列表后,也可以 另起一行书写。注意:当命令另起一行书写时一定要加tab键,否则make不认识。一行放不下时可以用“”来续行,在一行开头用“#”开始注释。

    例如,有下面一个简单的工程,其倚赖关系如下:


上图中,工程example倚赖于test.o 和main.o,而test.o倚赖test.h和test.c,main.o倚赖main.c和main.h。我们将这样写makefile:

example:test.o main.o
    gcc -o example test.o main.o
main.o:main.c main.h
    gcc -c main.c
test.o:test.c test.h
    gcc -c test.c

但是,你会发现,我们编译完成后,test.o和main.o没用了,我们应该删除它们。 那么应该怎么做呢?我们可以加一个动作名字clean,让这个动作完成删除作用。

clean:
    rm -f test.o main.o

要执行删除只要运行

$make clean

就可以了。但是这还不够, 因为我们也有可能想产生一个目标文件叫做clean,这就会造成冲突。为了避免如此, 我们增加一行:

.PHONY: clean

.PHONY是一个伪指令,向make说明clean不是一个文件。当计算clean依赖关系时,make都会忽略任何名为clean的文件。 make除此之外还有大量的高级功能,比如:宏变量,流程控制等。 如果你想了解更多关于make的知识,请看[5]。

    其实,makefile并不好写,尤其是对于大型工程项目。我们可以使用imake,它是一个makefile的生成程序,利用了C的预处理程 序,你只要写一个imakefile文件,就能使用imake来产生一个makefile。当然,还有其它的makefile生成器,像ICmakeautomake等,具体内容请阅读它们的相关文档。

三.调试器gdb:

    gdb是一款优秀的调试器,对它熟悉了你就会发现它真的很好用。在使用gdb调试程序前,你应该确认编译时加上了-ggdb选项,那样才能产生更多的调试信息。
提示:虽然你可以同时使用-ggdb和-O选项,但是不建议你那么做,因为一些最优化功能会让调试变得复杂。

下面将通过一个程序展示gdb的使用方法。有错误的程序是test.c。

$ gcc test.c -ggdb -o test
$ gdb test
GNU gdb Red Hat Linux (6.1post-1.20040607.41rh)
Copyright 2004 Free Software Foundation, Inc.
...
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb)

好了,现在gdb已经准备好接收命令了。

(gdb) l
1 #include < stdio.h>
2 int main(void){
3     int i=0;
4     for(;i<=10;i++);
5         printf("Now the value of i is:%dn",i);
6     return 0;
7     }

l/list命令的功能是列出源代码。如果后面带上行号,则会列出指定行号附近的代码。如果有多个文件的话,你也可以通过指定文件名:行号来列出对应的代码。

(gdb) b main
Breakpoint 1 at 0x8048384: file test.c, line 3.

b/break是插入断点,后面可以是函数名,也可以是行号。

(gdb) r
Starting program: /misc/myprogram/test

Breakpoint 1, main () at test.c:3
3 int i=0;

r/run命令是运行程序,直到断点处或程序结束。

(gdb)watch i
Hardware watchpoint 2: i

watch是用来观察变量的变化的,一旦指定变量发生变化就停止程序。

(gdb) n
4 for(;i<=10;i++);
(gdb) n
Hardware watchpoint 4: i

Old value = 7216256
New value = 1
0x08048396 in main () at test.c:4
4 for(;i<=10;i++);

n/next是执行下一行程序。i的值发生了变化,程序停了下来。

(gdb) p i
$1 = 1

p/print用来打印指定表达式的当前值。

...
(gdb) c
Continuing.
Now the value of i is:11

Program exited normally.

c/continue的功能是继续执行程序直到下一个断点处或程序结束。

(gdb) q
$

q/quit是退出gdb调试程序。 调试完毕,如果你想把调试信息从执行文件中去掉而又不重新编译,可以使用命令:stripfilename

使用gdb我们可以很快找出错误。gdb还有很多高级功能,比如进行汇编级别的调试,而且可以和emacs搭配使用,是非常优秀的调试工具。[8]中对它进行了更全面的介绍。 

四.性能分析工具gprof:

    有一些程序设计工具,它可以告诉你程序执行的效率,整个程序的调用结构,函数调用关系等。这样的工具真的很有用。gprof就是这样的一个效率分 析工具,它能产生一份详细的列表,列出程序执行的一些统计值,其中包括每个函数被调用的频率,被谁调用,所花费时间等。要使用gprof,在用gcc编译 时要加上-pg参数。这个参数会在目的文件中加上gprof所需的信息,也会将执行文件连接上支持性能分析的函数库。

    你只要直接执行编译时加过-pg的程序即可,执行完毕后会在当前工作目录下产生一个gmon.out的文件,它记录了gprof所需的信息,我们可以用gprof来读取它。

$ gcc bintree.c -o bintree -pg
$ ./bintree
...
$ gprof bintree gmon.out
Flat profile:

Each sample counts as 0.01 seconds.
no time accumulated
  %   cumulative   self              self     total
 time   seconds   seconds    calls  Ts/call  Ts/call  name
  0.00      0.00     0.00       28     0.00     0.00  print
  0.00      0.00     0.00        7     0.00     0.00  btree_insert
...

gprof的输出信息相当冗长,上面省略了很多。由于上面的函数执行太快,而gprof的计时单位相当粗略,所以那些函数的执行时间都显示0.00秒。gprof能为我们提供不少有用的信息。

    另一个常用的计时工具是time命令,它可以精确地测量程序运行时间。使用它只需在其后面 加上要测量的命令即可。比如: 

$time ./test>/dev/null

显示如下,分别是实际耗时,用户级别耗时和系统级别耗时:

real    0m0.056s
user    0m0.014s
sys     0m0.006s

它还能格式化输出,还能测量输入/输出,消息数目,非常方便。还有一个更简单的calls程序,它只显示源代码中函数调用的树状结构。而strace能够显示程序执行时用到的系统调用,具体请参阅相关手册。

五.链接器ld:

    ld是GNU的链接器,支持生成大量的可执行文件格式,它是一款复杂而快捷的工具。 ld有许多灵活的参数来控制其链接过程。这里只介绍主要几个参数。

    如果你希望用example.ld作为链接脚本,可以这样使用:

    ld -T example.ld

如果你想把一系列的.o文件链接到另外一个.o文件中,可以像这样用ld:

    ld -r foo.o bar.o -o example.o

如果你希望ld生成一个Linux上使用的共享库,可以用:

    ld -shared ...

如果你想去掉文件中的符号表等内容,加上-s选项。而-S选项则只去掉调试信息。

    ld -s ...

如果你想把entry作为程序入口,可以:

    ld -e entry ...

如果你想把.text段加载到0x0处,可以:

    ld -Ttext 0x0 ...

查看帮助信息可以用:

    ld --help

了解更多,请查看Steve Chamberlain的文章[6]。

六.Patch文件:

    如果你在维护包含很多源文件的一个大型项目,每次更新后都推出完整的源程序是不太可行的,所以最好就用patch程序来更新原来的程序。这样,当 你的程序升级时,你只要推出源文件对应的patch文件,其他人就能通过执行patch来使用那个patch文件,以获得最新版本的程序。
 

    比如我们有一个程序foo,我们把它更新为bar,我们可以用diff程序这样产生patch文件:

$diff -u foo bar > foo.patch

-u参数指定使用特殊的diff输出格式,否则得到的patch格式怪异,一般人都没法看懂。

foo.patch就包含了描述foo和bar不同的信息,我们将用这个文件来更新。

提示:一定要注意diff命令后面的文件名顺序,一定是旧的文件在前,新的文件在后!
接下来,我们用patch来更新:

$patch foo < foo.patch

使用过某个patch文件后,若要再次使用该patch文件,patch程序会产生警告信息:询问是否以-R方式执行,-R将还原文件。这样很好,防止进行了误操作。当然,有时你想更新的是整个目录中的所有源文件,比如foo和bar两个目录,我们可以:

$diff -cr foo bar >foo.patch
$patch -p0 < foo.patch

diff的-c参数表示输出上下文格式,-r参数表示递归的比较两个目录。-p0告诉patch程序被更新的文件的路径名并没改变。

    diffstat是一个很有用的工具,它可以列出patch 所引起的变更的统计(加入或移出的代码行)。输出关于patch的信息,执行:$diffstat -p1 foo.patch

    更多选项请参阅patch和diff的使用手册。 和diff类似的工具还有比较三个文件的diff3,合并文件的sdiff,简单比较的cmp,分行比较的comm等,这里就不一一介绍了。

七.版本控制系统CVS:

    CVS是非常优秀的版本控制工具,比较适合大项目的版本控制。甚至可以说没有CVS就不会有今天GNU的流行。GNU绝大多数的项目都采用CVS来控制版本。熟悉CVS对Linux程序员来说是非常有必要的。 CVS的使用很复杂,这里只做简单介绍。CVS管理着repository,里面存储着正式的源代码。每个在repository项目叫做module。开发者不能直接编辑repository中的文件,而是先要取出(check out),编辑完后再把源代码传送回repositorycommit)。 

    首先,我们应该把环境变量CVSROOT设成我们想要存储repository的目录:

$mkdir /usr/local/CVSROOT
$export CVSROOT=/usr/local/CVSROOT

提示:不要把CVS的repository建在和你想要加入repository之中的项目相同的目录中。这会导致一个死循环。
储存目录建好后,我们就可以建立repository了:$cvs init

然后要在repository中建立项目。在CVS中建立项目有很多方法,我们可以用下面的命令:

cvs import dir manufacturer tag
其中dir是项目所属的目录.manufacturer是作者名(设成别的也可以),tag是版本编号,比如说是initialstart。例如:

$cvs import example myname initial

一旦在CVS中建立了项目,开发者们就可以开始各自的工作了,他们互不影响。

提示:避免直接编辑CVS repository中的文件,这不符合CVS设计者的本意。CVS控制的文件被设置为只读来避免这种情况的发生。

 比如有一个程序有一个名为example的模块,可以这样“取出”它的本地目录:$cvs checkout example

CVS会把example所有的文件和目录取出,这样你就可以编辑这些文件了。在编辑完成后,你可以这样将改变的文件写回repository中:

$cvs commit -m “description of your changes”

你也可以只写入某个文件:

$cvs commit example.c

当然,在你修改时,很可能你的同事已经将他编辑的文件写入repository中去了。这时,CVS不会让你写入,而是要求你先更新再写入。可以这样来更新:

$cvs update

有时候,你想在项目中加入或删除某个文件,你可以这样做:$cvs add extra.c

这就把extra.c加入进去。删除文件有点麻烦,你必须先在你的工作目录中把你想删除的文件删除,然后在使用下面的命令:

$cvs remove

这样虽有点麻烦,但可以防止你误删,有必要时还可以进行恢复。

当然,开源项目几乎都是放在网上的。所以CVS也可以允许你远程使用:

$export CVSROOT=:cvsserver:guest@cvs.com:/cvs
$cvs login
...
CVS password:
...
$cvs checkout example.c
...

很多大的开源项目都是使用CVS进行版本控制的,要参与开源项目,非常有必要熟悉它。关于CVS更详细的介绍见[7]第13章。另外,RCS,Subversion也是同样出色的版本控制工具,[7]中对它们也作了介绍。 gCVS是CVS的图形化前端,使用非常简单。

八.双节棍──objdump&objcopy:

    objdump是一个不错的工具,它有很多功能,反汇编,显示调试信息,显示目标文件中的符号表或段信息等等。 而objcopy可以根据你的需要复制,翻译目标文件。

九.三叉戟──autoconf+automake+libtool:

十.瑞士军刀──valgrind

参见《瑞士军刀──valgrind》一文

十一.ctags+cxref+cflow+indent

ctags

cxref

    cxref可以分析C源程序,为它输出一个交叉引用的列表文件,这个输出文件可以是普通文本格式, 也可以是HTML,Latex等格式,对阅读代码非常方便。cxref命令格式如下:

cxref filename [ ... filename] -options

不同版本的cxref选项不太相同,以我使用的1.5版为例,讲一下它的用法。其它版本请参考它自带的手册。

-Nbasename:指定输出文件的前一部分的名字,默认的是cxref。

-Rdirname:当要分析的C源程序分布在多个目录中时,用此来指定源代码树的根目录。

-Odirname:输出交叉引用文件到指定的目录。

-htmlxx:xx可以是20或者32,使用HTML2.0或3.2格式输出。
 

cflow

indent

结论

    除了上面这些之外,Linux还有很多其它优秀的工具, 像著名的vi[4]和emacs[3]文本编辑器,词法分析工具flex, 编译器的编译器yacc,排版工具texgroff等。 有的发行版还带了图形化的IDE,像QtKDevelop等。 Linux自带了不少相关文档,而且篇幅有限,这里不再全面介绍。Linux真的是一个不错的开发平台。

进一步阅读:

[1]Programming with GNU Software, Mike Loukides and Andy Oram, O'Reilly

[2]Sed & Awk, Second Edition, Dale Dougherty and Arnold Robbins, 1997, ISBN 1-56592-225-5, O'Reilly.

[3]Learning GNU Emacs, Third Edition, Debra Cameron, James Elliott and Marc Loy, ISBN 0-596-00648-9, O'Reilly

[4]Learning the vi Editor, Fifth Edition

, L.Lamb, 1990, O'Reilly

[5]Managing Projects with GNU make, Third Edition, Robert Mecklenburg, 2004, ISBN 0-596-00610-1, O'Reilly.

[6]Using LD, the GNU linker

, Steve Chamberlain.

[7]Linux in a Nutshell, 5th Edition, Ellen Siever, Stephen Figgins and Aaron Weber, 2003, ISBN 0-596-00482-6, O'Reilly & Associates.

[8]《用GDB调试程序》,CSDN文档中心

[9]GNU Automake, David MacKenzie and Tom Tromey, For version 1.3, 3 April 1998.

[10]Sed - An Introduction, Bruce Barnett and General Electric Company, 2005.

[11]Getting started with awk, HMC Computer Science Department.

[12]GCC: The Complete Reference, Arthur Griffith, McGraw-Hill

来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
推荐资讯
在CentOS下搭建Android 开发环境
在CentOS下搭建Androi
轻松搭建属于自己的Ubuntu发行版
轻松搭建属于自己的Ub
利用SUSE Studio 打造自己的个性化Linux发行版
利用SUSE Studio 打造
那些采用PHP技术的IT大企业
那些采用PHP技术的IT大
相关文章
栏目更新
栏目热门