【Linux入门】2w字详解yum、vim、gcc/g++、gdb、makefile以及进度条小程序

文章目录

  • Ⅰ. Linux 软件包管理器 yum
      • 一、什么是软件包?
      • 二、查找软件包
      • 三、安装与卸载软件包
  • 拓展:lrzsz简介
  • 拓:配置 yum 源路径的方法
  • Ⅱ. Linux开发工具
    • vim编辑器
      • 一、vim 的基本概念
      • 二、vim 的基本操作
      • 三、vim 命令模式的操作
      • 四、vim 底行模式的操作命令
      • 五、vim 多行注释
      • 简单的 vim 配置
    • gcc/g++编译器使用
      • 安装
      • 一、背景知识
      • 二、gcc工作流程
      • 在这里涉及到一个重要的概念:函数库
      • 静态库和动态库
      • 三、gcc 选项
    • gdb调试器
      • 一、背景
      • 二、怎么查看文件是否可以 debug
      • 三、gdb 的使用
    • Linux项目自动化构建工具--make/Makefile
      • 一、背景
      • 二、依赖关系
      • 三、依赖方法
      • 四、工作原理
      • 五、项目清理
      • 补充几个符号
      • 补充的知识点
      • 一个问题:为什么如果源文件没有修改,make 后不会产生新的可执行文件呢?怎么证明?
  • 学习Linux 第一个程序:进度条与倒计时
    • 行缓冲区概念(具体的后面 I/O 部分还详细的讲解)
    • \r 与 \n 的区别
  • 注意事项

在这里插入图片描述

Ⅰ. Linux 软件包管理器 yum

一、什么是软件包?

​ 在 Linux 下安装软件, 一个通常的办法是 下载到程序的源代码, 并进行编译, 得到可执行程序。但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成 软件包(可以理解成 windows 上的安装程序) 放在一个服务器上,通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装

在这里插入图片描述

  • 软件包 相当于 App, 而 软件包管理器 相当于 “应用商店”。 而 yum 就是 centos 的软件包管理器。

  • yum(Yellow dog Updater, Modifified)是 Linux 下非常常用的一种包管理器。主要应用在 FedoraRedHatCentos 等发行版上。

二、查找软件包

​ 通过 yum list 可命令以罗列出当前一共有哪些软件包. 由于包的数目可能非常之多, 这里我们需要使用 grep 命令 只筛选出我们关注的包. 例如:

yum list | grep lrzsz 

​ 结果如下:

lrzsz.x86_64 						0.12.20-36.el7				 @base

在这里插入图片描述

  • 软件包名称:主版本号-次版本号-源程序发行号-软件包的发行号-主机平台-cpu架构。
  • x86_64:后缀表示 64 位系统的安装包,i686 后缀表示 32 位系统安装包,选择包时要和系统匹配。
  • el7:表示操作系统发行版的版本。el7 表示的是 centos7/redhat7
  • base:表示的是 “软件源” 的名称,类似于 “小米应用商店”,“华为应用商店” 这样的概念。

​ 补充内容:

  • yum 工具在每次安装指定软件包的时候,都会检测源服务器上的软件包信息,为了便捷不用每次都去搜索软件包信息,因此使用 yum makecache 将软件包信息缓存到本地,使用 yum clean all 清理老旧的缓存信息

  • yum search:搜索包含指定关键字的软件包

  • yum -y update:升级所有包同时,也升级软件和系统内核;

  • yum -y upgrade:只升级所有包,不升级软件和系统内核,软件和内核保持原样

三、安装与卸载软件包

sudo yum install -y lrzsz  # 安装的语法(加了-y后默认同意)

sudo yum remove lrzsz      # 删除的语法

yum 会自动找到都有哪些软件包需要下载, 这时候敲 y 确认安装。出现 complete 字样, 说明安装完成.

注意事项:

  • 安装软件时由于需要向系统目录中写入内容, 一般需要 sudo 或者切到 root 账户下才能完成.
  • yum 安装软件只能一个装完了再装另一个. 正在 yum 安装一个软件的过程中, 如果再尝试用 yum 安装另外一个软件, yum 会报错.

拓展:lrzsz简介

rzszLinux/UnixWindows 进行 ZModem 文件传输的命令行工具。

rz (receive Zmodem) 可以很方便的从客户端传文件到服务器,sz (send Zmodem) 也可以很方便的从服务器传文件到客户端,就算中间隔着跳板机也不影响。

​ 远程文件传输的工具有很多,例如 rzszscpsftpftp 等。如果环境服务器需要通过跳板机(relay)访问,使用 rzsz 传输更为方便。

