Linux系统——Makefile、gdb和文件IO

一、Makefile

1.基本语法

makefile由一组规则组成,规则如下:

目标: 依赖

(tab)命令

makefile基本规则三要素:

  • 目标: 要生成的目标文件
  • 依赖: 目标文件由哪些文件生成
  • 命令: 通过执行该命令由依赖文件生成目标

比如:

main:main.c fun1.c fun2.c sum.c
    gcc -o main main.c fun1.c fun2.c sum.c -I./

基本原则:要想生成目标,检查规则中的所有依赖文件是否存在,如果有的依赖文件不存在,则向下搜索规则,看是否有生成该依赖文件的规则,如果有规则用来生成该依赖,则执行规则中的命令生成依赖文件,如果没有规则用来生成该依赖文件,则报错。如果依赖中的文件都存在,检查规则中的目标是否需要更新时,必须先检查它的所有依赖,依赖中的任何一个被更新,则目标必须更新。检查规则是哪个时间大哪个最新。比如:目标的时间>依赖的时间,则不更新;目标的时间<依赖的时间,则更新。

2.使用变量

普通变量:定义直接用=,使用的时候用$(变量名)

自带变量:Makefile提供的变量:全部大写

  CC = gcc

  CPPFLAGS:C预处理的选项 -I

  CFLAGS:C编译器的选项 -Wall -g -c

  LDFLAGS:链接器选项-L -I

自动变量:

  • $@: 表示规则中的目标
  • $<: 表示规则中的第一个条件
  • $^: 表示规则中的所有条件, 组成一个列表, 以空格隔开, 如果这个列表中有重复的项则消除重复项。

3.Makefile函数

1. wildcard – 查找指定目录下的指定类型的文件
src=$(wildcard *.c)  //找到当前目录下所有后缀为.c的文件,赋值给src
2. patsubst – 匹配替换
obj=$(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
src=$(wildcard *.c) 等价于src=main.c fun1.c fun2.c sum.c
obj=$(patsubst %.c,%.o, $(src))等价于obj=main.o fun1.o fun2.o sum.o

4.Makefile清除操作

用途: 清除编译生成的中间.o文件和最终目标文件

make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令, 解决方案:

  • 伪目标声明:

  .PHONY:clean

  声明目标为伪目标之后, makefile将不会检查该目标是否存在或者该目标是否需要更新

clean命令中的特殊符号:

  • “-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”

      rm -f: 强制执行, 比如若要删除的文件不存在使用-f不会报错

  • “@”不显示命令本身, 只显示结果。如:“@echo clean done"

其它

  – make 默认执行第一个出现的目标, 可通过make dest指定要执行的目标

  – make -f : -f执行一个makefile文件名称, 使用make执行指定的makefile: make -fmainmak

 

命令行直接make执行,默认执行第一个目标也就是main,如果第二次编译需要删除前一次,执行make clean

如果当前路径下有不止一个Makefile,使用make -f +Makefile文件名的形式来执行这个Makefile文件。

二、gdb调试

gdb是gcc的调试工具,功能强大,可以完成四方面功能:

  1.启动程序,按照自定义的要求随心所欲的运行程序

  2.可让被调试的程序在你所指定的断点处停住

  3.当程序被停住,可以检查此时程序中发生的事

  4.动态的改变你程序的执行环境

gdb调试在单线程的时候可以使用,多线程的时候很麻烦,还是通过打印信息的形式调试。

特别注意,使用gdb调试的时候需要加-g参数。

三、文件IO

Linux的内核使用C语言写的。

1.c语言操作文件相关问题:

使用fopen函数打开一个文件, 返回一个FILE* fp, 这个指针指向的结构体有三个重要的成员.

  • 文件描述符: 通过文件描述可以找到文件的inode, 通过inode可以找到对应的数据块
  • 文件指针: 读和写共享一个文件指针, 读或者写都会引起文件指针的变化
  • 文件缓冲区: 读或者写会先通过文件缓冲区, 主要目的是为了减少对磁盘的读写次数, 提高读写磁盘的效率.

2.库函数和系统函数的关系

库函数和系统函数是调用和被调用的关系,库函数是系统函数的进一步封装。

系统调用:是操作系统实现并提供给外部应用程序的编程接口。

3.虚拟地址空间

Linux每一个运行的程序(进程)操作系统都会为其分配一个0~4G的地址空间(虚拟地址空间)。

0~3G用户区,3G~4G内核区:

 

操作系统管理内核空间,用户不能操作。

内核区很重重要的一个就是进程管理,进程管理中有一个区域就是PCB,本质是一个结构体,PCB中有一个文件描述符表,其中存放着进程打开的文件描述符,涉及到的文件IO操作都会用到这个文件描述符。

默认情况程序启动至少打开了三个文件:标准输入0、标准输出1和标准错误输出2。

每打开一个新的文件,占用一个新的描述符,而且是空闲的最小的一个文件描述符。

一个进程最多可以打开0~1023总共1024个文件,这取决于文件描述符表的大小。

一个进程有一个文件描述符表:1024

  • 前三个被占用, 分别是STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO
  • 文件描述符作用:通过文件描述符找到inode, 通过inode找到磁盘数据块.

虚拟地址空间——>内核区——>PCB——>文件描述表——>文件描述符——>文件IO操作使用文件描述符。

 

posted @ 2021-02-26 20:04  不妨不妨,来日方长  阅读(188)  评论(0编辑  收藏  举报