gcc编译步骤 动态库、静态库的使用、gdb调试、Makefile编写

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>. 命名规则:
    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 -v

    tar zxvf
    tar jcvf
    

    5>. 优缺点:
    优点: 1. 执行程序体积小

    1. 动态库更新后不需要重新编译程序
      缺点: 1. 程序的执行依赖动态库
    2. 动态库没有打包到应用程序中,加载速度相对较慢

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) 
#命令前加-可以在命令执行失败时不中断

猜你喜欢

转载自blog.csdn.net/ts1130/article/details/77868986