​ 在 SecureCRT 下的传输协议有 ASCIIXmodemYmodemZmodem 4种:

  1. ASCII:这是最快的传输协议,但只能传送文本文件

  2. Xmodem:这种古老的传输协议速度较慢,但由于使用了 CRC 错误侦测方法,传输的准确率可高达 99.6%

  3. Ymodem:这是 Xmodem 的改良版,使用了 1024 位区段传送,速度比 Xmodem 要快。

  4. ZmodemZmodem 采用了串流式(streaming)传输方式,传输速度较快,而且还具有自动改变区段大小和断点续传、快速错误侦测等功能,是目前最流行的文件传输协议

lrzsz 的使用:(需要提前用 yum 安装)

功能:这个工具用于 windows 机器和远端的 Linux 机器通过 XShell 传输文件

  • Windows 传到 Linux

    1. 使用 rz [ 选项 ] 具体选项可以使用 rz -h 进行查阅

      rz -e    # -e 选项会对所有控制字符进行转义
      
    2. 直接将要上传到 linux 中的文件拖到 xshell 的界面

  • LinuxWindows

    使用 sz [ 选项 ] 文件名

    sz t1.txt
    

拓:配置 yum 源路径的方法

yum 的配置文件:/etc/yum.conf

[liren@VM-8-2-centos tmp]$ ls /etc/yum.conf     #查看yum的配置文件
/etc/yum.conf
[liren@VM-8-2-centos tmp]$ vim /etc/yum.conf	#使用vim打开yum的配置文件

在这里插入图片描述

yum 源的存放地点:/etc/yum.repos.d

在这里插入图片描述

​ 若进入到 CentOS-Base.repo 中:

[liren@VM-8-2-centos tmp]$ vim /etc/yum.repos.d/CentOS-Base.repo  #使用vim进入CentOS-Base.repo

在这里插入图片描述

​ 若无这些配置,可到百度查找:centos7 配置国内yum源进行配置

Ⅱ. Linux开发工具

vim编辑器

在这里插入图片描述

vivim 的区别简单点来说,它们都是多模式编辑器,不同的是 vimvi 的升级版本,它不仅兼容 vi 的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于 xp windowmac oswindows。下面我们统一按照 vim 来进行讲解!

一、vim 的基本概念

  • 正常/普通/命令模式Normal mode):控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入插入模式下,或者到末行模式。

  • 插入模式Insert mode):只有在插入模式下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。

  • 末行模式last line mode):文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift + : 即可进入该模式

二、vim 的基本操作

​ 三种常见模式的转换关系:

在这里插入图片描述

进入 vim 的方法:vim + 文件名

退出 vim 的方法:

  • :w (保存当前文件)
  • :wq (输入「wq」,存盘并退出vim)
  • :q! (输入q!,不存盘强制退出vim)

三、vim 命令模式的操作

  1. 切换为插入模式

    • i 进入插入模式后,从光标当前位置开始输入文字

    • a 进入插入模式后,从目前光标所在位置的下一个位置开始输入文字

    • o 进入插入模式后,插入新的一行,从行首开始输入文字

  2. 切换回命令模式

    • Esc
  3. 移动光标

    • vim 可以直接用键盘上的光标来上下左右移动,但正规的 vim 是用小写英文字母 hjkl,分别控制光标左、下、上、右移一格
    • gg: 进入到文本开头
    • Gshift + gn + shift + g: 移动到 文本末端向下移动n
    • shift + ^: 移动到光标所在行的“行首”
    • shift + $: 移动到光标所在行的“行尾”
    • w: 光标跳到下个字的开头
    • e: 光标跳到下个字的字尾
    • b: 光标回到上个字的开头
    • n + 方向键: 光标移到该行或上下的第 n 个位置,如:5l,56j
    • ctrl + b: 屏幕往“后”移动一页
    • ctrl + f: 屏幕往“前”移动一页
    • ctrl + u: 屏幕往“后”移动半页
    • ctrl + d: 屏幕往“前”移动半页
  4. 删除文字

    • x:每按一次,删除光标所在位置的一个字符
    • n + x:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符
    • X:大写的X,每按一次,删除光标所在位置的“前面”一个字符
    • n + X:例如,「20X」表示删除光标所在位置的“前面”20个字符
    • dd:删除光标所在行
    • n + dd:从光标所在行开始删除 n 行
    • dd + pn + dd + p:剪切某行或剪切 n 行
  5. 撤销上一次操作

    • u:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
    • ctrl + r: 撤销上一次的撤销
  6. 复制

    • p:将缓冲区内的字符粘贴到光标所在位置(注意所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能)
    • yy:复制光标所在行到缓冲区。
    • n + yy:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
    • yw:将光标所在之处到字尾的字符复制到缓冲区中。
    • n + yw:复制 n 个完整的字符串到缓冲区
  7. 替换、更改、切换大小写

    • shift + ~:将光标处的大小写互相切换
    • r:替换光标所在处的字符。
    • n + r:替换光标所在处的 n 个字符。
    • shift + r (R):切换为替换模式,直到按下「ESC」键为止。
    • cw:更改光标所在处的字到字尾处
    • c + n + w:例如,「c3w」表示更改3个完整的字符串

