GCC、GDB和Makefile学习笔记

前言

关于Linux系统编程的前导课程学习笔记,共涉及 GCC GDB Makefile 三个部分

1. GCC

介绍

GCC(英文全拼:GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件,由 Richard Stallman 于 1985 年开始开发。

GCC 原名为 GNU C语言编译器,因为它原本只能处理 C 语言,但如今的 GCC 不仅可以编译 C、C++ 和 Objective-C,还可以通过不同的前端模块支持各种语言,包括 Java、Fortran、Ada、Pascal、Go 和 D 语言等等。

GCC 的编译过程可以划分为四个阶段:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)以及链接(Linking)。

1.1 相关参数

4个步骤 :预处理、编译、汇编、链接

-E:仅执行预处理           # hello.i  源文件 i  
-S:只编译                # hello.s  汇编文件 s 
-c:编译和汇编,但不链接。   # hello.o  目标文件 o
-o <file>:指定输出文件。   # a.out  可执行文件
-I:  指定头文件位置         # gcc -I ./inc hello.c -o hello
-g:  编译时增加调试文件
-Wall: 显示所有警告信息
-D:    向程序中“动态“注册宏定义

1.2 静态库和动态库

静态库

空间大,速度块,基本淘汰

1. gcc -c foo.c -o foo.o    # 生成 foo.o 目标文件
2. ar rcs libfoo.a foo.o    # 生成 libfoo.a 静态库
3. gcc hello.c -static libfoo.a -o hello    # 编译 并链接静态库 libfoo.a
4. gcc test.c -static ./lib/libmymath.a -I ./inc -o b.out  # 文件+库+头文件
动态库

空间小,速度慢,最多使用

1. gcc -c add.c -o add.o -fPIC          # 生成于位置无关的代码 -fPIC
2. gcc -shared -o libmymath.so add.o sub.o   #  制作动态库
3. -l: 指定库名      -L:指定库路径
   gcc test.c -lmymath -L./lib -I./inc -o a.out  # 编译可执行程序

执行报错
原因

  1. 链接器:工作于链接阶段,工作时需要 -l 和 -L
  2. 动态链接器:工作于程序运行阶段,工作时需要提供动态库所在目录位置解决

解决 :

  1. export LD_LIBRARY_PATH=动态库路径:$LD_LIBRARY_PATH (一次进程里,临时)

  2. 移动到 /usr/lib (永久)

  3. .bashrc 中 写入 环境变量 (永久)

  4. vim /etc/ld.so.conf  # 写入动态库的路径
    ldconfig  #  刷新  (永久)
    

ldd是Linux系统下的一个命令行工具,用于查看可执行程序或共享库所依赖的动态链接库(Dynamic Linking Library,简称DLL)。它会列出指定的可执行程序或共享库所使用的共享库,并显示它们的完整路径。

root@freecho:/opt/C/gcc/lib/dynamicLib# ldd a.out
        linux-vdso.so.1 (0x0000ffffb6b6d000)
        libmymath.so => /lib/libmymath.so (0x0000ffffb6af0000)
        libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffffb6940000)
        /lib/ld-linux-aarch64.so.1 (0x0000ffffb6b34000)
root@freecho:/opt/C/gcc/lib/dynamicLib#

2. GDB

介绍

GDB 全称“GNU symbolic debugger”,从名称上不难看出,它诞生于 GNU 计划(同时诞生的还有 GCC、Emacs 等),是 Linux 下常用的程序调试器。发展至今,GDB 已经迭代了诸多个版本,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。实际场景中,GDB 更常用来调试 C 和 C++ 程序

2.1 基础指令

gcc gdbtest.c -o a.out -g   # -g 使用该参数编译可执行文件,得到调试表
gdb a.out # 开始
l 1       # 从第一行开始显示
l 		  # 继续往下显示   (lsit)
b 52	  # 52行设置断点	  (breakout)
r		  # 运行 		(run)
n   	  # 逐过程单步执行,越过函数,系统函数用 n              (next)
s 		  # 逐语句单步执行,进入函数,其他情况与n无区别,执行下一步 		(step)
until 16  # 运行程序直到达到指定的行号并停止
p i       # 打印变量 i 的值  (print)
continue  # 继续执行断点后续指令
quit      # 退出gdb调试

2.2 断点指令

(gdb) b 23 # 设置断点
(gdb) b 30
(gdb) b 41
(gdb) b 41 if i=5 # 设置条件断点
(gdb) info b # 查看断点信息表
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000009f8 in select_sort at gdbtest2.c:23
2       breakpoint     keep y   0x0000000000000a7c in select_sort at gdbtest2.c:30
3       breakpoint     keep y   0x0000000000000b14 in print_arr at gdbtest2.c:41
4       breakpoint     keep y   0x0000000000000b14 in print_arr at gdbtest2.c:41
        stop only if i=5
