8.28 《Andvance linux programming》学习笔记
时间:2010-08-29 来源:uag
今天开始学习linux编程,看e文《Andvance linux programming》电子书。虽然以前教材也很多是E文的,但是看起来还是有点累。
不管理解错对,先记下来。
今天主要学习了第一章,主要内容如下:
1.linux环境下C和C++代码的编译和连接。
2.Makefile文件的编写。
3.gdb的初步使用。
1.linux下C和c++代码的编译和连接。
c代码---main.c
#include <stdio.h>
#include "reciprocal.hpp"
int main(int argc, char ** argv)
{
int i;
i = atoi(argv[1]);
printf("the reciprocal of %d is %g\n",i,reciprocal(i));
return 0;
}
头文件---reciprocal.hpp
#ifdef __cplusplus
extern "C" {
#endif
extern double reciprocal (int i);
#ifdef __cplusplus
}
#endif
注:什么是hpp文件。google之: 是Header Plus Plus的简写,是一种可以将头文件内容和实现放进同一个文件的格式文件。
即*.hpp里声明实现都有,可以减少.cpp文件的数量。
C++文件---reciprocal.cpp
#include<cassert>
#include "reciprocal.hpp"
double reciprocal (int i)
{
assert(i!=0);
return 1.0/i;
}
编译源代码
% gcc -c main.c 编译main.c
% g++ -c reciprocal.cpp 编译reciprocal.cpp
注:因为头文件跟源代码在同一个目录,所以我们不用指定包含的头文件路径。如果你所需要的头文件不跟源文件一个目录,则可以通过-I去指定路径。
% g++ -c -I ../include reciprocal.cpp
连接.o文件生成可执行文件:
% g++ -o reciprocal main.o reciprocal.o
这样就可以使用如下命令来运行程序
% ./reciprocal 7
结果为:
The reciprocal of 7 is 0.142857
另外,如果你想将其他库文件连接如你的程序(windows下的.lib在linux是.a文件),你可以通过-l来加入。如:
% g++ -o reciprocal main.o reciprocal.o -lpam
使用-l是,编译器会自动加入lib前缀和.a后缀,即将libpam.a的静态库连接如程序。
在引入这样的静态库时,系统会默认去寻找/lib 和/usr/lib这两个目录,如果你需要去寻找其他目录,你可以通过
-L去指定。如:
% g++ -o reciprocal main.o reciprocal.o -L/usr/local/lib/pam -lpam
2.Makefile文件的编写。
编写Makefile可以自动编译你的程序,这样如果你的文件非常多的情况下,可以明显提高你的效率。像上面提到的程序,我们可以通过编写如下的Makefile文件
自动编译程序。
reciprocal: main.o reciprocal.o
g++ $(CFLAGS) -o reciprocal main.o reciprocal.o
main.o: main.c reciprocal.hpp
gcc $(CFLAGS) -c main.c
reciprocal.o: reciprocal.cpp reciprocal.hpp
g++ $(CFLAGS) -c reciprocal.cpp
clean:
rm -f *.o reciprocal
注:在每一个包含命令的行,必须一TAB开头,不能是空格代替,否则会出错。
那么如何编写Makefile。(参考: http://www.chinaunix.net/jh/23/408225.html)
这里写得非常详细,顺便感谢作者,看了非常有帮助。
一、Makefile的规则
在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。
target ... : prerequisites ...
command
...
...
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),
对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生
成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,
command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
二、一个示例
正如前面所说的,如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile
应该是下面的这个样子的。
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
反斜杠(\)是换行符的意思。这样比较便于Makefile的易读。我们可以把这个内容保存在文件为“Makefile”或
“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文件edit。如果要删除执行文件和所
有的中间目标文件,那么,只要简单地执行一下“make clean”就可以了。
在这个makefile中,目标文件(target)包含:执行文件edit和中间目标文件(*.o),依赖文件(
prerequisites)就是冒号后面的那些 .c 文件和 .h文件。每一个 .o 文件都有一组依赖文件,而这些 .o 文件
又是执行文件 edit 的依赖文件。依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是
哪些文件更新的。
在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。记住,
make并不管命令是怎么工作的,他只管执行所定义的命令。make会比较targets文件和prerequisites文件的修改
日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执
行后续定义的命令。
这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的lable一样,其冒号后什么
也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要
在make命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个makefile中定义不用的编译或
是和编译无关的命令,比如程序的打包,程序的备份,等等。
3.gdb的初步使用
1)启动gdb % gdb reciprocal
2)开始运行 (gdb) run
显示:
Starting program: /home/uag/cspace/1.2/reciprocal
Program received signal SIGSEGV, Segmentation fault.
0x002997bc in ?? () from /lib/tls/i686/cmov/libc.so.6
3)此时你可以查看堆栈 (gdb) where
内容:
#0 0x002997bc in ?? () from /lib/tls/i686/cmov/libc.so.6
#1 0x00299520 in strtol () from /lib/tls/i686/cmov/libc.so.6
#2 0x00296891 in atoi () from /lib/tls/i686/cmov/libc.so.6
#3 0x0804854d in main (argc=1, argv=0xbffff474) at main.c:6
4)使用 up 数字 可以查看对应的代码 (gdb) up 3
内容:
#3 0x0804854d in main (argc=1, argv=0xbffff474) at main.c:6
6 i = atoi(argv[1]);
5)使用print查看变量的值 (gdb) print argv[1]
显示:
$1 = 0x0
注:您查看的值为空。
6)使用break设置断点 (gdb) break main
显示:
Breakpoint 1 at 0x804853d: file main.c, line 6.
7)使用next进入下一句
8)使用setp进入函数内部
9)使用q退出