Linux下的程序设计主要指C程序设计,它与其他环境中的C程序设计一样,主要涉及到编辑器、编译链接器、调试器及项目管理工具。
GCC编译器能将C、C++语言源程序、汇编程序和目标程序编译、连接成可执行文件,如果没有给出可执行文件的名字,GCC将生成一个名为a.out的文件。
在Linux系统中,编译器通过程序的扩展名可分辨出编写原始程序代码所用的语言,由于不同程序所需要执行编译的步骤是不同的。因此GCC可根据不同的扩展名对它们进行分别处理。
GCC 编译过程
编译过程分为四个阶段
预处理(Pre-Processing)
编译(Compiling)
汇编(Assembling)
链接(Linking)
基本语法格式
gcc [选项] 源文件 [选项] [目标文件]
举例
$gcc -E hello.c -o hello.i
#“-E” 指定只进行预处理
#“hello.c”是源程序文件
#“-o”指定生成目标文件
#“hello.i”是预处理过程生成的目标文件
$gcc -S hello.i -o hello.S
#“-S”指定只进行到编译阶段
#“hello.i”是进行编译的源文件
#“-o”指定生成目标文件
#“hello.S”是编译生成的目标文件名
$gcc -c hello.S -o hello.o
#“-c”指定只进行到汇编阶段结束为止
#“hello.S”是进行汇编的源文件
#“-o”指定生成目标文件
#“hello.o”是编译生成的目标文件名。hello.o为二进制目标代码文件
$gcc hello.o -o hello
#该命令gcc之后无选项参数,表示对指定的源文件进行编译,直到输出执行文件(示例中的源文件为hello.o,输出的执行文件hello)。
$./hello
#运行该可执行文件
函数库创建和使用
函数库一般分为静态库和动态库两种。
静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。
动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时运行链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的libc.so.6就是动态库。GCC在编译时默认使用动态库。
#ifndef _libhello_H_
#define _libhello_H_
void print_hello(void);
#endif
编辑源文件libhello.c
#include
void print_hello(void)
{
printf(“hello library\n”);
}
$gcc –c libhello.c –o libhello.o
$ar –rc libhello.a libhello.o
$file libhello.a
$gcc –o usehello_static usehello.c libhello.a
$./usehello_static
动态库的创建
$gcc –fPIC –Wall –g
$gcc –fPIC –Wall –g–c libhello.c –o libhello.o
$gcc –g –shared –W1,-soname,libhello.so –o libhello.so.1.0 libhello.o
$file libhello.so.1.0
$ln –s libhello.so.1.0 libhello.so
$gcc –g –o usehello_dy usehello.c –lhello –L ./
$LD_LIBRARY_PATH=$(pwd) ./usehello_dy
静态库与共享库的区别
可执行文件大小不同
共享库可很大程度上节约系统内存。
共享库发生错误,只需要修改当前共享库,无需重新编译每个使用该库的程序
多个源文件编译
$gcc foo1.c foo2.c -o foo
解释:对于源文件不止一个情况,GCC编译过程仍然按照预处理、编译、汇编和链接的过程依次进行。因此,上面这条命令相当于依次执行如下三条命令。
$gcc -c foo1.c -o foo1.o
$gcc -c foo2.c -o foo2.o
$gcc foo1.o foo2.o -o foo
GCC选项——-I dir选项
在当前路径下有文件hello1.c ,“/root/work/gcc/”目录下有my.h:
编译命令:
$gcc hello1.c -I /root/work/gcc/ -o hello1
GCC选项——==-L dir ==选项
“-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加dir目录。例如有程序hello2.c需要用到目录“/root/work/gcc/lib/” /下的一个动态库libxch.so,则只需键入如下命令即可:
$gcc hello2.c –L root/work/gcc/lib/ hello2
注意:“-I dir”和“-L dir”都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名。
GDB概述
对于Linux程序员来讲,GDB(GNU Debugger)通过与GCC的配合使用,为基于Linux的软件开发提供了一个完善的调试环境。
将调试符号插入到生成的二进制代码中的gcc编译
$gcc -g hello.c -o hello
GDB调试举例
#【GDBTest.c】
#include
void sum(int m);
int main()
{
int i,n=0;
sum(50);
for(i=1; i<=50; i++)
{
n += i;
}
printf("The sum of 1-50 is %d \n", n );
return(0);
}
void sum(int m)
{
int i,n=0;
for(i=1; i<=m;i++) n += i;
printf("The sum of 1-m is %d\n", n);
}
$gcc -g test.c -o test
$gdb test
设置断点
(gdb) break 6
GDB调试选项
make简介
Make工程管理器
Makefile
makefile的编写
Makefile术语
target: dependency
COMMAND
环境变量——工作环境的相关变量,如路径、时间等。
自动变量——用于代表编译语句中出现的目标文件和依赖文件,并且具有本地含义。
预定义变量——通常指编译器、汇编器的名称及其编译选项。
模式规则
模式规则是用来定义相同处理规则的多个文件的。它不同于隐式规则,隐式规则仅仅能够用make默认的变量来进行操作,而模式规则还能引入用户自定义变量,为多个文件建立相同的规则,从而简化Makefile的编写。
模式规则的格式类似于普通规则,这个规则中的相关文件前必须用“%”标明。
Makefile注释
makefile文件中只有行注释,其注释用“#”字符,就像C语言中的“//”,如果要在makefile文件中使用“#”字符,可以使用“\”进行转义,即“#”。
Makefile-函数
$(subst from,to,text)
功能:在文本text中使用to替换每一处form。
举例:$(subst ee,EE,feet on the street)
$(patsubst pattern,replacement,text)
功能:寻找text中符合pat的字,并repl替换它们。
举例:$(patsubst %.c,%.o,x.c.c bar.c)
$(filter pattern……,text)
功能:返回在text中有空格隔开并匹配pat的字。
举例:sources := foo.c bar.c bar.s ug.h
foo:$(sources)
cc $(filter %.c %.s,$(sources)) -o foo
$(filter-out pattern……,text)
$(wildcard pattern)
功能:寻找与格式匹配且文件存在的文件名
举例:$(wildcard %.c ../src/%.c)
$(addprefix prefix,names……)
功能:将prefix附加在每一个独立文件名的前面。
举例:$(addprefix src/,foo bar)