gcc编译过程(ESc)
1.预处理器:cpp
头文件展开,宏替换,注释去掉
gcc -E hello.c -o hello.i (-o 指定编译后文件名)
2.编译器:gcc
C文件变成汇编文件
gcc -S hello.i -o hello.s
3.汇编器:as
汇编文件变成二进制文件
gcc -c hello.s -o hello.o
4.链接器:ld
将库函数相应代码组合到目标文件中
gcc hello.o -o app
注意:其中第二阶段最费时,其他阶段gcc调用其它工具完成
直接生成:gcc hello.c -o myapp
gcc hello.c -I(指定头文件路径) -D(指定宏) -O3(指定优化等级) -g(包含调试信息) -Wall(编译时输出警告信息)
静态库的制作
1>. 命名规则
1). lib + 库的名字 + .a
2). libmytest.a
2>. 制作步骤:
1). 生成对应的.o文件 – .c –> .o -c
gcc -c -I ../include/ *.c
2). 将生成的.o文件打包 ar rcs + 静态库的名字(libMytest.a) + 生成的所有的.o
3>. 发布和使用静态库:
1). 发布:静态库、头文件
2). 使用1:gcc main.c ./lib/Mytest.a(直接指定库) -I(指定头文件) -o (生成可执行程序)
gcc main.c -I ./include/ ./lib/libTest.a -o app(库路径跟在.c后)
使用2:gcc main.c -I include -L lib(库路径) -l(库名,掐头去尾) -o myapp
gcc main.c -I ./include/ -L./lib/ -lTest -o Test
nm lib.a 查看库文件包含内容
4>. 静态库的优缺点
优点:
1.发布程序时不需要提供对应的库
2.加载库的速度快
缺点:
1.库(以.o为最小打包单元)被打包到应用程序中,导致库的体积很大
2.库发生改变后需要重新编译程序
共享库的制作:
1>. 命名规则:
1). lib + 名字 + .so
2>. 制作步骤:
1). 生成与位置无关的代码 (生成与位置无关的.o)
gcc -fPIC -c *.c -I../include
2). 将.o打包成共享库(动态库)
gcc -shared -o libMyapp.so *.o
3>. 发布和使用共享库:
1). 发布:动静态库、头文件
2). 使用1:gcc main.c lib/Mytest.so(直接指定库) -I(指定头文件) -o (生成可执行程序)
使用2:gcc main.c -I include -L lib(库路径) -l(库名,掐头去尾) -o myapp
注:动态库由动态链接器(本质是动态库)调用,依赖环境变量,使用方法2若不添加环境变量动态链接器无法找到动态库
3). ldd myapp :查看执行程序依赖的所有共享库
4>. 解决程序执行时动态库无法被加载的问题:
1). 放到系统的库目录 中 – 不允许使用
2). 临时测试
环境变量: LD_LIBRARY_PATH=将动态库的路径设置给该变量
将设置的值, 导入到系统环境变量中: export LD_LIBRARY_PATH=动态库
当终端关闭, 设置会失效
3).不常用的方法(永久设置):
用户级别:在家目录的 .bashrc文件 中添加一句话: export LD_LIBRARY_PATH=动态库目录的绝对路径
.bashrc修改完成, 需要重启终端
系统级别:/ect/profile
4).
1. 需要找动态连接器的配置文件 – /etc/ld.so.conf
2. 动态库的路径写到配置文件中 – 绝对路径
3. 更新 – sudo ldconfig -vtar zxvf tar jcvf
5>. 优缺点:
优点: 1. 执行程序体积小- 动态库更新后不需要重新编译程序
缺点: 1. 程序的执行依赖动态库 - 动态库没有打包到应用程序中,加载速度相对较慢
- 动态库更新后不需要重新编译程序
gdb调试
编译: gcc *.c -g -o app
开始调试: gdb app
传递参数:set args xxx
l: 默认列出包含main函数的文件
l file.c:20 —查看指定文件指定行
l file.c:func —查看指定文件内指定函数
break(b) 行号 if i==15
dis num(编号) 禁用断点
ena num(编号) 打开断点
delete(d) 编号 删除断点
info(i) break(b)
start 单步运行
run(r) 执行
n 单步调试
c continue
step(s) 进入函数内
u 跳出循环
p 变量名 查看变量值
ptype 变量名 查看变量类型
display 变量名 追踪变量
undisplay
until 跳出循环(不能有断点)
finish 跳出当前函数(不能有断点)
set var i=10
quit 退出gdb
set follow-fork-mode child 设置跟踪子进程
set follow-fork-mode parent 设置跟踪父进程
strace ./a.out 追踪当前程序执行过程中使用的系统调用
makefile的编写:
1. makefile的命名
makefile/Makefile
2. makefile的规则:
规则中的三要素: 目标, 依赖, 命令
目标:依赖条件
命令
子目标和终极目标的关系:终极目标依赖于子目标
更新目标的原则:目标不存在 或 依赖更新时间在目标之后
3. makefile的两个函数
wildcard 查找指定目录下指定类型的文件
src = $(wildcard ./*.c)
patsubst 匹配替换
obj = $(patsubst %.c, %.o, $(src))
4. makefile的三个自动变量,只能在当前规则中使用
$< 规则中的第一个依赖
$@ 规则中的目标
$^ 规则中的所有依赖
1.最简单Makefile
app:main.c add.c sub.c
gcc main.c add.c sub.c -o app
2.拆分依赖,重新编译时已有且最新的依赖不用更新,减少编译时间
app:main.o add.o sub.o
gcc main.o add.o sub.o -o app
main.o:main.c
gcc -c main.c
add.o:add.c
gcc -c add.c
sub.o:sub.c
gcc -c sub.c
3.增加自动变量
obj=main.o add.o sub.o
target=app
#makefile中自己维护的变量
CC=gcc
CPPFLAGS = -I
$(target):$(obj)
$(CC) $(obj) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
4.使用函数
target=app
src=$(wildcard ./*.c)
obj=$(patsubst ./%.c, ./%.o, $(src))
CC=gcc
CPPFLAGS = -I
$(target):$(obj)
$(CC) $(obj) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean
clean:
-rm /etc
rm -f $(obj) $(target)
#命令前加-可以在命令执行失败时不中断