目录
GCC支持的文件格式
使用GCC编译器需要特殊的文件名后缀,若文件名无后缀或后缀非法则GCC编译器无法识别。GCC支持的文件类型和后缀常见的有: .c:C语言源代码 .cc:C++语言源代码 .m:Objective-C语言源代码 .i:预处理过的C语言程序 .ii:预处理过的C++语言程序 .s:汇编语言程序 .h:预处理文件(头文件) .o:目标文件 .a/.so:编译后的库文件
代码优化
代码优化指的是编译器通过分析代码找出其中不是最优的部分,然后对代码重新组合从而改善程序的执行性能。GCC的代码优化功能十分强大。GCC提供的代码优化有4个等级,分别是: -O0:无优化(默认) -O1:1级优化。使用该选项能减少目标文件大小及执行时间并且不会让编译时间明显增加。在编译较大型的程序时常用。 -O2:2级优化。包含1级优化功能并进一步优化生成的目标代码(例如使用更优化的指令调度等),不过会让编译时间增加。 //2级优化是大多数程序员最常用的代码优化等级,因为它在编译时间与优化长度上取得了一个平衡点。 -O3:3级优化。包含2级优化功能并进一步优化生成的目标代码(例如使用特殊的处理器等),不过会让编译时间大幅度增加。 虽然代码优化选项可以加快生成的可执行程序的运行速度,不过对于需要调试的代码而言是一个巨大的挑战。因为经过优化的代码与原始代码很可能有诸多不同,使用调试工具时非常有可能跳转到意外的地方从而使调试崩溃。而且,使用越高等级的代码优化,编译时间也会越长。因此代码优化功能要适度使用,也要认清并非所有代码都需要代码优化功能。
GDB调试
gdb gnu的是一款代码调试工具 1、将代码编译成可gdb调试的程序 gcc -g c原码 -o 目标文件(程序名) 2、gdb 程序名(进入gdb调试) 调试基本命令: l:查看10行代码 b + 行号:在该行加断点 info b: 查看断点信息 r:运行程序 n:单步调试,不进入函数 s:单步调试,进入函数 p + 变量名:查看当前该变量的值 del + 断点编号:删除断点 q :退出调试
makefile
makefile基本介绍
makefile 关系到整个工程的编译规则,一个工程中的源文件不计其数,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译甚至于进行更复杂的功能操作,都可以通过makefile指定。makefile作为一个可执行文件,就像一个shell 脚本一样,自己设计文件的编译规则与顺序,其中也可以执行其他操作系统的命令。
makefile的特点
makefile 可以根据文件的时间戳“自动化编译”。 一旦写好,只需要配合“make”命令使用,整个工程将自动编译,极大的提高了软件开发的效率。而“make”是一个命令工具,是一个makefile 中指定的命令工具,一般来说,大多数的IDE 都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。
“make”命令的使用
“make”是一个命令行命令,使用规则: 当写好makefile文件之后,在命令行执行命令:make GNUmakefile、makefile、Makefile。 如果你写的makefile文件名和上面三个文件名一样,系统会自动在当前目录找写好的makefile执行。有多个makefile,但是如果不用 make –f 指定执行某个文件,那么默认先赵GNUmakefile 再找Makefile 最后才是makefile。 或者可以指定一个makefile执行,格式如下: make -f {自己写的makefile文件名} “make”作为一个命令还有其他选项,如下图:
makefile文件的编写规则
target:prerequisites tab键command target 目标文件名 prerequisites 生成目标文件需要的依赖文件 command 由依赖文件生成目标文件所需要执行的命令 上诉四个部分(target、prerequisites、tab键、command)就是最基本的makefile文件组成部分,所有复杂的nakefile文件都是以此思想建立起来的。
例子:
main.c(main主函数文件) demo.c(内含有实现特定功能的函数模块) demo.h(.c文件需要的头文件) 以上是一个简单工程的文件目录: 如果不用makefile编译,就可以直接 gcc main.c demo.c -o test进行编译 现在就基于它写一个简单的makefile文件 test:main.o demo.o gcc main.o demo.o -o test main.o:main.c gcc -c main.c -o main.o demo.o:demo.c gcc -c demo.c -o demo.o 1、在实际工作中,一个工程或项目main.c有且仅有一个,就像整个项目的大脑,根据程序的设计根据功能的不同调用不同函数模块(demo.c)。然而一个大的项目要实现功能很多,所需要的自定义的函数也很会很多,众多的函数模块不可能放在一个文件。放在一个文件不仅会降低开发效率还不利于后期修改维护,所以会有很多demo(demo1.c demo2.c......)。如果不用makefile,直接gcc,意味着每次编译都要输入一大串命令。如果文件名太长,命令行编译将是噩梦很容易写错。如果第一次写好makefile后,每次编译都只需要执行make命令就可以了。 2、makefile最大优势不是简化程序员的命令输入,如果仅仅是简化命令输入的优点。makefile不会这么重要,直接复制粘贴也能解决。makefile最大的优点也就是它的特点“会根据时间戳自动化编译文件”。在对一个文件修改保存退出后文件的时间戳会更新。make命令执行时,会自动检测文件的时间戳,如果发现某个依赖文件的时间戳比目标文件时间戳更新,那么会执行这个命令,否则将不再执行。也就是说你只是改了demo1.c意味着只会执行与其相关的编译命令而不是所有编译命令全部执行。 比如在进行内核移植交叉编译的时候,单个文件很大。如果用gcc直接编译所有文件都会全部编译一个文件用十分钟,十来个文件就是1个小时。如果一次成功很幸运,如果不成功该bug后还要再来1小时。 如果用makefile,它只会重新编译修改后的文件形成需要的目标文件,可以大量减少编译时间,提高开发效率。
时间戳
makefile执行顺序
makefile重要的变量
$@ 目标文件 $^ 所有依赖文件 $< 第一个依赖文件
makefile常见的模板
模板一( 最基础简单的模板)
test:main.o add.o myprint.o
gcc main.o add.o myprint.o -o test
main.o:main.c
gcc -c main.c -o main.o
add.o:add.c
gcc -c add.c -o add.o
myprint.o:myprint.c
gcc -c myprint.c -o myprint.o
模板二(使用了一些变量)
使用了一些变量
OBJS=main.o add.o myprint.o
CFLAGS= -Wall -g -O2 -I./
VPATH=src
test:$(OBJS)
gcc $(CFLAGS) $(OBJS) -o test
.PHONY:clean
clean:
rm -r ./*.o test
模板三(进阶型)
CC=gcc
#CC=arm-linux-gcc
CFLAGS=-Wall -g -std=gnu99 -I./inc
LDFLAGS= -L ./lib/ -lcam
#LDFLAGS= -L ./lib/ -lcam_arm
$(all):$(APP)
$(CC) $< $(CFLAGS)
APP = test
#APP = arm_test
#src = $(wildcard *.c)
src = $(wildcard ./src/*.c)
OBJS = $(patsubst %.c, %.o, $(src))
$(APP): $(OBJS)
$(CC) -o $(APP) $^ $(LDFLAGS)
rm -f $(OBJS)
.PHONY:clean
clean:
rm -rf $(OBJS) $(APP)