四、vim 底行模式的操作命令

在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式。

  1. 行号

    • set nu:在文件中的每一行前面列出行号。

    • set nonu:取消行号。

  2. 跳到文件中的某一行

    • #:这个符号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字 15,再回车,就会跳到文章的第 15 行。
  3. 查找字符

    • / + 关键字:先按「/」键,再输入想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会 往后 寻找到您要的关键字为止。
    • ? + 关键字:先按「?」键,再输入想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会 往前 寻找到您要的关键字为止。
  4. 保存文件与退出vim

    • w:在冒号输入字母「w」就可以将文件保存起来

    • q:按「q」就是退出,如果无法离开 vim,可以在「q」后跟一个「!」强制离开 vim。

    • wq:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件

    • x!:保存并退出编辑,仅当文件有修改时会保存,并修改文件时间属性

  5. 不退出 vim 执行命令行命令

    • :! + 命令:如 「:! gcc test.c」 即可在vim中编译.c文件
  6. vim 中的分屏

    • : vs + 文件名:如在 test.c 中打开或创建一个文件「: vs liren.c 」
    • ctrl + w:光标在分屏的多屏幕下进行切换
  7. 批量替换关键字

    • : %s/要被修改的关键字/最终修改的关键字/g:比如将 makefile 中的 mycmd 修改为 mytest,是 %s/mycmd/mytest/g

五、vim 多行注释

vim 中多行注释和多行删除命令,这些命令也是经常用到的一些小技巧,可以大大提高工作效率。

  • 多行注释
    1. 首先按 esc 进入命令行模式下,按下 Ctrl + v,进入列(也叫区块)模式
    2. 在行首使用上下键选择需要注释的多行
    3. 按下键盘(大写)I 键,进入插入模式
    4. 然后输入注释符( //# 等)
    5. 最后按下 Esc 键(在按下 esc 键后,会稍等一会才会出现注释,不要着急~~时间很短的)

  • 删除多行注释

    1. 首先按 esc 进入命令行模式下,按下 Ctrl + v, 进入列模式
    2. 选定要取消注释的多行
    3. 按下 x 或者 d (注意:如果是 // 注释,那需要执行两次该操作,如果是 # 注释,一次即可)
  • 多行删除

    • 首先在命令模式下,输入 :set nu 显示行号
    • 通过行号确定你要删除的行
    • 命令输入 :32,65d,回车键,然后 32-65 行就被删除了
    • 如果无意中删除错了,可以使用 u 键恢复(命令模式下)

简单的 vim 配置

  • 在目录 /etc/ 下面,有个名为 vimrc 的文件,这是系统中公共的 vim 配置文件,对所有用户都有效。
  • 而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为:.vimrc。例如,/root 目录下,通常已经存在一个 .vimrc 文件,如果不存在,则创建即可
  • 打开自己目录下的 .vimrc 文件,执行 vim .vimrc

注:直接到百度查找vim配置项,做为了解即可。 —> 一套完整的配置文件(直接安装即可)

在这里插入图片描述

gcc/g++编译器使用

安装

sudo yum install gcc
sudo yum install gcc-c++

一、背景知识

  1. 预处理(宏定义、文件包含、条件编译、去注释等)

  2. 编译(生成汇编)

  3. 汇编(生成机器可识别代码)

  4. 连接(生成可执行文件或库文件)

二、gcc工作流程

格式: gcc [选项] 要编译的文件 [选项] [目标文件]

  1. 预处理-E)(生成 .i 文件)
    • 预处理功能主要包括:宏定义、文件包含、条件编译、去注释等
    • 预处理指令是以 # 号开头的代码行
    • 实例:gcc –E hello.c –o hello.i
    • 选项 -E,该选项的作用是让 gcc 在预处理结束后停止编译过程
    • 选项 -o 是指目标文件,.i 文件为已经过预处理的C原始程序
  2. 编译-S)(生成 .s 文件)
    • 编译过程为:扫描程序 --> 语法分析 --> 语义分析 --> 源代码优化 --> 代码生成器 --> 目标代码优化
      • 扫描程序进行词法分析,从左向右,从上往下扫描源程序字符,识别出各个单词,确定单词类型
      • 语法分析是根据语法规则,将输入的语句构建出分析树,或者语法树,也就是我们提到的分析树 parse tree 或者语法树 syntax tree
      • 语义分析是根据上下文分析函数返回值类型是否对应这种语义检测,可以理解语法分析就是描述一个句子主宾谓是否符合规则,而语义用于检测句子的意思是否是正确的
    • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
    • 用户可以使用 -S 选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码,生成的后缀文件为 .s
    • 实例:gcc –S hello.i –o hello.s
  3. 汇编-c)(生成 .o 文件)
    • 汇编阶段是把编译阶段生成的 .s 文件转成目标文件
    • 可使用选项 -c 就可看到汇编代码已转化为 .o 的二进制目标代码
    • 实例: gcc –c hello.s –o hello.o
    • 目标文件也称为 可重定向目标文件,该文件不可被执行,还得经过链接才能完成重定向
  4. 链接(只需要 -o 选择目标文件)(生成可执行文件)
    • 在成功编译之后,就进入了链接阶段
    • 实例:gcc hello.o –o hello

