- 浏览: 20608 次
- 性别:
- 来自: 北京
最新评论
Linux下的基本操作速查
涉及的内容:
1) 连接服务器;
2) Shell常用命令与常用参数;
3) VIM 的使用;
4) Linux更新软件;
5) GCC的常见参数;
6) GDB调试程序;
7) Makfefile的编写;
8) 代码注释,文档管理:开源Doxygen;
9) 版本控制:SVN常用命令;
连接到Linux服务器
用SecureCRT 连接Linux服务器。安装完成后从File菜单选择Quick Connect即可。使用SSH1协议,在连接时注意。
为了方便起见,建议在安装完成后作如下设置:
Options -> Global Options -> Default Session -> Edit Default Settings
Connection -> Protocol SSH1
Terminal -> Emulation-> Terminal Xterm
Terminal -> Emulation-> ANSI Color On
Terminal -> Appearance-> Current Color Schema Traditional
建议在Windows上安装虚拟机学习;
如何使用Shell
刚登录到Linux时,会显示Bash Shell提示符如下。现在你可以使用Shell命令来指挥Linux。
l ===常识===
linux用"/"而非"\"来分隔目录,/dir/.表示/dir这个目录,而/dir1/dir2/..表示/dir1这个目录。
shell总是有一个当前目录,文件的相对路径(不以"/"开头的路径)从当前目录开始计算
cat sort等处理文件内容的命令,在没有文件名时处理标准输入(键盘输入)
*和?是文件名通配符,*代表示任意数量字符,?代表单个字符。通配符由shell而非命令自身解释,因此ren *.bak *.sav这样的dos操作是不可能的。
l ===目录相关===
pwd 显示当前目录,
cd /dir1/dir2 修改当前目录为/dir1/dir2
mkdir newdir 在当前目录下建立新目录newdir
rmdir olddir 在当前目录下删除旧目录olddir
ls -l 列出当前目录下所有文件
ls -la 列出包括以"."开头的隐含文件
l ===解决乱码或者其他中文字符集问题===
export LC_ALL=
export LC_CTYPE=zh_CN.gbk
l ===文件操作===
rm foo bar etc 删除文件foo bar etc
mv foo bar 文件改名foo1改成bar
mv src1 src2 … dst 把文件移动到dst目录
cp src dst 把文件src拷贝为dst
cp src1 src2 … dst 把文件拷贝到dst目录
scp … root@host:path 把文件拷贝到主机host的目录path下
scp root@host:path dst . 把文件从主机host的目录path下拷贝到当前目录
ln -s old new 为文件old建一个符号连接new
l ===文件内容操作===
cat foo 显示文件foo的内容
head -n100 foo 查看文件foo的前100行
tail -n100 foo 查看文件foo的尾100行
diff -u foo bar 对比文件foo和bar
sort foo 按字母排序文件foo
sort -n foo 按数字排序文件foo
sort foo | uniq -c 统计文件foo中每行出现了多少次
fgrep xxx files 在文件中检索字符串xxx
l ===查看帮助===
man bash 查看bash shell的内部命令,按q退出
info coreutils 查看最常用的那些命令,按q退出
man ls 查看命令ls的帮助
man -a printf 查看printf的所有帮助,按q切换到下一个帮助。像printf这样同时出现在shell/c/perl等多个环境中的命令会有多个帮助。
man -K printf 在所有的帮助文件中搜索printf
l ===简单管理===
ps aux 列出当前所有的进程,注意PID和COMMAND两列
top 实时显示当前系统负载和最活跃的进程。
按1显示多cpu详情,按shift-m显示内存最多的进程
kill 1234 杀死PID为1234的进程
kill -9 1234 强行杀死PID为1234的进程(如果kill不行的话)
netstat --anp 列出当前所有的tcp/udp连接以及相关的进程
l ===打包===
一般用tar打包,包有.tar.gz(.tgz)以及.tar.bz2两种格式
tar cvzf a.tar.gz foo 把foo下的所有文件打包成a.tar.gz
tar xvzf a.tar.gz 把a.tar.gz解包到当前目录
tar xvjf a.tar.bz2 把a.tar.bz2解包到当前目录
如何使用VIM编辑文件
首先,正确的设置vim环境会使用更加舒服,执行以下命令设置环境:
echo -e "set nocp\nsyntax on\nset ts=4\nset sw=4\nset si\n" >> ~/.vimrc
vim foo 启动vim,并编辑文件foo
vim和Windwos的编辑器不一样,它有2种模式:命令模式和编辑模式。刚启动vim时处于命令模式,此时可以移动光标和发布命令。常用命令:
i r <insert> 进入编辑模式
<esc> 离开编辑模式
:q :q! 退出/强制退出
:w :w! 存盘/强制存盘
:wq :wq! 存盘退出/强制存盘退出
? / 向前/向后查找文本
gg G 移动到文件头/文件尾
dd 删除当前行
v V 开始选择文本/开始按行选择文本
y 将v/V选中的文本放入剪贴板
p 粘贴剪贴版的内容
J 将下一行拼到当前行尾
:%s/old/new/g 全文替换old为new
<ctrl-]> 如果有make tags的话,查找当前标识符的定义
:make 在当前目录执行make,并移动到第一个编译错误
Shell进阶
===egrep 正则表达式检索===
egrep pattern files 在文件中检索pattern,显示匹配的行
pattern 由若干atom组成,atom定义如下
. 匹配任意字符
[abc] 匹配abc三个字母任何一个
[^abc] 匹配除abc三个字母以外的任何字符
[a-h] 匹配abcdefgh中的任何一个
<atom>? ?前一个atom匹配0~1次
<atom>+ +前一个atom匹配至少1次
<atom>* *前一个atom匹配任意次
<atom1>|<atom2> 匹配两个atom中的任何一个
(<atom1><atom2>…) 用"("和")"把多个atom编成一组
\ 转义符,例如"\."精确匹配".","\t"匹配tab字符
^ 表示一行的开始
$ 表示一行的结束
其他普通字符都是atom
例子:
([a-z]\.)[a-z]+ 匹配任何纯由小写字母组成的域名
egrep常用参数
-o 显示匹配上pattern的串
-v 显示没有匹配pattern的那些行
-n 显示行号 ===输入输出重定向和管道===
一般情况下程序从键盘读取用户输入,输出到显示器。我们可以通过"<" ">" "|"操作符来改变这种行为。
ls > file 把ls的结果存到文件file,file原有的内容被销毁i
ls >> file 把ls的结果存到文件file原有内容的尾部
ls -xxx &> file 把ls的错误信息和正常输出都存到文件file
foo < file 用文件file作为命令foo的输入
ls | sort 把ls的结果做为sort的输入
ls 2>&1 | sort 把ls的结果和出错信息一起做为sort的输入
ls | tee file 利用tee命令把ls的结果存到文件file并同时显示在荧幕上。 ===后台任务===
在程序运行的过程中,按ctrl-z可以把程序切换到后台挂起,此时程序暂停执行。
启动程序的时候,在命令行的最后加"&",可以让程序直接在后台执行
grep xxx file > yyy & 在后台执行grep命令
jobs 显示当前后台有哪些程序
fg 9 把第9号后台程序切换到前台
bg 9 让第9号后台程序恢复执行(用于ctrl-z挂起的程序)
Windows和Linux互传文件
如果你使用SecureCRT,那么可以用rz命令传送文件到linux,用sz命令传送文件到Windows,但是这两个命令在处理大文件时往往有问题。
你可以安装winscp来传送文件
用yum或者apt-get补充安装rpm软件包
rpm是linux下常用的软件包封装格式。
rpm -ivh xxx.rpm 安装xxx.rpm
rpm -qa 显示系统上已经安装了哪些rpm
rpm -ql xxx 显示xxx包括哪些文件,xxx需要已经安装
rpm -e xxx 删除xxx
rpm -qf /bin/ls 查找/bin/ls属于哪个rpm包
rpm比自己下载源码要方便,但是去哪里下载rpm仍然是个问题。Linux发行版一般都附带了大量的rpm,但是并没有默认全部安装。Redhat提供了yum工具用于安装和管理系统附带的rpm软件包。使用软件和编译程序时如果发现缺少对应的工具或者库文件可以用yum补充安装。
yum search xxx 搜索名字和描述中带有xxx的软件包。
yum install xxx 安装xxx以及xxx依赖的rpm到最新版本。
例如,我们编译时发现找不到zlib相关的头文件。首先用”yum search zlib”发现有一个包叫做zlib-devel.i386,然后用”yum install zlib-devel”安装它即可。
某些系统用的是apt-get来管理rpm
apt-cache search xxx 搜索xxx
apt-get install xxx 安装xxx
参考
Bash新手指南
http://xiaowang.net/bgb-cn/
Shell设计入门
http://www.newsmth.net/bbscon.php?bid=392&id=320837
C/C++的开发 GCC/GDB/Make
在Linux下,我们用gcc来编译C/C++程序,用GDB调试程序,并用make工具来把多个源文件组织成project。如果缺乏耐心的话,请直接跳到本章的最后快速指南[Makefile模板[14页]]学习如何快速开始一个项目。
gcc
gcc – the GNU Compiler Collection。 能编译C,C++和一些其它语言编写的程序。
gcc特性
和其它编译器一样,gcc的编译过程可分为4个阶段:预处理,汇编,编译和链接。gcc的使用者可以在任何阶段停止整个编译过程,并得到该阶段的输出信息。
gcc也有优化代码和生成调试信息的功能,一般我们编译代码的时候,都会加入调试信息,这样代码出现问题的时候容易追查。但编译器优化过的代码往往不方便调试,因此,代码优化只有在正式上线的时候才会被使用。
此外gcc支持30多个警告和3个警告级别,支持交叉编译(生成非本机体系结构的二进制代码),还对标准C和C++进行了大量扩展,以提高执行效率和编程的方便性。但我们不建议使用这些扩展,因为这会影响代码的可移植性。
gcc使用
编译文件hello.c的基本方式是:
gcc hello.c --o hello
其中hello.c是输入文件,-o选项的内容为输出文件。该命令编译并链接hello.c,生成文件为hello可执行文件。如果不加-o参数,则为gcc最简单的用法:
gcc hello.c
此时gcc生成文件名为a.out的可执行文件。
编译多个源文件(如hello.c和world.c):
gcc hello.c world.c --o helloworld
实际使用中,建议先把多个源文件编译成为目标文件,再进行链接生成可执行文件:
gcc --c hello.c
gcc world.c -c
gcc hello.o world.o --o helloworld
上例中的-c选项表示只对源文件做编译处理,生成目标文件,没有加-o参数,此时编译器生成与源文件同名的.o目标文件(为别为hello.o和world.o),第三个命令把各个.o文件链接成可执行文件。
注意各参数和输入文件在命令中顺序可任意。例如第三句可以写成(不推荐)
gcc hello.o --o helloworld world.o
只对源文件进行预处理(包括头文件展开,宏展开等),可用-E参数。例如:
gcc --E --o hello.cpp hello.c
先成的文件名为hello.cpp。在unix系统下,.cpp文件表示预处理过的C/C+文件。而对于C+源文件,一般使用.cc或.cxx的扩展名。
很多时候我们还需要观察gcc产生的汇编代码,可用-S参数:
gcc --S hello.c
此时gcc生成文件名为hello.s的汇编语言文件。
调试与优化
优化的目的是改进程序的执行效率,代价是延长编译时间,也可能会增加产生的二进制文件的大小,增大调试难度。
优化参数包括-O0,-O1(等同于-O),-O2和-O3,优化程度递增。如果不加优化参数,则相当于--O0,不优化。在O0下内联函数不会被展开。一般在编译Linux内核的时候使用参数-O2,因为O3参数会展开一些非内联函数,增加二进制代码量,这对Linux内核是不能接受的。对于一般的应用,使用O3优化也是安全的。
优化参数只需在编译的时候指定,链接时不需要,例如:
gcc hello.c --c --O2
gcc --o hello hello
编译优化在理论上不会影响程序的逻辑,如果出现优化后代码运行异常,则很可能是源程序本身有bug。
gcc可通过-g参数在生成的代码里加入调试信息,以方便调试时的会话过程。和优化参数一样,-g也只需在编译的时候指定:
gcc --g --c hello.c
gcc --o hello hello.o
Unix下常用的调试工具gdb(GNU Debugger)将在下一部分介绍。用户还可通过-ggdb参数来加入更多的只能被gdb识别的调试信息。
注意,尽量避免-g和-Ox一起使用。编译优化会改变代码执行顺序被打乱以加快运行速度,但调试会变得很困难。
其它常用参数
-I::指定一个头文件路径。可用多个-I参数指定多个头文件路径。只在编译时有效。
-L::指定一个库文件路径。和-I一样可指定多个。只在链接时有效,经常和-l一起使用。
-l:指定一个库文件名。Linux下库文件的文件都是libXXX.so或libXXX.a的形式,分别是动态链接库和静态链接库。例如数学函数库文件为libm.so和libm.a,SSL的函文件为libssl.so和libssl.a。gcc在链接时-l参数只需指定库文件名的中缀部分。例如hello.c中调用了数学库的cos()函数,则:
gcc --g --c hello.c
gcc --o hello hello.o --lm
-Wall:实际上是-W参数加”all”。可让gcc打开所有的警告。在调试代码时建议使用。
-static:所有引用的库都静态链接。将会增加可执行文件的大小。
gdb
gdb介绍
gdb – the GNU Debugger。Linux下用得最多的命令行调试器。使用gdb对程序进行调试的前提是可执行文件有调试符号,在编译时需使用-g或-ggdb参数(见上一节),同时不打开编译优化。
gdb基础
启动gdb有三种常用的方法(直接启动,调试core文件和调试运行中的进程)。直接启动gdb的方法如下。
gdb test
此时会启动对程序test的调试,进入gdb交互界面。
在gdb中输入run(或r)命令表示运行程序,如果程序需要参数(main的参数),在run之后加入参数即可,例如:
(gdb) run arg1 arg2
run命令将运行到程序正常退出,或遇到断点,或被用户Ctrl-C,或出现异常,例如段错误(内存访问超出进程的地址空间),除0,总线错误,以及其它一些使程序无法运行下错误。当程序中断时(断点或Ctrl-C或异常),gdb会显示中断的代码位置。可用list(或l)命令来查看中断位置前后(共10行)代码。list命令每运行一次,查看10行代码,同时查看点也向后推进10行。list命令也可指定要查看的源文件名和位置,例如:
(gdb) list test.c:100
或当前文件就是test.c的话,等价于:
(gdb) list 100
此时gdb显示test.c的第95行到104行的代码。如果再敲入一次list,则显示从105行到114行。
程序中断是可用print(或p)命令来查看各变量的值。print命令支持所有C语言的语法。例如查看结构体指针a的域x:
(gdb) print a->x
通过where(或bt)命令可查看程序的中断位置,此会gdb会显示当前的函数调用层次。通过up命令可退回到上一级函数,以查看上一级函数中的变量情况。与up相对应的命令是down。
断点的使用
调试出问题的代码的时候,在某一点停止执行往往很管用。gdb支持几种不同的设置断点的方式,包括行号和函数名。还允许设置条件断点,即只有满足一定条件,代码才会在断点处停止执行。设置断点的命令为break(或b),例如:
(gdb) break test.c:100
(gdb) break 100
(gdb) break func1
(gdb) break 100 if (a->x==5)
其中,条件断点语句的条件部分支持C语言的所有语法。当程序在某个断点中断时,则可用上面说到的print命令来查看各变量的值,up,down命令来查看程序各级函数中的状态。注意up,down命令只会影响查看点,并不会改变程序当前执行到的位置。
让程序在断点中断之后继续运行,包括几个常用的命令。
continue(或c)命令让程序继续运行,直到遇到下一个断点;
next(或n)命令让程序执行下一条语句,如果下一条语句是函数,不进入函数内部;s
tep(或s)命令执行一下条语句,遇到函数则进入函数内部。
finish(或fin,maybe)可让程序继续运行,直到当前函数返回;
return(或ret?)命令让函数立即返回,返回后程序仍处于中断状态。return命令可加返回值,例如:
(gdb) return 20
即让当前函数立即返回,返回值为20。注意的时让函数从一个非正常的点返回,后果可能很严重,但在调试中有时也很有用。在程序中断时还可以通过call命令来调用函数,例如:
(gdb) call a=func(20)
此时gdb调用了func函数并把返回值赋予变量a。如果func函数中也有断点,程序也会在断点处被中断。
如果要删除某个断点,首先找到要删除断点的id号,方法是:
(gdb) info break
此时gdb会显示当然的所有断点位置和对应的id。用delete(或del?)命令加id号删除对应的断点;delete不加参数则删除所有的断点。另外,用disable和enable命令可让断点临时关闭和重新打开。
调试core和调试进程
对于运行中的进程,如果出现一些异常无法继续运行,会在程序的运行目录下留下一个core文件,就是我们常说的“程序core了”。core的原因是程序/进程收到了某些会让程序core的信号(准确的说是让程序流产的信号),常见的有SIGSEGV(程序出现段错误,越界访问,最常见),SIGABRT(如程序调用了abort()函数,abort本身就是流产的意思),SIGFPE(浮点异常)。当程序core了之后,会在运行目录留下一个core文件,文件名为core.XXXX,XXXX为进程号pid。如果发现怎么程序异常退出却没有core文件,系统设置的问题。用以下命令允许产生无限大的core文件:
ulimit --c unlimited
假设我们的程序名为test,产生了文件名为core.1234的core文件,通过以下命令启动gdb来调试core:
gdb test core.1234
进入gdb之后,会显示出程序异常的位置。再通过上面介绍的gdb命令查看异常时程序的状态,就可以比较方便的找到程序bug所在。注意程序core了之后已经不在运行状态,因此和运行相关的命令,如run,continue,next, step,finish,return,call,在调度core的时候无法使用。break也是没有意义的。
gdb还可以调试一个正在运行中的进程,方法是:
gdb --p <进程号>
进入gdb之后进程被gdb中断,gdb显示中断位置。此时调试的方法与普通启动gdb方式几乎无异,也可以使用运行相关命令来控制进程的推进。唯一的区别是,使用exit(或Ctrl-D)命令退出后,被调试的进程会继续运行,而不是结束。
其它常用命令
kill – 杀死当前的调试进程,对于core调试无效,因为core已经是死掉的进程。
info thread – 显示所有线程和id号。
thread <id> – 切换到某个线程。
set variable <variable name>=<expression> – 改变变量的值,对core调试无效,支持C语法。例如:
(gdb) set variable i=x+5
ptype <variable> – 显示变量的数据类型。
shell [cmd] – 执行一个shell命令。如果[cmd]为空,则进入shell。在shell中exit或Ctrl-D返回gdb。
help – 当你需要其它帮助。
Makefile
Makefile的原始形式
Make是linux最基本的工程描述工具。编写Makefile以后,简单的键入make all就能方便的编译整个项目而不用一次次手工调用gcc。先来看一下一个最基本的Makefile,它描述了如何从s1.cpp s2.cpp编译产生程序test:
objects=s1.o s2.o ##变量定义
all: test ##一般用all表示生成所有目标
test: $(objects) ##普通依赖关系
g++ $+ -o $@ ##从s1.o s2.o如何生成test
%.o:%.cpp ##从.cpp文件编译.o的依赖模板
g++ -g -O2 -c $< ##具体如何编译
clean: ##一般用clean表示清除所有目标和中间文件
rm -f test *.o ##
[kirbyzhou@sohu]$ make ##编译test
g++ -g -O2 -c s1.cpp
g++ -g -O2 -c s2.cpp
g++ s1.o s2.o -o test
[kirbyzhou@sohu]$ make ##再次编译,因为文件没有变化,所以什么都没发生
make: Nothing to be done for `all'.
[kirbyzhou@sohu]$ make clean ##清理
rm -f test *.o
Makefile的文件名必须是严格的”Makefile”,make会在当前目录下查找Makefile文件。Makefile主要由3部分组成:1.变量定义;2普通依赖关系(explicit rule);3.模板依赖关系(implicit rule)。格式分别如下:
TARGET : PREREQUISITES ##TARGETS直接依赖于PREREQUISITES
<TAB>COMMAND ##从PREREQUISITES如何产生TARGET
%.DST : %.SRC ##.dst文件依赖于.src文件,例如.o和.cpp的关系
<TAB>COMMAND ##从PREREQUISITES如何产生TARGET
在COMMAND中可以用$+表示PREREQUISITES,用$@表示TARGET,用$<表示第一个PREREQUISIT。例子参见上文。
用Automake/Autoconf自动生成makefile
涉及的文件增多以后,Makefile变得很难维护。首先是依赖关系的复杂性:s1.o不仅仅是依赖于s1.cpp,它可能还依赖于s1.h s2.h s3.h等等;其次如何生成库、动态库等等都比较复杂;各人的Makefile风格迥异很难修改;最后是缺乏统一的子目录管理机制。总之靠人工来维护Makefile是非常辛苦的。为此人们发明了一系列工具用于简化Makefile的编写,并统一Makefile的风格。
automake/autoconf是一套比较成熟的工具,它主要涉及到1个configure.ac和若干个Makefile.am
l Makefile.am一般每个子目录一个,一个最简单的Makefile.am如下,已经可以满足绝大部分的需求:
bin_PROGRAMS=demo1 demo2 ##我要编译demo1 demo2这两个程序
lib_LTLIBRARIES=libdemo3.la ##我要编译libdemo3.la这个库
demo1_SOURCES=demo1.cpp func.cpp f.h ##demo1的源码
demo2_SOURCES=demo2.cpp func.cpp f.h ##demo2的源码
libdemo3_la_SOURCES=demo3.cpp demo3.h ##libdemo3.la的源码
SUBDIRS=sub1 sub2 ##如果有子目录要build的话,列在这里
Makefile.am首先定义需要build哪些target,语法如下:
[bin|lib|libexec|…|noinst]_[SCRIPTS/PROGRAMS|LIBRARIES|LTLIBRARIES]=target1 target2 …
其中””前说明target会被安装到$(prefix)下的哪个目录,noinst表示不安装;””后是target的类型------脚本/可执行程序/静态库/动态库。注意静态库和动态库分别要满足lib*.a lib*.la的命名。
然后是每个target相关的源码,automake会自己处理源码间的关系:
<target>_SOURCES=src1.c src2.cpp header1.h header2.hpp
这里如果target是X.Y这样的形式,要写成X_Y_SOURCES=…的形式
l 在项目的topdir里还需要一个configure.ac,描述一些全项目的信息
AC_PREREQ(2.57) ##样板戏,不用管它,下同
AC_INIT(demopkg, 0.5.1) ##整套程序的名字、版本号
AM_INIT_AUTOMAKE([foreign]) ##样板戏,让autoconf按最糙的要求审核我们的程序
AC_PROG_CC ##样板戏,检查C编译器
AC_PROG_CXX ##样板戏,检查C++编译器
AC_PROG_LIBTOOL ##样板戏,检查用于生成动态库的libtool工具
AC_CONFIG_FILES([
Makefile demo/Makefile ##在[]里列出需要自动生成的Makefile
])
AC_OUTPUT ##最后一行样板戏
l 最后执行autoreconf --is && ./configure就可以开始make了。
l 常用的make目标有all(缺省target,build项目),clean(清理),install(安装),uninstall(反安装),check(测试),dist(源码打包),distcheck(检查打包后的源码能否正常工作)。
快速指南:
=== 编写Makefile ===
编写Makefile 参见[Makefile模板[14页]]
make 用makefile编译整个工程
make clean 清除make的结果和中间文件
=== GCC ===
gcc a.c 编译纯C程序a.c为可执行程序a.out
g++ -g s1.cc s2.cpp -o dest 把源文件s1.cc s2.cpp编译成可执行程序dest
g++ -g -O0 src.cpp -o dest 禁止优化的编译,这样方便调试
g++ -I/opt/include … 附加的include目录
g++ -L/opt/lib -lACE … 附加的lib目录,并链接库libACE.so
==== GDB ===
gdb test 调试程序test
gdb test 12345 调试进程PID为12345的程序test
gdb test core.123 调试程序test崩溃后留下的现场core.123
ulimit --c unlimited 使程序崩溃后有机会留下现场
==== GDB 命令===
r arg1 arg2 … 运行程序,arg1 arg2 …是传给程序的参数
l 列出代码
l a.cpp:100 列出a.cpp第一百行附近的代码
b 100 在第100行设置断点
<ctrl-c> 中断程序
p x 打印变量x的值
set variable x = y +2 改变变量的值
n / s / c 单步/深入单步/继续
bt 察看函数调用层次
up / down 转到上一级/下一级函数
kill 杀死当前的调试进程
info thread 显示所有线程和id号
thread 3 切换到线程3
参考
GCC常见编译选项
http://dev.csdn.net/author/ganxingming/d4fabf69cc48471fbcbc7b9be2a908dc.html
GDB手册 http://www.newsmth.net/bbs0an.php?path=%2Fgroups%2Fcomp.faq%2FLinuxDev%2Fdevelop%2Fgdb_linuxdev
GNU make指南
http://www.newsmth.net/bbs0an.php?path=%2Fgroups%2Fcomp.faq%2FLinuxDev%2Fdevelop%2Fmakefile
使用automake和autoconf管理项目的上手指南
http://blog.donews.com/idlecat511/archive/2006/01/17/698470.aspx
http://cvs.so.sohu.com:2080/svn/arch/trunk/Projects/MakefileDemo/
文档工具
Doxygen
Doxygen是开源(GPL)的文档工具,可以自动根据类之间的调用关系生成UML图,也支持类似javadoc的从注释中提取文档的功能。
Doxygen可以直接生成html, LaTeX, rtf等格式的文档。
Doxygen的项目主页在http://www.doxygen.org/。生成图片需要Graphviz(http://www.graphviz.org/)程序的支持。
程序中的注释块
Doxygen支持的注释格式如下:
l /*或者/!开头:
/**
* @brief put result back to output module
*
* @param seq the seq of the request
* @param result the result
*
* @return 0 on successful, otherwise an error number
*/
virtual int put_result(const seq_t& seq, const result_t& result) = 0;
l ///或者//!开头:
/// the superclass for output module
class Base_Output {
l 还可以用增加一个<来为注释前面的代码写文档(默认为注释后面的),这种情况在定义enum的时候很有用:
/**
* @brief enumerate for supported products
*/
关于更多的程序中的注释块的说明可以参考官方文档
常用命令
命令以@或者\开头,用来指定后面文字的形势,比如@brief, \return等。
常用命令如下:
l brief: 简短说明
l details: 详细说明
l param: 参数说明,后面跟的第一个单词为参数名
l return: 返回值说明
l class: 类名,可以省略
l file: 文件名,可以省略
l author: 作者
完整的命令列表请见官方文档(http://www.stack.nl/~dimitri/doxygen/commands.html)
配置文件
与make类似,doxygen的默认配置文件为当前目录下的Doxyfile文件,http://www.sohu-rd.com/images/f/fe/Doxyfile.doc是一个example,注意要去掉.doc扩展名
在这个例子里面,一般来说你需要更改的东西有:
l PROJECT_NAME: 项目的名字
l PROJECT_NUMBER: 项目的版本号
l TAB_SIZE: 制表符的宽度
l INPUT: 源代码的路径
l HTML_OUTPUT: 输出的html文档的路径
l LATEX_OUTPUT: 输出的LaTeX文档的路径
l RTF_OUTPUT: 输出的rtf文档的路径
准备好配置文件后,在配置文件(Doxyfile)所在目录执行doxygen就可以生成文档。按照这个例子,doxygen会对Code子目录下面的所有代码生成文档,其中html文档生成到html子目录下,LaTeX文档生成到latex子目录下,rtf文档生成到rtf子目录下。
其它
l 如果使用vim作为编辑器,可以安装DoxygenToolkit这个插件,这个可以对你已经写好的函数头、类头等自动生成doxygen注释框架。
l 一个doxygen注释的源代码的例子在http://www.sohu-rd.com/images/7/7e/Core_Manager.h.doc,注意要去掉.doc扩展名
版本管理工具
SVN
SVN是CVS的进化版本,最主要的区别是SVN为整个Repository维护一个统一的版本号以避免混乱。建议在Windows下用TortotiseSVN。
svn中的trunk目录对应CVS的HEAD/MAIN分支,SVN中没有传统CVS的branch/tag,而是通过在branches/tags目录下建立原始文件的拷贝来模拟:
cvs tag branch_name : svn copy . branch_path
cvs up -r tag_name : svn switch tag_path
WorkCopy的概念和CVS类似,注意,一般不checkout整个respository,而是check out trunk或某个分支
svn命令行简明参考手册
l Prestart
l 创建仓库(Repository)
svnadmin create /path/to/repository
svnadmin是有用的subversion系统管理命令,使用svnadmin help查看在线帮助
信息。subversion的手册推荐在项目在repository下分别建立branches/ tags/trunk/三个目录,分别存放分支/标签/主分支
l 检出(checkout)项目
svn checkout file:///.../trunk/ project
svn checkout http://host/.../trunk/ project
l 列出仓库中的项目(list)
svn list -verbose file:///.../tags/
svn list -verbose http://.../trunk/
l 状态查询(status)
svn status
给出新文件,已经改变的文件和被删除的文件列表
l 添加文件或目录(add)
svn add
l 删除文件或目录(delete)
svn delete
svn delete http://host/svn_dir/repository/project_dir 这条命令可以用来删除错误的import的某些项目!!
l 回滚workcopy的修改
svn revert file1 file2
svn revert -R .
l 提交(commit)
svn commit http://host/svn_dir/repository/project_dir
l 更新(update)
svn update
更新仓库中的文件到本地。
l 删除重命名和移动(update)
svn delete (del, remove, rm)
svn move (mv, rename, ren)
l 使用COPY命令管理Tag和 Branch
svn copy http://host/repos/project/trunk http://host/repos/project/tags/1.0.0
用于创建某个特定版本的快照(snapshot);
svn list http://host/repos/project/tags/1.0.0
查看某个版本的内容
svn switch branch_url
把workcopy切换到某个分支
l 版本合并
svn merge -r N:M branch .
把branch上版本N和M之间的修改合并到当前目录
branch可以是url或者本地目录
svn merge tag branch .
把tag和branch之间的修改合并到当前目录
svn log -qv --stop-on-copy http://svnhost/svn/repo/branches/br1
查看某个branch的修改日志从而决定从哪个版本开始merge
l 快速查看当前workcopy的版本号(svnversion)
svnversion
给出新文件,已经改变的文件和被删除的文件列表;
参考
CVS中文手册
http://man.chinaunix.net/develop/cvsdoc_zh/
使用Subversion进行版本控制
http://svnbook.red-bean.com/index.zh.html
涉及的内容:
1) 连接服务器;
2) Shell常用命令与常用参数;
3) VIM 的使用;
4) Linux更新软件;
5) GCC的常见参数;
6) GDB调试程序;
7) Makfefile的编写;
8) 代码注释,文档管理:开源Doxygen;
9) 版本控制:SVN常用命令;
连接到Linux服务器
用SecureCRT 连接Linux服务器。安装完成后从File菜单选择Quick Connect即可。使用SSH1协议,在连接时注意。
为了方便起见,建议在安装完成后作如下设置:
Options -> Global Options -> Default Session -> Edit Default Settings
Connection -> Protocol SSH1
Terminal -> Emulation-> Terminal Xterm
Terminal -> Emulation-> ANSI Color On
Terminal -> Appearance-> Current Color Schema Traditional
建议在Windows上安装虚拟机学习;
如何使用Shell
刚登录到Linux时,会显示Bash Shell提示符如下。现在你可以使用Shell命令来指挥Linux。
l ===常识===
linux用"/"而非"\"来分隔目录,/dir/.表示/dir这个目录,而/dir1/dir2/..表示/dir1这个目录。
shell总是有一个当前目录,文件的相对路径(不以"/"开头的路径)从当前目录开始计算
cat sort等处理文件内容的命令,在没有文件名时处理标准输入(键盘输入)
*和?是文件名通配符,*代表示任意数量字符,?代表单个字符。通配符由shell而非命令自身解释,因此ren *.bak *.sav这样的dos操作是不可能的。
l ===目录相关===
pwd 显示当前目录,
cd /dir1/dir2 修改当前目录为/dir1/dir2
mkdir newdir 在当前目录下建立新目录newdir
rmdir olddir 在当前目录下删除旧目录olddir
ls -l 列出当前目录下所有文件
ls -la 列出包括以"."开头的隐含文件
l ===解决乱码或者其他中文字符集问题===
export LC_ALL=
export LC_CTYPE=zh_CN.gbk
l ===文件操作===
rm foo bar etc 删除文件foo bar etc
mv foo bar 文件改名foo1改成bar
mv src1 src2 … dst 把文件移动到dst目录
cp src dst 把文件src拷贝为dst
cp src1 src2 … dst 把文件拷贝到dst目录
scp … root@host:path 把文件拷贝到主机host的目录path下
scp root@host:path dst . 把文件从主机host的目录path下拷贝到当前目录
ln -s old new 为文件old建一个符号连接new
l ===文件内容操作===
cat foo 显示文件foo的内容
head -n100 foo 查看文件foo的前100行
tail -n100 foo 查看文件foo的尾100行
diff -u foo bar 对比文件foo和bar
sort foo 按字母排序文件foo
sort -n foo 按数字排序文件foo
sort foo | uniq -c 统计文件foo中每行出现了多少次
fgrep xxx files 在文件中检索字符串xxx
l ===查看帮助===
man bash 查看bash shell的内部命令,按q退出
info coreutils 查看最常用的那些命令,按q退出
man ls 查看命令ls的帮助
man -a printf 查看printf的所有帮助,按q切换到下一个帮助。像printf这样同时出现在shell/c/perl等多个环境中的命令会有多个帮助。
man -K printf 在所有的帮助文件中搜索printf
l ===简单管理===
ps aux 列出当前所有的进程,注意PID和COMMAND两列
top 实时显示当前系统负载和最活跃的进程。
按1显示多cpu详情,按shift-m显示内存最多的进程
kill 1234 杀死PID为1234的进程
kill -9 1234 强行杀死PID为1234的进程(如果kill不行的话)
netstat --anp 列出当前所有的tcp/udp连接以及相关的进程
l ===打包===
一般用tar打包,包有.tar.gz(.tgz)以及.tar.bz2两种格式
tar cvzf a.tar.gz foo 把foo下的所有文件打包成a.tar.gz
tar xvzf a.tar.gz 把a.tar.gz解包到当前目录
tar xvjf a.tar.bz2 把a.tar.bz2解包到当前目录
如何使用VIM编辑文件
首先,正确的设置vim环境会使用更加舒服,执行以下命令设置环境:
echo -e "set nocp\nsyntax on\nset ts=4\nset sw=4\nset si\n" >> ~/.vimrc
vim foo 启动vim,并编辑文件foo
vim和Windwos的编辑器不一样,它有2种模式:命令模式和编辑模式。刚启动vim时处于命令模式,此时可以移动光标和发布命令。常用命令:
i r <insert> 进入编辑模式
<esc> 离开编辑模式
:q :q! 退出/强制退出
:w :w! 存盘/强制存盘
:wq :wq! 存盘退出/强制存盘退出
? / 向前/向后查找文本
gg G 移动到文件头/文件尾
dd 删除当前行
v V 开始选择文本/开始按行选择文本
y 将v/V选中的文本放入剪贴板
p 粘贴剪贴版的内容
J 将下一行拼到当前行尾
:%s/old/new/g 全文替换old为new
<ctrl-]> 如果有make tags的话,查找当前标识符的定义
:make 在当前目录执行make,并移动到第一个编译错误
Shell进阶
===egrep 正则表达式检索===
egrep pattern files 在文件中检索pattern,显示匹配的行
pattern 由若干atom组成,atom定义如下
. 匹配任意字符
[abc] 匹配abc三个字母任何一个
[^abc] 匹配除abc三个字母以外的任何字符
[a-h] 匹配abcdefgh中的任何一个
<atom>? ?前一个atom匹配0~1次
<atom>+ +前一个atom匹配至少1次
<atom>* *前一个atom匹配任意次
<atom1>|<atom2> 匹配两个atom中的任何一个
(<atom1><atom2>…) 用"("和")"把多个atom编成一组
\ 转义符,例如"\."精确匹配".","\t"匹配tab字符
^ 表示一行的开始
$ 表示一行的结束
其他普通字符都是atom
例子:
([a-z]\.)[a-z]+ 匹配任何纯由小写字母组成的域名
egrep常用参数
-o 显示匹配上pattern的串
-v 显示没有匹配pattern的那些行
-n 显示行号 ===输入输出重定向和管道===
一般情况下程序从键盘读取用户输入,输出到显示器。我们可以通过"<" ">" "|"操作符来改变这种行为。
ls > file 把ls的结果存到文件file,file原有的内容被销毁i
ls >> file 把ls的结果存到文件file原有内容的尾部
ls -xxx &> file 把ls的错误信息和正常输出都存到文件file
foo < file 用文件file作为命令foo的输入
ls | sort 把ls的结果做为sort的输入
ls 2>&1 | sort 把ls的结果和出错信息一起做为sort的输入
ls | tee file 利用tee命令把ls的结果存到文件file并同时显示在荧幕上。 ===后台任务===
在程序运行的过程中,按ctrl-z可以把程序切换到后台挂起,此时程序暂停执行。
启动程序的时候,在命令行的最后加"&",可以让程序直接在后台执行
grep xxx file > yyy & 在后台执行grep命令
jobs 显示当前后台有哪些程序
fg 9 把第9号后台程序切换到前台
bg 9 让第9号后台程序恢复执行(用于ctrl-z挂起的程序)
Windows和Linux互传文件
如果你使用SecureCRT,那么可以用rz命令传送文件到linux,用sz命令传送文件到Windows,但是这两个命令在处理大文件时往往有问题。
你可以安装winscp来传送文件
用yum或者apt-get补充安装rpm软件包
rpm是linux下常用的软件包封装格式。
rpm -ivh xxx.rpm 安装xxx.rpm
rpm -qa 显示系统上已经安装了哪些rpm
rpm -ql xxx 显示xxx包括哪些文件,xxx需要已经安装
rpm -e xxx 删除xxx
rpm -qf /bin/ls 查找/bin/ls属于哪个rpm包
rpm比自己下载源码要方便,但是去哪里下载rpm仍然是个问题。Linux发行版一般都附带了大量的rpm,但是并没有默认全部安装。Redhat提供了yum工具用于安装和管理系统附带的rpm软件包。使用软件和编译程序时如果发现缺少对应的工具或者库文件可以用yum补充安装。
yum search xxx 搜索名字和描述中带有xxx的软件包。
yum install xxx 安装xxx以及xxx依赖的rpm到最新版本。
例如,我们编译时发现找不到zlib相关的头文件。首先用”yum search zlib”发现有一个包叫做zlib-devel.i386,然后用”yum install zlib-devel”安装它即可。
某些系统用的是apt-get来管理rpm
apt-cache search xxx 搜索xxx
apt-get install xxx 安装xxx
参考
Bash新手指南
http://xiaowang.net/bgb-cn/
Shell设计入门
http://www.newsmth.net/bbscon.php?bid=392&id=320837
C/C++的开发 GCC/GDB/Make
在Linux下,我们用gcc来编译C/C++程序,用GDB调试程序,并用make工具来把多个源文件组织成project。如果缺乏耐心的话,请直接跳到本章的最后快速指南[Makefile模板[14页]]学习如何快速开始一个项目。
gcc
gcc – the GNU Compiler Collection。 能编译C,C++和一些其它语言编写的程序。
gcc特性
和其它编译器一样,gcc的编译过程可分为4个阶段:预处理,汇编,编译和链接。gcc的使用者可以在任何阶段停止整个编译过程,并得到该阶段的输出信息。
gcc也有优化代码和生成调试信息的功能,一般我们编译代码的时候,都会加入调试信息,这样代码出现问题的时候容易追查。但编译器优化过的代码往往不方便调试,因此,代码优化只有在正式上线的时候才会被使用。
此外gcc支持30多个警告和3个警告级别,支持交叉编译(生成非本机体系结构的二进制代码),还对标准C和C++进行了大量扩展,以提高执行效率和编程的方便性。但我们不建议使用这些扩展,因为这会影响代码的可移植性。
gcc使用
编译文件hello.c的基本方式是:
gcc hello.c --o hello
其中hello.c是输入文件,-o选项的内容为输出文件。该命令编译并链接hello.c,生成文件为hello可执行文件。如果不加-o参数,则为gcc最简单的用法:
gcc hello.c
此时gcc生成文件名为a.out的可执行文件。
编译多个源文件(如hello.c和world.c):
gcc hello.c world.c --o helloworld
实际使用中,建议先把多个源文件编译成为目标文件,再进行链接生成可执行文件:
gcc --c hello.c
gcc world.c -c
gcc hello.o world.o --o helloworld
上例中的-c选项表示只对源文件做编译处理,生成目标文件,没有加-o参数,此时编译器生成与源文件同名的.o目标文件(为别为hello.o和world.o),第三个命令把各个.o文件链接成可执行文件。
注意各参数和输入文件在命令中顺序可任意。例如第三句可以写成(不推荐)
gcc hello.o --o helloworld world.o
只对源文件进行预处理(包括头文件展开,宏展开等),可用-E参数。例如:
gcc --E --o hello.cpp hello.c
先成的文件名为hello.cpp。在unix系统下,.cpp文件表示预处理过的C/C+文件。而对于C+源文件,一般使用.cc或.cxx的扩展名。
很多时候我们还需要观察gcc产生的汇编代码,可用-S参数:
gcc --S hello.c
此时gcc生成文件名为hello.s的汇编语言文件。
调试与优化
优化的目的是改进程序的执行效率,代价是延长编译时间,也可能会增加产生的二进制文件的大小,增大调试难度。
优化参数包括-O0,-O1(等同于-O),-O2和-O3,优化程度递增。如果不加优化参数,则相当于--O0,不优化。在O0下内联函数不会被展开。一般在编译Linux内核的时候使用参数-O2,因为O3参数会展开一些非内联函数,增加二进制代码量,这对Linux内核是不能接受的。对于一般的应用,使用O3优化也是安全的。
优化参数只需在编译的时候指定,链接时不需要,例如:
gcc hello.c --c --O2
gcc --o hello hello
编译优化在理论上不会影响程序的逻辑,如果出现优化后代码运行异常,则很可能是源程序本身有bug。
gcc可通过-g参数在生成的代码里加入调试信息,以方便调试时的会话过程。和优化参数一样,-g也只需在编译的时候指定:
gcc --g --c hello.c
gcc --o hello hello.o
Unix下常用的调试工具gdb(GNU Debugger)将在下一部分介绍。用户还可通过-ggdb参数来加入更多的只能被gdb识别的调试信息。
注意,尽量避免-g和-Ox一起使用。编译优化会改变代码执行顺序被打乱以加快运行速度,但调试会变得很困难。
其它常用参数
-I::指定一个头文件路径。可用多个-I参数指定多个头文件路径。只在编译时有效。
-L::指定一个库文件路径。和-I一样可指定多个。只在链接时有效,经常和-l一起使用。
-l:指定一个库文件名。Linux下库文件的文件都是libXXX.so或libXXX.a的形式,分别是动态链接库和静态链接库。例如数学函数库文件为libm.so和libm.a,SSL的函文件为libssl.so和libssl.a。gcc在链接时-l参数只需指定库文件名的中缀部分。例如hello.c中调用了数学库的cos()函数,则:
gcc --g --c hello.c
gcc --o hello hello.o --lm
-Wall:实际上是-W参数加”all”。可让gcc打开所有的警告。在调试代码时建议使用。
-static:所有引用的库都静态链接。将会增加可执行文件的大小。
gdb
gdb介绍
gdb – the GNU Debugger。Linux下用得最多的命令行调试器。使用gdb对程序进行调试的前提是可执行文件有调试符号,在编译时需使用-g或-ggdb参数(见上一节),同时不打开编译优化。
gdb基础
启动gdb有三种常用的方法(直接启动,调试core文件和调试运行中的进程)。直接启动gdb的方法如下。
gdb test
此时会启动对程序test的调试,进入gdb交互界面。
在gdb中输入run(或r)命令表示运行程序,如果程序需要参数(main的参数),在run之后加入参数即可,例如:
(gdb) run arg1 arg2
run命令将运行到程序正常退出,或遇到断点,或被用户Ctrl-C,或出现异常,例如段错误(内存访问超出进程的地址空间),除0,总线错误,以及其它一些使程序无法运行下错误。当程序中断时(断点或Ctrl-C或异常),gdb会显示中断的代码位置。可用list(或l)命令来查看中断位置前后(共10行)代码。list命令每运行一次,查看10行代码,同时查看点也向后推进10行。list命令也可指定要查看的源文件名和位置,例如:
(gdb) list test.c:100
或当前文件就是test.c的话,等价于:
(gdb) list 100
此时gdb显示test.c的第95行到104行的代码。如果再敲入一次list,则显示从105行到114行。
程序中断是可用print(或p)命令来查看各变量的值。print命令支持所有C语言的语法。例如查看结构体指针a的域x:
(gdb) print a->x
通过where(或bt)命令可查看程序的中断位置,此会gdb会显示当前的函数调用层次。通过up命令可退回到上一级函数,以查看上一级函数中的变量情况。与up相对应的命令是down。
断点的使用
调试出问题的代码的时候,在某一点停止执行往往很管用。gdb支持几种不同的设置断点的方式,包括行号和函数名。还允许设置条件断点,即只有满足一定条件,代码才会在断点处停止执行。设置断点的命令为break(或b),例如:
(gdb) break test.c:100
(gdb) break 100
(gdb) break func1
(gdb) break 100 if (a->x==5)
其中,条件断点语句的条件部分支持C语言的所有语法。当程序在某个断点中断时,则可用上面说到的print命令来查看各变量的值,up,down命令来查看程序各级函数中的状态。注意up,down命令只会影响查看点,并不会改变程序当前执行到的位置。
让程序在断点中断之后继续运行,包括几个常用的命令。
continue(或c)命令让程序继续运行,直到遇到下一个断点;
next(或n)命令让程序执行下一条语句,如果下一条语句是函数,不进入函数内部;s
tep(或s)命令执行一下条语句,遇到函数则进入函数内部。
finish(或fin,maybe)可让程序继续运行,直到当前函数返回;
return(或ret?)命令让函数立即返回,返回后程序仍处于中断状态。return命令可加返回值,例如:
(gdb) return 20
即让当前函数立即返回,返回值为20。注意的时让函数从一个非正常的点返回,后果可能很严重,但在调试中有时也很有用。在程序中断时还可以通过call命令来调用函数,例如:
(gdb) call a=func(20)
此时gdb调用了func函数并把返回值赋予变量a。如果func函数中也有断点,程序也会在断点处被中断。
如果要删除某个断点,首先找到要删除断点的id号,方法是:
(gdb) info break
此时gdb会显示当然的所有断点位置和对应的id。用delete(或del?)命令加id号删除对应的断点;delete不加参数则删除所有的断点。另外,用disable和enable命令可让断点临时关闭和重新打开。
调试core和调试进程
对于运行中的进程,如果出现一些异常无法继续运行,会在程序的运行目录下留下一个core文件,就是我们常说的“程序core了”。core的原因是程序/进程收到了某些会让程序core的信号(准确的说是让程序流产的信号),常见的有SIGSEGV(程序出现段错误,越界访问,最常见),SIGABRT(如程序调用了abort()函数,abort本身就是流产的意思),SIGFPE(浮点异常)。当程序core了之后,会在运行目录留下一个core文件,文件名为core.XXXX,XXXX为进程号pid。如果发现怎么程序异常退出却没有core文件,系统设置的问题。用以下命令允许产生无限大的core文件:
ulimit --c unlimited
假设我们的程序名为test,产生了文件名为core.1234的core文件,通过以下命令启动gdb来调试core:
gdb test core.1234
进入gdb之后,会显示出程序异常的位置。再通过上面介绍的gdb命令查看异常时程序的状态,就可以比较方便的找到程序bug所在。注意程序core了之后已经不在运行状态,因此和运行相关的命令,如run,continue,next, step,finish,return,call,在调度core的时候无法使用。break也是没有意义的。
gdb还可以调试一个正在运行中的进程,方法是:
gdb --p <进程号>
进入gdb之后进程被gdb中断,gdb显示中断位置。此时调试的方法与普通启动gdb方式几乎无异,也可以使用运行相关命令来控制进程的推进。唯一的区别是,使用exit(或Ctrl-D)命令退出后,被调试的进程会继续运行,而不是结束。
其它常用命令
kill – 杀死当前的调试进程,对于core调试无效,因为core已经是死掉的进程。
info thread – 显示所有线程和id号。
thread <id> – 切换到某个线程。
set variable <variable name>=<expression> – 改变变量的值,对core调试无效,支持C语法。例如:
(gdb) set variable i=x+5
ptype <variable> – 显示变量的数据类型。
shell [cmd] – 执行一个shell命令。如果[cmd]为空,则进入shell。在shell中exit或Ctrl-D返回gdb。
help – 当你需要其它帮助。
Makefile
Makefile的原始形式
Make是linux最基本的工程描述工具。编写Makefile以后,简单的键入make all就能方便的编译整个项目而不用一次次手工调用gcc。先来看一下一个最基本的Makefile,它描述了如何从s1.cpp s2.cpp编译产生程序test:
objects=s1.o s2.o ##变量定义
all: test ##一般用all表示生成所有目标
test: $(objects) ##普通依赖关系
g++ $+ -o $@ ##从s1.o s2.o如何生成test
%.o:%.cpp ##从.cpp文件编译.o的依赖模板
g++ -g -O2 -c $< ##具体如何编译
clean: ##一般用clean表示清除所有目标和中间文件
rm -f test *.o ##
[kirbyzhou@sohu]$ make ##编译test
g++ -g -O2 -c s1.cpp
g++ -g -O2 -c s2.cpp
g++ s1.o s2.o -o test
[kirbyzhou@sohu]$ make ##再次编译,因为文件没有变化,所以什么都没发生
make: Nothing to be done for `all'.
[kirbyzhou@sohu]$ make clean ##清理
rm -f test *.o
Makefile的文件名必须是严格的”Makefile”,make会在当前目录下查找Makefile文件。Makefile主要由3部分组成:1.变量定义;2普通依赖关系(explicit rule);3.模板依赖关系(implicit rule)。格式分别如下:
TARGET : PREREQUISITES ##TARGETS直接依赖于PREREQUISITES
<TAB>COMMAND ##从PREREQUISITES如何产生TARGET
%.DST : %.SRC ##.dst文件依赖于.src文件,例如.o和.cpp的关系
<TAB>COMMAND ##从PREREQUISITES如何产生TARGET
在COMMAND中可以用$+表示PREREQUISITES,用$@表示TARGET,用$<表示第一个PREREQUISIT。例子参见上文。
用Automake/Autoconf自动生成makefile
涉及的文件增多以后,Makefile变得很难维护。首先是依赖关系的复杂性:s1.o不仅仅是依赖于s1.cpp,它可能还依赖于s1.h s2.h s3.h等等;其次如何生成库、动态库等等都比较复杂;各人的Makefile风格迥异很难修改;最后是缺乏统一的子目录管理机制。总之靠人工来维护Makefile是非常辛苦的。为此人们发明了一系列工具用于简化Makefile的编写,并统一Makefile的风格。
automake/autoconf是一套比较成熟的工具,它主要涉及到1个configure.ac和若干个Makefile.am
l Makefile.am一般每个子目录一个,一个最简单的Makefile.am如下,已经可以满足绝大部分的需求:
bin_PROGRAMS=demo1 demo2 ##我要编译demo1 demo2这两个程序
lib_LTLIBRARIES=libdemo3.la ##我要编译libdemo3.la这个库
demo1_SOURCES=demo1.cpp func.cpp f.h ##demo1的源码
demo2_SOURCES=demo2.cpp func.cpp f.h ##demo2的源码
libdemo3_la_SOURCES=demo3.cpp demo3.h ##libdemo3.la的源码
SUBDIRS=sub1 sub2 ##如果有子目录要build的话,列在这里
Makefile.am首先定义需要build哪些target,语法如下:
[bin|lib|libexec|…|noinst]_[SCRIPTS/PROGRAMS|LIBRARIES|LTLIBRARIES]=target1 target2 …
其中””前说明target会被安装到$(prefix)下的哪个目录,noinst表示不安装;””后是target的类型------脚本/可执行程序/静态库/动态库。注意静态库和动态库分别要满足lib*.a lib*.la的命名。
然后是每个target相关的源码,automake会自己处理源码间的关系:
<target>_SOURCES=src1.c src2.cpp header1.h header2.hpp
这里如果target是X.Y这样的形式,要写成X_Y_SOURCES=…的形式
l 在项目的topdir里还需要一个configure.ac,描述一些全项目的信息
AC_PREREQ(2.57) ##样板戏,不用管它,下同
AC_INIT(demopkg, 0.5.1) ##整套程序的名字、版本号
AM_INIT_AUTOMAKE([foreign]) ##样板戏,让autoconf按最糙的要求审核我们的程序
AC_PROG_CC ##样板戏,检查C编译器
AC_PROG_CXX ##样板戏,检查C++编译器
AC_PROG_LIBTOOL ##样板戏,检查用于生成动态库的libtool工具
AC_CONFIG_FILES([
Makefile demo/Makefile ##在[]里列出需要自动生成的Makefile
])
AC_OUTPUT ##最后一行样板戏
l 最后执行autoreconf --is && ./configure就可以开始make了。
l 常用的make目标有all(缺省target,build项目),clean(清理),install(安装),uninstall(反安装),check(测试),dist(源码打包),distcheck(检查打包后的源码能否正常工作)。
快速指南:
=== 编写Makefile ===
编写Makefile 参见[Makefile模板[14页]]
make 用makefile编译整个工程
make clean 清除make的结果和中间文件
=== GCC ===
gcc a.c 编译纯C程序a.c为可执行程序a.out
g++ -g s1.cc s2.cpp -o dest 把源文件s1.cc s2.cpp编译成可执行程序dest
g++ -g -O0 src.cpp -o dest 禁止优化的编译,这样方便调试
g++ -I/opt/include … 附加的include目录
g++ -L/opt/lib -lACE … 附加的lib目录,并链接库libACE.so
==== GDB ===
gdb test 调试程序test
gdb test 12345 调试进程PID为12345的程序test
gdb test core.123 调试程序test崩溃后留下的现场core.123
ulimit --c unlimited 使程序崩溃后有机会留下现场
==== GDB 命令===
r arg1 arg2 … 运行程序,arg1 arg2 …是传给程序的参数
l 列出代码
l a.cpp:100 列出a.cpp第一百行附近的代码
b 100 在第100行设置断点
<ctrl-c> 中断程序
p x 打印变量x的值
set variable x = y +2 改变变量的值
n / s / c 单步/深入单步/继续
bt 察看函数调用层次
up / down 转到上一级/下一级函数
kill 杀死当前的调试进程
info thread 显示所有线程和id号
thread 3 切换到线程3
参考
GCC常见编译选项
http://dev.csdn.net/author/ganxingming/d4fabf69cc48471fbcbc7b9be2a908dc.html
GDB手册 http://www.newsmth.net/bbs0an.php?path=%2Fgroups%2Fcomp.faq%2FLinuxDev%2Fdevelop%2Fgdb_linuxdev
GNU make指南
http://www.newsmth.net/bbs0an.php?path=%2Fgroups%2Fcomp.faq%2FLinuxDev%2Fdevelop%2Fmakefile
使用automake和autoconf管理项目的上手指南
http://blog.donews.com/idlecat511/archive/2006/01/17/698470.aspx
http://cvs.so.sohu.com:2080/svn/arch/trunk/Projects/MakefileDemo/
文档工具
Doxygen
Doxygen是开源(GPL)的文档工具,可以自动根据类之间的调用关系生成UML图,也支持类似javadoc的从注释中提取文档的功能。
Doxygen可以直接生成html, LaTeX, rtf等格式的文档。
Doxygen的项目主页在http://www.doxygen.org/。生成图片需要Graphviz(http://www.graphviz.org/)程序的支持。
程序中的注释块
Doxygen支持的注释格式如下:
l /*或者/!开头:
/**
* @brief put result back to output module
*
* @param seq the seq of the request
* @param result the result
*
* @return 0 on successful, otherwise an error number
*/
virtual int put_result(const seq_t& seq, const result_t& result) = 0;
l ///或者//!开头:
/// the superclass for output module
class Base_Output {
l 还可以用增加一个<来为注释前面的代码写文档(默认为注释后面的),这种情况在定义enum的时候很有用:
/**
* @brief enumerate for supported products
*/
关于更多的程序中的注释块的说明可以参考官方文档
常用命令
命令以@或者\开头,用来指定后面文字的形势,比如@brief, \return等。
常用命令如下:
l brief: 简短说明
l details: 详细说明
l param: 参数说明,后面跟的第一个单词为参数名
l return: 返回值说明
l class: 类名,可以省略
l file: 文件名,可以省略
l author: 作者
完整的命令列表请见官方文档(http://www.stack.nl/~dimitri/doxygen/commands.html)
配置文件
与make类似,doxygen的默认配置文件为当前目录下的Doxyfile文件,http://www.sohu-rd.com/images/f/fe/Doxyfile.doc是一个example,注意要去掉.doc扩展名
在这个例子里面,一般来说你需要更改的东西有:
l PROJECT_NAME: 项目的名字
l PROJECT_NUMBER: 项目的版本号
l TAB_SIZE: 制表符的宽度
l INPUT: 源代码的路径
l HTML_OUTPUT: 输出的html文档的路径
l LATEX_OUTPUT: 输出的LaTeX文档的路径
l RTF_OUTPUT: 输出的rtf文档的路径
准备好配置文件后,在配置文件(Doxyfile)所在目录执行doxygen就可以生成文档。按照这个例子,doxygen会对Code子目录下面的所有代码生成文档,其中html文档生成到html子目录下,LaTeX文档生成到latex子目录下,rtf文档生成到rtf子目录下。
其它
l 如果使用vim作为编辑器,可以安装DoxygenToolkit这个插件,这个可以对你已经写好的函数头、类头等自动生成doxygen注释框架。
l 一个doxygen注释的源代码的例子在http://www.sohu-rd.com/images/7/7e/Core_Manager.h.doc,注意要去掉.doc扩展名
版本管理工具
SVN
SVN是CVS的进化版本,最主要的区别是SVN为整个Repository维护一个统一的版本号以避免混乱。建议在Windows下用TortotiseSVN。
svn中的trunk目录对应CVS的HEAD/MAIN分支,SVN中没有传统CVS的branch/tag,而是通过在branches/tags目录下建立原始文件的拷贝来模拟:
cvs tag branch_name : svn copy . branch_path
cvs up -r tag_name : svn switch tag_path
WorkCopy的概念和CVS类似,注意,一般不checkout整个respository,而是check out trunk或某个分支
svn命令行简明参考手册
l Prestart
l 创建仓库(Repository)
svnadmin create /path/to/repository
svnadmin是有用的subversion系统管理命令,使用svnadmin help查看在线帮助
信息。subversion的手册推荐在项目在repository下分别建立branches/ tags/trunk/三个目录,分别存放分支/标签/主分支
l 检出(checkout)项目
svn checkout file:///.../trunk/ project
svn checkout http://host/.../trunk/ project
l 列出仓库中的项目(list)
svn list -verbose file:///.../tags/
svn list -verbose http://.../trunk/
l 状态查询(status)
svn status
给出新文件,已经改变的文件和被删除的文件列表
l 添加文件或目录(add)
svn add
l 删除文件或目录(delete)
svn delete
svn delete http://host/svn_dir/repository/project_dir 这条命令可以用来删除错误的import的某些项目!!
l 回滚workcopy的修改
svn revert file1 file2
svn revert -R .
l 提交(commit)
svn commit http://host/svn_dir/repository/project_dir
l 更新(update)
svn update
更新仓库中的文件到本地。
l 删除重命名和移动(update)
svn delete (del, remove, rm)
svn move (mv, rename, ren)
l 使用COPY命令管理Tag和 Branch
svn copy http://host/repos/project/trunk http://host/repos/project/tags/1.0.0
用于创建某个特定版本的快照(snapshot);
svn list http://host/repos/project/tags/1.0.0
查看某个版本的内容
svn switch branch_url
把workcopy切换到某个分支
l 版本合并
svn merge -r N:M branch .
把branch上版本N和M之间的修改合并到当前目录
branch可以是url或者本地目录
svn merge tag branch .
把tag和branch之间的修改合并到当前目录
svn log -qv --stop-on-copy http://svnhost/svn/repo/branches/br1
查看某个branch的修改日志从而决定从哪个版本开始merge
l 快速查看当前workcopy的版本号(svnversion)
svnversion
给出新文件,已经改变的文件和被删除的文件列表;
参考
CVS中文手册
http://man.chinaunix.net/develop/cvsdoc_zh/
使用Subversion进行版本控制
http://svnbook.red-bean.com/index.zh.html
相关推荐
Unix和Linux之所以优秀,是因为它们是由一群聪明、有创造力的人开发的,这些人以思考为乐,不仅非常聪明,而且非常了解自己在做什么,并且热爱他们的工作。因此,当你使用Unix或Linux系统时,你实际上是在与历史上最...
书中的练习和光盘资源提供了丰富的实践机会,对于任何希望在Unix/Linux环境中开发软件的人来说,都是不可或缺的学习材料。通过学习这本书,读者将能够熟练地利用Unix/Linux的强大力量,编写出高效、稳定的系统级程序...
但我可以根据【标题】和【描述】提供的信息,概述《Linux指令速查手册》中可能包含的知识点。 《Linux指令速查手册》是一本关于Linux操作系统的指令参考书籍,覆盖了Linux系统中常用的命令行指令。本书通过介绍每一...
《Unix-Linux编程实践教程》是一本面向程序员和系统管理员的实用指南,旨在通过丰富的实例深入浅出地介绍Unix和Linux环境下的系统级编程技术。这本书涵盖了从基本的命令行操作到复杂的系统调用和库函数的使用,是...
Greetings, and welcome to Unix and Linux! In this book, you’ll find the information you need to get started with the ...or between specific Unix or Linux versions, but they’ll be small indeed.
在软件开发上,Unix和Linux提供了强大的开发工具,如gcc编译器、make构建工具、gdb调试器,以及版本控制系统如git。它们还有一套完整的调试、性能分析和内存检查工具,如strace、valgrind、gprof等,帮助开发者优化...
这个"UNIX/Linux下C/C++函数速查手册"提供了全面的C和C++函数参考,帮助开发者快速找到所需的函数信息,提升开发效率。以下是一些关键的知识点: 1. **C语言函数**: - **标准库函数**:C语言的标准库包括、、等...
UNIX&LINUX;大学教程.pdf
尽管给定的部分内容似乎与标题和描述不相符,主要包含了重复的下载...总之,curses库是UNIX/Linux环境下进行文本用户界面开发的强大工具,掌握了其基本原理和编程技巧,就能构建出功能丰富、界面友好的TUI应用程序。
在IT领域,Linux操作系统是开发者、系统管理员和程序员不可或缺的工具。...Unix/Linux源码的了解则需要对操作系统原理有较深理解,包括进程管理、内存管理、设备驱动等,这通常是系统级开发人员的进阶内容。
Unix or Linux下软件无线电的平台,在上面可以进行通信的多种仿真测试,如LDPC,信道估计等
UNIX and Linux System Administration Handbook: UNIX Linux Syste Admin Han_5 5th Edition, 英文版,带书签
Covering all the essential components of Unix/Linux, including process management, concurrent programming, timer and time service, file systems and network programming, this textbook emphasizes ...
UNIX® and Linux® System Administration Handbook, Fifth Edition, is today’s definitive guide to installing, configuring, and maintaining any UNIX or Linux system, including systems that supply core ...
Unix和Linux的美妙之处在于,它们是由那些喜欢思考的聪明人所开发的。他们不仅非常聪明,而且明白自己在做什么,并且热爱他们的工作。 整本书的目的是要引导读者学习Unix和Linux,同时改变读者的生活。Harley Hahn...
UNIX® and Linux® System Administration Handbook, Fifth Edition, is today’s definitive guide to installing, configuring, and maintaining any UNIX or Linux system, including systems that supply core ...
包括:C++标准库.chm,C函数速查.chm,ISO-C函数速查.chm,Linux_C.chm,Linux函数大全.chm,UnixC函数.chm,UNIX-C函数速查.chm,POSIX-C函数速查.chm等函数速查手册,欢迎大家下载!
es2unix作为Linux命令行下的Elasticsearch查询工具,极大地提高了数据检索和处理的效率。通过熟练掌握es2unix以及与其配合使用的Unix命令,你可以轻松实现对Elasticsearch中的大数据进行快速分析和操作,这对于日常...
黄海涛是本书的译者之一,拥有丰富的教学和研究经验,研究领域包括软件工程、工具及环境、形式化、面向对象、组件、中间件、分布式计算、过时管理和测试与度量等。 出版信息的补充: 本书还提供了出版社的详细信息...