(gdb) delete 3 # 删除指定断点

delete  # 删除所有断点
disable	# 禁用断点
enable  # 启用断点

2.3 其他指令

  1. 使用 r 查找段错误出现位置
  2. start :用于开始执行程序并停在main函数的第一条语句上
  3. finish :当你在调试一个函数时,你可以使用finish命令来执行该函数的剩余部分,并停在函数调用的地方
  4. ser args :设置 main 函数命令行参数,在start run 命令之前
  5. run 字符串1字符串2 ... : 设置 main 函数命令行参数
  6. info b:查看断点信息表 information breakout
  7. ptype i:查看变量类型
  8. backtrace :查看函数的调用的栈帧和层级关系 缩写:bt
  9. frame 编号:切换函数的栈帧 缩写:f
  10. display i :设置跟踪变量
  11. undisplay 编号:取消跟踪变量

补:栈帧

栈帧(Stack Frame) 是在程序执行期间,用于管理函数调用和局部变量的一种数据结构。在函数调用时,会创建一个栈帧来存储函数的参数、局部变量以及保存调用函数的返回地址和调用函数的寄存器状态等信息。

每个函数调用都会创建一个新的栈帧,将其添加到函数调用栈(Call Stack)的顶部。当函数执行结束后,其对应的栈帧会被销毁,栈帧也会被从调用栈中移除,程序会返回到调用该函数的上一个栈帧继续执行。

栈帧通常包含以下几个重要的部分:

  1. 返回地址:指向调用该函数的下一条指令的地址,用于函数执行完后返回到正确的位置。
  2. 函数参数:将函数的参数值存储在栈帧中,以便在函数内部使用。
  3. 本地变量:函数中定义的局部变量也被存储在栈帧中,它们只在函数执行期间存在,函数结束后将被销毁。
  4. 保存的寄存器状态:为了保护调用函数时的寄存器状态,可能需要将某些寄存器的值保存在栈帧中,在函数执行完后再恢复寄存器的值。

栈帧的使用使得函数调用和返回的过程更加高效和可控,同时提供了函数间局部变量的隔离,避免了函数之间的冲突。栈帧在计算机体系结构和操作系统中发挥着重要作用,为函数调用提供了必要的支持。

3. Makefile

介绍

Makefile是一个用于构建和管理项目的工程文件,它定义了项目中的源文件、依赖关系以及构建规则等信息,用于自动化编译和链接程序。

Makefile通常使用make工具来执行其中定义的规则和命令。通过Makefile,开发人员可以在项目中定义编译、链接、清理等操作的规则,以及指定项目中的文件之间的依赖关系。这样,当项目的源文件发生变化时,make工具可以根据Makefile中的规则,自动检测变化并重新编译需要更新的文件,从而加快项目的开发和构建过程。

文件命令:makefile Makefile

1个规则

目标:依赖条件
	(一个tab缩进) 命令
  1. 目标的时间必须晚于依赖条件的时间,否则,更新目标
  2. 依赖条件如果不存在,找寻新的规则去产生依赖

ALL:指定makefile的最终目标,否则最终目标写在文件开头

步骤

root@freecho:/opt/C/make# vim makefile
root@freecho:/opt/C/make# cat makefile
hello:hello.c
        gcc hello.c -o a.out
root@freecho:/opt/C/make# ls
hello.c  makefile
root@freecho:/opt/C/make# make
gcc hello.c -o a.out
root@freecho:/opt/C/make# ls
a.out  hello.c  makefile

makefile文件1

ALL:a.out  # 指定makefile的最终目标,否则最终目标写在文件开头

hell.o:hello.c
        gcc -c hello.c -o hello.o
add.o:add.c
        gcc -c add.c -o add.o
sub.o:sub.c
        gcc -c sub.c -o sub.o
mul.o:mul.c
        gcc -c mul.c -o mul.o
div1.o:div1.c
        gcc -c div1.c -o div1.o
a.out:hello.o add.o sub.o mul.o div1.o
        gcc hello.o add.o sub.o mul.o div1.o -o a.out

2个函数

两个函数分别为:wildcard(通配符)patsubst(匹配替换)