在这里涉及到一个重要的概念:函数库

​ 我们的 C 程序中,并没有定义 printf 的函数实现,且在预编译中包含的 stdio.h 中也只有该函数的声明,而没有定义函数的实现,那么是在哪里实现了 printf 函数的呢?

​ 答案是:linux 系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径 /usr/lib 下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数 printf 了,而这也就是链接的作用。

静态库和动态库

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了,其后缀名一般为 .a

  • 动态库是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为 .so,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示:gcc 默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证:

    在这里插入图片描述

此外,系统默认会自动携带动态库,而不存在静态库,如果我们需要使用静态库链接的话,需要自己手动安装:

  • 对于c:sudo yum install -y glibc-static
  • 对于c++:sudo yum install -y libstdc++-static

三、gcc 选项

  • -E: 只激活 预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
  • -S编译 到汇编文件,而不进行汇编和链接
  • -c汇编 到二进制目标代码
  • -o: 文件输出到指定文件
  • -Iinclude):后面跟着 头文件的绝对路径,让 gcc 指定到该路径去**链接头文件**
  • -Llink):后面跟着 库的绝对路径,让 gcc 指定到该路径去**链接库**
  • -l:后面跟着 库的名称,指定链接某一个库。(注意这里的库名称要去掉前缀和后缀
  • -D: 宏的命令行定义,多用于 条件编译中的调试
  • -static: 此选项对生成的文件采用静态链接
  • -g: 生成 调试程序
  • -std=c99-std=gnu99:用指定标准来生成可执行文件
  • -w: 不生成任何警告信息
  • -Wall: 生成所有警告信息
  • -shared: 此选项将 尽量使用动态库,所以生成文件比较小,但是需要系统有动态库
  • 四个优化级别:
    • -O0:该选项表示 禁止所有优化,生成的代码与源代码完全一致,主要用于调试目的
    • -O1:该选项表示启用 基本优化,是默认选项。如删除没有用到的代码、简单的常量折叠和复写、函数内联等。这些优化不会对编译时间和代码大小产生太大的影响,但可以提高程序的执行速度
    • -O2:该选项启用 更多的优化,包括循环展开、函数调用的参数传递寄存器化、优化算术运算等。这些优化会对编译时间和代码大小产生一定的影响,但可以进一步提高程序的执行速度
    • -O3:该选项启用 最高级别的优化,包括自动向量化、函数内联、强制内联等。这些优化可能会对编译时间和代码大小产生较大的影响,但也可以进一步提高程序的执行速度
    • 注意:gcc 的优化级别越高,生成的代码质量和执行速度都会越好,但编译时间和代码大小也会相应地增加。因此,我们需要根据具体情况选择适当的优化级别

gdb调试器


一、背景

  • 程序的发布方式有两种,debug 模式和 release 模式
  • Linux gcc/g++ 生成的二进制程序,默认是 release 模式
  • 要使用 gdb 调试,必须在编译指令中加上 -g 选项

二、怎么查看文件是否可以 debug

​ 用下面的命令即可,如果可以 debug,则会显示 debug 相关的一些信息,否则没有相关信息:objdump --syms your-binary | grep debugobjdump -t your-binary | grep debug,如下所示:

[liren@VM-8-2-centos tmp1]$ objdump --syms mytmp | grep debug   #该文件可以debug所以会出现以下这些文件
0000000000000000 l    d  .debug_aranges	0000000000000000              .debug_aranges
0000000000000000 l    d  .debug_info	0000000000000000              .debug_info
0000000000000000 l    d  .debug_abbrev	0000000000000000              .debug_abbrev
0000000000000000 l    d  .debug_line	0000000000000000              .debug_line
0000000000000000 l    d  .debug_str	0000000000000000              .debug_str

三、gdb 的使用

  • 退出ctrl + dquit
  • l + 行号显示 binFile 源代码,接着上次的位置往下列,每次列 10
  • l + 函数名:列出某个函数的源代码

上述的 l 就是 list 的意思,可以将其替换为 list

  • rrun):运行程序,从开始连续而非单步执行程序

  • nnext):单条执行,逐过程

  • sstep):进入函数调用,逐语句

  • ccontinue):直接跳转到下一个断点

  • until 行号跳至某行

  • finish:直接运行完毕对应的函数

  • b + 行号break):在某一行设置断点

  • b + 函数名在某个函数开头设置断点

  • i binfomation): 查看断点信息

  • d bdelete): 删除所有断点

  • d b + 行号删除行号为 n 的断点

  • disable bbreakpoints): 禁用断点

  • enable b启用断点

  • p + 变量或表达式print):打印表达式的值,通过表达式可以修改变量的值或者调用函数

  • display 变量名跟踪查看一个变量,每次停下来都显示它的值,相当于vs中的监视

  • undisplay 变量名:取消对先前设置的那些变量的跟踪

  • btbreaktrace):查看各级函数调用及参数,相当于 vs 中的调用堆栈窗口

  • i localsinfo):查看当前栈帧局部变量的值

  • set 变量名=n修改变量的值为 n

  • shell + shell指令:在 gdb 界面使用 shell 指令

