gcc生成ELF文件的整个流程
1.0预处理
#开头的都是预处理,生成.i文件
2.0编译
对预处理过后的代码进行词法与句法分析,生成目标系统的汇编代码,生成.s文件
3.0汇编
对汇编文件进行优化,生成目标代码文件,生成.o文件
4.0链接
解析目标代码的外部引用,将多个目标代码文件连接为一个可执行文件
gcc命令
gcc 【选项】 文件列表
过程控制选项
(1)预处理选项(-E)
(2)编译选项(-S)
(3)汇编选项(-c)
输出目标选项控制
-o filename
gcc main.c -o main
输出所有警告选项 -Wall
gcc main.c -o main.c
头文件选项 -I filename
将dirname目录加入到头文件搜索目录列表中。当gcc在默认的路径中没有找到头文件时,就到本选项指定的目录中去找
$ tree
.
├── inc
│ └── test.h
└── main.c
gcc main.c -I inc -o main
链接库选项
添加库文件搜索目录(-Ldirname)
将dirname目录加入到库文件的搜索目录列表中。
加载库名选项(-lname)
加载名为libname.a或libname.so的函数库。例如:-lm表示链接名为libm.so的函数库。
静态库选项(-static)
代码优化选项
gcc提供几种不同级别的代码优化方案,用“-O*level”*选项表示。level取值可以是0、1、2、3和s。
默认0级,即不进行优化。典型的优化选项:
(1)-O或-O1:基本优化,使代码执行的更快。
(2)-O2:产生尽可能小和快的代码。如无特殊要求,不建议使用O2以上的优化。
(3)-Os:生成最小的可执行文件,适合用于嵌入式软件。
调试选项及调试示例
代码:GIT下载后在“05_100ASK_IMX6ULL裸机程序/6_Makefile与GCC/001_gcc_02”目录下。
gcc支持数种调试选项:
-g:产生能被GDB调试器使用的调试信息。
举个例子,首先需要在编译时加上“-g”选项,操作步骤如下:
$ gcc main.c -g -o main
GDB调试示例:
(1)run命令
调试运行,使用run命令开始执行被调试的程序,run命令的格式:
run [运行参数]
$ gdb -q main <—进入调试程序
Reading symbols from output…done.
(gdb) run <—开始执行程序
Starting program: /home/100ask/makefile/
100 ask
[Inferior 1 (process 7425) exited normally]
(gdb)
(2)list命令
列出源代码,使用list命令来查看源程序以及行号信息,list命令的格式:
list [行号]
(gdb) list 1 <—列出第一行附近的源码,每次10行
#include <stdio.h>
#define HUNDRED 100
int main()
{
int a = 100;
printf("%d ask\n",HUNDRED);
return 0;
(gdb) <—按Enter键,列出下10行源码
}
(gdb)
(3)设置断点
1)break命令,设置断点命令,break命令的格式: break <行号> | <函数名>
(gdb) break 7
Breakpoint 1 at 0x40052e: file main.c, line 7.
(gdb)
2)info break命令,查 看断点命令:
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040052e in main at main.c:7
(gdb)
3)delete breakpoint命令,删除断点命令, delete breakpoint命令的格式: delete breakpoint <断点号>
(gdb) delete breakpoint 1
(gdb) info break
No breakpoints or watchpoints.
(gdb)
(4)跟踪运行结果
1)print命令,显示变量的值,print命令的格式:print[/格式] <表达式>
2)display命令,设置自动现实命令,display命令的格式: display <表达式>
3)step和 next命令,单步执行命令,step和next命令的格式:step <行号> 或 next <行号>
4)continue命令,继续执行命令。
(gdb) break 7
Breakpoint 1 at 0x40052e: file main.c, line 7.
(gdb) break 9
Breakpoint 2 at 0x400535: file main.c, line 9.
(gdb) run
Starting program:/home/100ask/makefile/
Breakpoint 1, main () at main.c:7
7 int a = 100;
(gdb) continue
Continuing.
动态链接库和静态链接库使用例程
静态库和动态库,是根据链接时期的不同来划分。
静态库:在链接阶段,所用的库就被加进可执行程序里了。静态链接生成的可执行文件,已经内嵌了所有的库,可以独立运行。链接静态库从某种意义上来说是一种复制粘贴,被链接后库就直接嵌入可执行程序中了。如果有多个程序都用到这些库,并且都使用静态 接,那么系统里空间就有很大的浪费,而且一旦发现系统中有bug,就必须把所有程序都重新编译、重新链接,十分麻烦。静态库是不是一无是处了呢?不是的,如果代码在其他系统上运行,且没有相应的库时,解决办法就是使用静态库。而且由于动态库是在程序运行的时候被链接,因此动态库的运行速度比较慢。
动态库:在程序执行的时候,才把所需要的库跟程序链接在一起。多个程序可以合用一份动态库,节省存储空间。如果发现bug或者是要升级,只要用新的库把原来的替换掉就可以了。
一个例子
VERSION = 1.0.0
SOURCE = $(wildcard ./src/*.c)
OBJECT = $(patsubst %.c, %.o, $(SOURCE))
INCLUDES = -I ./inc
TARGET = enable
CC = gcc
CFLAGS = -Wall -g
$(TARGET) : $(OBJECT)
@mkdir -p output/
$(CC) $^ $(CFLAGS) -o output/$(TARGET)_$(VERSION)
%.o : %.c
$(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@
.PHONYl : clean
clean:
@rm -rm $(OBJECT) output/
# 行1 将版本号赋值给变量VERSION
# 行2 获取当前目录下src所有.c文件,并赋值给SOURCE
# 行3 将所有的从src查找出符合.c文件类型的文件,然后一一替换并生成.o文件
# 行5 通过-I选项指明头文件的目录,并赋值给INCLUDES
# 行7 最终目标文件名为 enable
# 行8 CC 替换 gcc 编译工具
# 行9 将显示的所有警告信息选项和gdb调试选项赋值给变量CFLAGS
# 行12 级联创建 output文件
# 行13 编译生成可执行文件enable
# 行16 将源文件生成对应的目标文件
# 行18 伪目标防止该目录下有clean的文件夹
# #现在我们的目录里面有名为“clean”的文件,目标文件是有的,并且没有依赖文件,没有办法判断依赖文件的时间。
# 这种写法会导致:有同名的"clean"文件时,就没有办法执行make clean操作。解决办法:我们需要把目标定义为假想目标,用关键字PHONY。
# %.o:表示所用的.o文件
# %.c:表示所有的.c文件
# $@:表示目标
# $<:表示第1个依赖文件
# $^:表示所有依赖文件
# 主要参考: http://wiki.100ask.org/%E7%AC%AC009%E8%AF%BE_gcc%E5%92%8Carm-linux-gcc%E5%92%8CMakefile