2.1 $(wildcard ./*.c)

src = $(wildcard *.c) 
# src = add.c sub.c mul.c div1.c

匹配当前目录下的所有后缀为 .c 的文件,将文件名组成列表,赋值给变量 src

2.2 $(patsubst %.c, %.o, $(src))

obj = $(patsubst %.c, %.o, $(src))
# obj = add.o sub.o mul.o div1.o

参数3 中,包含 参数1 的部分,替换为 参数2,即把 src 变量里所有后缀为 .c 的文件替换为 .o

makefile文件2、3

src = $(wildcard *.c)               # src = add.c sub.c mul.c div1.c
obj = $(patsubst %.c, %.o, $(src))  # obj = add.o sub.o mul.o div1.o

ALL:a.out

hell.o:hello.c
        gcc -c hello.c -o hello.o
add.o:add.c
        gcc -c add.c -o add.o
sub.o:sub.c
        gcc -c sub.c -o sub.o
mul.o:mul.c
        gcc -c mul.c -o mul.o
div1.o:div1.c
        gcc -c div1.c -o div1.o
a.out: $(obj)
        gcc $(obj) -o a.out

clean:  # 终端输入 make clean 才会生效
        -rm -rf $(obj)  # -rm 前面的 '-'  表示出错依然执行

步骤

clean: (没有依赖)

make clean -n 会演示清除命令,不会实际生效

make clean 则会实际生效

root@freecho:/opt/C/make# make
gcc -c add.c -o add.o
gcc -c div1.c -o div1.o
gcc -c -o hello.o hello.c
gcc -c mul.c -o mul.o
gcc -c sub.c -o sub.o
gcc  add.o  div1.o  hello.o  mul.o  sub.o   -o a.out
root@freecho:/opt/C/make# ls
add.c  add.o  a.out  div1.c  div1.o  hello.c  hello.o  m1  m2  makefile  mul.c  mul.o  sub.c  sub.o
root@freecho:/opt/C/make# make clean -n
rm -rf  add.o  div1.o  hello.o  mul.o  sub.o
root@freecho:/opt/C/make# ls
add.c  add.o  a.out  div1.c  div1.o  hello.c  hello.o  m1  m2  makefile  mul.c  mul.o  sub.c  sub.o
root@freecho:/opt/C/make# make clean
rm -rf  add.o  div1.o  hello.o  mul.o  sub.o
root@freecho:/opt/C/make# ls
add.c  a.out  div1.c  hello.c  m1  m2  makefile  mul.c  sub.c

3个自动变量

$@ :在规则的命令中,表示规则中的目标

$< :在规则的命令中,表示规则中的第一个条件,如果将该变量应用于 模式规则 中,它可将依赖列表中的依赖依次取出,套用规则模式

$^ :在规则的命令中,表示规则中的所有依赖条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复

makefile文件4

src = $(wildcard *.c)               # src = add.c sub.c mul.c div1.c
obj = $(patsubst %.c, %.o, $(src))  # obj = add.o sub.o mul.o div1.o

ALL:a.out

hell.o:hello.c
        gcc -c $< -o $@
add.o:add.c
        gcc -c $< -o $@
sub.o:sub.c
        gcc -c $< -o $@
mul.o:mul.c
        gcc -c $< -o $@
div1.o:div1.c
        gcc -c $< -o $@
a.out: $(obj)
        gcc $^ -o $@

clean:
        -rm -rf $(obj)

模式规则

编译 .c 文件 生成 .o 文件

%.o:%.c
        gcc -c $< -o $@

makefile文件5

src = $(wildcard *.c)               # src = add.c sub.c mul.c div1.c
obj = $(patsubst %.c, %.o, $(src))  # obj = add.o sub.o mul.o div1.o

ALL:a.out

a.out: $(obj)
        gcc $^ -o $@

%.o:%.c
        gcc -c $< -o $@

clean:
        -rm -rf $(obj) a.out

拓展

静态模式规则

表示对哪一个依赖条件套用这个规则

$(obj):%.o:%.c
        gcc -c $< -o $@

伪目标

声明了 .PHONY: clean ALL,它告诉 Make 不会去检查是否存在名为 cleanALL 的文件,而是直接执行它们后面的命令块。这样,运行 make cleanmake ALL 时,Make 将执行相应的命令块。

.PHONY: clean ALL

最终形态 makefile

src = $(wildcard *.c)
obj = $(patsubst %.c, %.o, $(src))

myArgs = -Wall -g

ALL:a.out

a.out: $(obj)
        gcc $^ -o $@ $(myArgs)

$(obj):%.o:%.c
        gcc -c $< -o $@ $(myArgs)

clean:
        -rm -rf $(obj) a.out

.PHONY: clean ALL

相关参数

-n:模拟执行make、make clean 命令
-f:指定文件执行 make 命令

相关链接

教程视频:Linux系统编程_哔哩哔哩_bilibili

Linux系列文章:Linux – Echo (liveout.cn)

Linux基础命令:Linux学习资料分享 – Echo (liveout.cn)

Vim配置:Linux学习资料分享 – Echo (liveout.cn)

GitHub仓库,包含教程讲义、代码以及笔记:https://github.com/PGwind/LinuxSystem

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值