Linux项目自动化构建工具–make/Makefile

一、背景

​ 会不会写 makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。

​ 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作!

makefile 带来的好处就是“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。

​ 而 make 是一个命令工具,是一个解释 makefile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:DelphimakeVisual C++nmakeLinuxGNUmake。可见,makefile 都成为了一种在工程方面的编译方法。

​ 总结起来就是:make 是一条命令,makefile 是一个文件,两个搭配使用,完成项目自动化构建

​ 实例:

mytmp:tmp.c       # 其中 :前面的是依赖关系中的目标文件,而 :后面的是依赖关系中的依赖文件列表
 	gcc -o tmp.c tmp.c   # 这行命令表示依赖方法

.PHONY:clean      # 用.PHONY修饰,代表了伪目标
clean:
    rm -f mytmp 

二、依赖关系

​ 上面的例子中,mytmp 文件就依赖于 tmp.c 文件

在这里插入图片描述

如果是以这个为例子的话,其中:

  • mytmp 依赖于 tmp.o
  • tmp.o 依赖于 tmp.s
  • tmp.s 依赖于 tmp.i
  • tmp.i 依赖于 tmp.c

这样子相当于上面例子的 mytmp 依赖于 tmp.c而我们一般操作时候也以 mytmp 依赖于 tmp.c 为主,更加简洁

三、依赖方法

​ 上面例子中的 gcc -o mytmp tmp.c 就是依赖方法!

四、工作原理

make 是如何工作的,在默认的方式下,也就是我们只输入 make 命令。此时:

  1. make 会在当前目录下找名字叫 Makefilemakefile 的文件

  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到 mytmp 这个文件,并把这个文件作为最终的目标文件

  3. 如果 mytmp 文件不存在,或是 mytmp 所依赖的后面的 tmp.o 文件的文件修改时间要比 mytmp 这个文件新(可以用 touch 命令查看),那么他就会执行后面所定义的命令来生成 mytmp 这个文件。

  4. 如果 mytmp 所依赖的 tmp.o 文件不存在,那么 make 会在当前文件中找目标为 tmp.o文件的依赖性如果找到则再根据那一个规则生成 tmp.o 文件。(这有点像一个堆栈的过程)

  5. 当然,你的 .c 文件和 .h 文件是存在的啦,于是 make 会生成 tmp.o 文件然后再用 tmp.o 文件声明 make 的终极任务,也就是执行文件 mytmp

  6. 这就是整个 make 的依赖性make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件

  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么 make 就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make 根本不理。

  8. make 只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦

五、项目清理

工程是需要被清理的,像 clean 这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过我们可以显示要 make 执行。即命令 make clean,以此来清除所有的目标文件,以便重编译。

​ 但是一般我们这种 clean 的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的*

​ 可以将我们的 hello 目标文件声明成伪目标,测试一下:

在这里插入图片描述

补充几个符号

  • $@:表示依赖关系中的目标文件
  • $^ :表示依赖关系中的依赖文件列表
  • $< :表示依赖关系中的第一个依赖文件

举例:

mytest:test.o main.o
	gcc -o $@ $^
test.o:test.c
	gcc -c $<
main.o:main.c
	gcc -c $<

.PHONY:clean
clean:
	rm -f *.o mytest

在这里插入图片描述

补充的知识点

  • makefile 文件中,保存了编译器和链接器的参数选项,并且描述了所有源文件之间的关系。make 程序会读取 makefile 文件中的数据,然后根据规则调用编译器,汇编器,链接器产生最后的输出,即 makefile文件保存了编译器和连接器的参数选项
  • Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释
    • 显式规则说明了,如何生成一个或多个目标文件。
    • make 有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写 makefile,比如源文件与目标文件之间的时间关系判断之类
    • makefile 中可以定义变量,当 makefile 被执行时,其中的变量都会被扩展到相应的引用位置上,通常使用 $(var) 表示引用变量
    • 文件指示。包含在一个 makefile 中引用另一个 makefile,类似C语言中的 include
    • 注释,makefile 中可以使用 # 在行首表示行注释
  • 默认的情况下make 命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件
  • make 的执行规则是,只生成所有目标对象中的第一个,当然 make 会根据语法规则,递归生成第一个目标对象的所有依赖对象后再回头生成第一个目标对象,生成后退出。
  • make 在执行 makefile 规则中,根据语法规则,会分析目标对象与依赖对象的时间信息,判断是否在上一次生成后,源文件发生了修改,若发生了修改才需要重新生成
  • makefile 中的伪对象表示对象名称并不代表真正的文件名,与实际存在的同名文件没有相互关系,因此伪对象不管同名目标文件是否存在都会执行对应的生成指令。伪对象的作用有两个:
    1. 使目标对象无论如何都要重新生成
    2. 并不生成目标文件,而是为了执行一些指令

一个问题:为什么如果源文件没有修改,make 后不会产生新的可执行文件呢?怎么证明?

​ 首先我们得先了解一个东西,就是文件的一些时间问题:

在这里插入图片描述

一个文件的时间分为三种:AccessModifyChange,这三种分别有什么区别呢?

  • Access 表示最后一次访问(不包括改动)文件的时间,当时新版本中优化了,为了减少频繁的改变时间带来的负载,新版本将其设为多次访问后才会修改 Access 的时间,而不是一次!
  • Modify 表示该 文件内容 被修改的时间
  • Change 表示该 文件属性 被修改的时间(其实也==包括文件权限,大小,属性==等等,因为改变了内容就改变了文件大小,文件属性也就跟着改变了)

​ 把上面的文件时间搞明白之后,我们想一想,一个文件是否需要被重新生成,是不是与其改变的时间有关?

​ 答案是对的!与其 Modify 即修改时间是有关系的,如果源文件没有被改动,其 make 后的可执行文件的 Modify 时间应当是和源文件相同的,所以系统会去比较这两个时间,相同则说明不需要重新生成;若源文件被改动了,那么源文件的 Modify 时间肯定是要比原来 make 的可执行文件要新,所以重新 make 的话,系统去比较时间的时候就会判断源文件被改动了,所以就会重新生成可执行文件!

​ 下面我们用 touch 指令来验证一下:(touch 一个存在的文件,其修改时间是会被改变的~

在这里插入图片描述

学习Linux 第一个程序:进度条与倒计时

行缓冲区概念(具体的后面 I/O 部分还详细的讲解)

  • 行缓冲:输入或输出缓冲区遇到 换行符(\n) 会进行实际 I/O 操作
  • 行刷新:显示器默认遇到 换行符(\n) 会将行缓冲区的内容显示出来
    • 其中显示器默认的 刷新方式是行刷新
  • 若不想被缓冲,得用 fflush() 函数继续刷新

\r 与 \n 的区别

  • \n:换到下一行,称为 换行
  • \r:代表的是光标回到 当前行 的最开始的位置 ,称为 回车

​ 注:根据上面的概念,真正的回车符号应该是 \r ,即回到当前行的起始位置,而我们通常了解的 \n 应该是回车换行符,因为它的功能既包括了回车,也包括了换行,即光标跳转到下一行的起始位置。

​ 所以我们可以用 \r 来进行倒计时功能的实现:

void Count()
{
    int i = 15;
    while(i)
    {
        printf("%-2d\r", i);   //注意这里的\r是关键,并且为了防止十位数变成个位数会多出个0,采取了-2d的写法
        fflush(stdout);   //对屏幕输出流进行刷新,使行缓冲区的内容显示出来
        sleep(1);
        i--;
    }
}

​ 进度条代码:

proc.h
-----------------------------------------------------------
#pragma once 
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#define Max 5
extern void ProcBar();
    
proc.c
------------------------------------------------------------
#include "proc.h"
char style[Max] = {'>','+','$','~','#'};
void ProcBar()
{
    int i = 0;
    char proc[102] = {0};
    const char* tmp = "|/-\\";
    while(i <= 100)
    {
        printf("[%-100s][%d%%][%c]\r", proc, i, tmp[i%4]);     //打印出进度条以及百分比和旋转的状态
        fflush(stdout);  //对屏幕输出流进行刷新,使行缓冲区的内容显示出来
        proc[i++] = style[N];  //记得将每次i对应的数组位置置为'#'
        usleep(50000);
    }
    printf("\n");
}

makefile
------------------------------------------------------------
myproc:main.c proc.c
	gcc -o myproc main.c proc.c -DN=3
.PHONY:clean
clean:
	rm -f *.o myproc

​ 注意这里的 makefile 文件中的 -D 选项其实就是使用命令行来操作宏,这里 -DN 其实就是操作 proc.c 中的 N,让其等于 3,这就很方便!

注意事项

1、关于 yum 的所有操作 必须保证主机(虚拟机)网络畅通 !!!

​ 可以通过 ping 指令验证:

ping www.baidu.com

2、Centos 在任何时刻,只允许一个 yum 进行安装。

3、for 循环的循环控制变量,通常被 cpu 访问频繁,因此如果调度到寄存器中进行访问则不用每次从内存中取出数据,可以提高访问效率

4、强度削弱是指执行时间较短的指令等价的替代执行时间较长的指令,比如 num % 128 与 num & 127 相较,则明显&127更加轻量

5、死代码删除是编译最优化技术,指的是移除根本执行不到的代码,或者对程序运行结果没有影响的代码,而并不是删除被注释的代码

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/957556.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《动•情》组诗浅析

路遇一枚运动的灵魂&#xff0c;邂逅一张随拍的悸动。 (笔记模板由python脚本于2025-01-21 22:59:21创建&#xff0c;本篇笔记适合喜欢诗的coder翻阅) 【学习的细节是欢悦的历程】 Python官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 pyt…

redis-排查命中率降低问题

1.命中率降低带来的问题 高并发系统&#xff0c;当命中率低于平常的的运行情况&#xff0c;或者低于70%时&#xff0c;会产生2个影响。 有大量的请求需要查DB&#xff0c;加大DB的压力&#xff1b;影响redis自身的性能 不同的业务场景&#xff0c;阈值不一样&#xff0c;一般…

Android RTMP直播练习实践

前言&#xff1a;本文只是练习&#xff0c;本文只是练习&#xff0c;本文只是练习&#xff01; 直播的核心就是推流和拉流&#xff0c;我们就以RTMP的协议来实现下推流和拉流&#xff0c;其他的协议等我学习后再来补充 1.推流 1.1搭建流媒体服务器&#xff0c;具体搭建方法请参…

【算法】集合List和队列

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 零&#xff1a;集合&#xff0c;队列的用法 一&#xff1a;字母异位词分组 二&#xff1a;二叉树的锯…

一篇文章学会Milvus【Docker 中运行 Milvus(Windows),Python实现对Milvus的操作,源代码案例,已经解决巨坑】【程序员猫爪】

一篇文章学会Milvus【Docker 中运行 Milvus&#xff08;Windows&#xff09;&#xff0c;Python实现对Milvus的操作&#xff0c;源代码案例&#xff0c;已经解决巨坑】【程序员猫爪】 一、Milvus 是什么&#xff1f;【程序员猫爪】1、Milvus 是一种高性能、高扩展性的向量数据库…

第35天:安全开发-JavaEE应用原生反序列化重写方法链条分析触发类类加载

时间轴&#xff1a; 序列化与反序列化图解&#xff1a; 演示案例&#xff1a; Java-原生使用-序列化&反序列化 Java-安全问题-重写方法&触发方法 Java-安全问题-可控其他类重写方法 Java-原生使用-序列化&反序列化 1.为什么进行序列化和反序列化&#xff1…

Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )

一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化&#xff1a; 文件是存储数据的一种非常基本且重要的方式。通过文件&#xff0c;我们可 以将程序运行时产生的数据永久保存下来&#xff0c;以便将来使用。 跨平台兼容性&#xff1a; 文件是一种通用…

[MCAL]Mcu配置

PostBuild: PreCompile: 选择时钟来源&#xff1b; 选择初始McuInitClock() 函数 电路手册里有晶振频率&#xff0c;如上所示&#xff1b;

(k8s)k8s部署mysql与redis(无坑版)

0.准备工作 在开始之前&#xff0c;要确保我们的节点已经加入网络并且已经准备好&#xff0c;如果没有可以去看我前面发表的踩坑与解决的文章&#xff0c;希望能够帮到你。 1.k8s部署redis 1.1目标 由于我们的服务器资源较小&#xff0c;所以决定只部署一个redis副本&#x…

Python新春烟花

目录 系列文章 写在前面 技术需求 完整代码 下载代码 代码分析 1. 程序初始化与显示设置 2. 烟花类 (Firework) 3. 粒子类 (Particle) 4. 痕迹类 (Trail) 5. 烟花更新与显示 6. 主函数 (fire) 7. 游戏循环 8. 总结 注意事项 写在后面 系列文章 序号直达链接爱…

机器学习09-Pytorch功能拆解

机器学习09-Pytorch功能拆解 我个人是Java程序员&#xff0c;关于Python代码的使用过程中的相关代码事项&#xff0c;在此进行记录 文章目录 机器学习09-Pytorch功能拆解1-核心逻辑脉络2-个人备注3-Pytorch软件包拆解1-Python有参和无参构造构造方法的基本语法示例解释注意事项…

AI在SEO中的关键词优化策略探讨

内容概要 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;正逐渐重塑搜索引擎优化&#xff08;SEO&#xff09;行业。AI技术的快速发展使得SEO策略发生了翻天覆地的变化&#xff0c;特别是在关键词优化方面。关键词优化的基本概念是通过选择与用户搜索意图密…

探索与创作:2024年我在CSDN平台上的成长与突破

文章目录 我与CSDN的初次邂逅初学阶段的阅读CSDN&#xff1a;编程新手的避风港初学者的福音&#xff1a;细致入微的知识讲解考试复习神器&#xff1a;技术总结的“救命指南”曾经的自己&#xff1a;为何迟迟不迈出写博客的第一步兴趣萌芽&#xff1a;从“读”到“想写”的初体验…

element el-table合并单元格

合并 表格el-table添加方法:span-method"” <el-table v-loading"listLoading" :data"SHlist" ref"tableList" element-loading-text"Loading" border fit highlight-current-row :header-cell-style"headClass" …

行业热点丨低空飞行eVTOL的关键技术与发展趋势

本篇主要围绕eVTOL仿真难点和趋势&#xff0c;eVTOL仿真多学科解决方案和当下热门的AI或者机器学习的方法在EVTOL中的应用展开。 eVTOL 研发难点 首先是eVTOL研发难点&#xff0c;区别于上个世纪70年代就已经构型稳定或者技术方法稳定的民航客机&#xff0c;eVTOL到今天尚未有经…

BOBO小火炬全套源码XE修复版2025(火炬天花板二次开发版)

《小火炬全套源码 传奇游戏源码讲解》 小火炬全套源码是一种用于开发经典传奇类游戏的源码包。传奇游戏作为一款经典的多人在线角色扮演游戏&#xff08;MMORPG&#xff09;&#xff0c;有着庞大的用户基础和强大的游戏生态。小火炬全套源码主要提供了从基础架构到核心功能的完…

Flutter:搜索页,搜索bar封装

view 使用内置的Chip简化布局 import package:chenyanzhenxuan/common/index.dart; import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import package:get/get.dart; import package:tdesign_flutter/tdesign_flutter.dart;import i…

网络通信---MCU移植LWIP

使用的MCU型号为STM32F429IGT6&#xff0c;PHY为LAN7820A 目标是通过MCU的ETH给LWIP提供输入输出从而实现基本的Ping应答 OK废话不多说我们直接开始 下载源码 LWIP包源码&#xff1a;lwip源码 -在这里下载 ST官方支持的ETH包&#xff1a;ST-ETH支持包 这里下载 创建工程 …

麒麟操作系统服务架构保姆级教程(十三)tomcat环境安装以及LNMT架构

如果你想拥有你从未拥有过的东西&#xff0c;那么你必须去做你从未做过的事情 之前咱们学习了LNMP架构&#xff0c;但是PHP对于技术来说确实是老掉牙了&#xff0c;PHP的市场占有量越来越少了&#xff0c;我认识一个10年的PHP开发工程师&#xff0c;十年工资从15k到今天的6k&am…

elementUI Table组件实现表头吸顶效果

需求描述 当 table 内容过多的时候&#xff0c;页面上滑滚动&#xff0c;表头的信息也会随着被遮挡&#xff0c;无法将表头信息和表格内容对应起来&#xff0c;需要进行表头吸顶 开始编码&#x1f4aa; 环境&#xff1a;vue2.6、element UI step1&#xff1a; 给el-table__h…