文章目录
- Ⅰ. 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
下非常常用的一种包管理器。主要应用在Fedora
、RedHat
、Centos
等发行版上。
二、查找软件包
通过 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简介
rz
、sz
是 Linux
/Unix
同 Windows
进行 ZModem
文件传输的命令行工具。
rz
(receive Zmodem) 可以很方便的从客户端传文件到服务器,sz
(send Zmodem) 也可以很方便的从服务器传文件到客户端,就算中间隔着跳板机也不影响。
远程文件传输的工具有很多,例如 rz
、sz
、scp
、sftp
、ftp
等。如果环境服务器需要通过跳板机(relay)访问,使用 rz
、sz
传输更为方便。
在 SecureCRT
下的传输协议有 ASCII
、Xmodem
、Ymodem
、Zmodem
4种:
-
ASCII
:这是最快的传输协议,但只能传送文本文件 -
Xmodem
:这种古老的传输协议速度较慢,但由于使用了CRC
错误侦测方法,传输的准确率可高达99.6%
-
Ymodem
:这是Xmodem
的改良版,使用了1024
位区段传送,速度比Xmodem
要快。 -
Zmodem
:Zmodem
采用了串流式(streaming)传输方式,传输速度较快,而且还具有自动改变区段大小和断点续传、快速错误侦测等功能,是目前最流行的文件传输协议
lrzsz
的使用:(需要提前用 yum 安装)
功能:这个工具用于 windows
机器和远端的 Linux
机器通过 XShell
传输文件
-
从
Windows
传到Linux
:-
使用
rz
[ 选项 ] 具体选项可以使用rz -h
进行查阅rz -e # -e 选项会对所有控制字符进行转义
-
直接将要上传到
linux
中的文件拖到xshell
的界面
-
-
从
Linux
到Windows
:使用
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编辑器
vi
和 vim
的区别简单点来说,它们都是多模式编辑器,不同的是 vim
是 vi
的升级版本,它不仅兼容 vi
的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于 xp window
、 mac os
、windows
。下面我们统一按照 vim
来进行讲解!
一、vim 的基本概念
-
正常/普通/命令模式(
Normal mode
):控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入插入模式下,或者到末行模式。 -
插入模式(
Insert mode
):只有在插入模式下,才可以做文字输入,按「ESC
」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。 -
末行模式(
last line mode
):文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift + :
即可进入该模式。
二、vim 的基本操作
三种常见模式的转换关系:
进入 vim
的方法:vim + 文件名
退出 vim
的方法:
:w
(保存当前文件):wq
(输入「wq」,存盘并退出vim):q!
(输入q!,不存盘强制退出vim)
三、vim 命令模式的操作
-
切换为插入模式:
-
按
i
进入插入模式后,从光标当前位置开始输入文字 -
按
a
进入插入模式后,从目前光标所在位置的下一个位置开始输入文字 -
按
o
进入插入模式后,插入新的一行,从行首开始输入文字
-
-
切换回命令模式:
- 按
Esc
键
- 按
-
移动光标:
vim
可以直接用键盘上的光标来上下左右移动,但正规的vim
是用小写英文字母h
、j
、k
、l
,分别控制光标左、下、上、右移一格gg
: 进入到文本开头G
或shift + g
或n + shift + g
: 移动到 文本末端 或 向下移动n
位shift + ^
: 移动到光标所在行的“行首”shift + $
: 移动到光标所在行的“行尾”w
: 光标跳到下个字的开头e
: 光标跳到下个字的字尾b
: 光标回到上个字的开头n + 方向键
: 光标移到该行或上下的第 n 个位置,如:5l,56jctrl + b
: 屏幕往“后”移动一页ctrl + f
: 屏幕往“前”移动一页ctrl + u
: 屏幕往“后”移动半页ctrl + d
: 屏幕往“前”移动半页
-
删除文字:
x
:每按一次,删除光标所在位置的一个字符n + x
:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符X
:大写的X,每按一次,删除光标所在位置的“前面”一个字符n + X
:例如,「20X」表示删除光标所在位置的“前面”20个字符dd
:删除光标所在行n + dd
:从光标所在行开始删除 n 行dd + p
或n + dd + p
:剪切某行或剪切 n 行
-
撤销上一次操作:
u
:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。ctrl + r
: 撤销上一次的撤销
-
复制:
p
:将缓冲区内的字符粘贴到光标所在位置(注意所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能)yy
:复制光标所在行到缓冲区。n + yy
:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。yw
:将光标所在之处到字尾的字符复制到缓冲区中。n + yw
:复制 n 个完整的字符串到缓冲区
-
替换、更改、切换大小写:
shift + ~
:将光标处的大小写互相切换r
:替换光标所在处的字符。n + r
:替换光标所在处的 n 个字符。shift + r (R)
:切换为替换模式,直到按下「ESC」键为止。cw
:更改光标所在处的字到字尾处c + n + w
:例如,「c3w」表示更改3个完整的字符串
四、vim 底行模式的操作命令
在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式。
-
行号:
-
set nu
:在文件中的每一行前面列出行号。 -
set nonu
:取消行号。
-
-
跳到文件中的某一行:
#
:这个符号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15
,再回车,就会跳到文章的第15
行。
-
查找字符:
/ + 关键字
:先按「/」键,再输入想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会 往后 寻找到您要的关键字为止。? + 关键字
:先按「?」键,再输入想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会 往前 寻找到您要的关键字为止。
-
保存文件与退出
vim
:-
w
:在冒号输入字母「w」就可以将文件保存起来 -
q
:按「q」就是退出,如果无法离开 vim,可以在「q」后跟一个「!」强制离开 vim。 -
wq
:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件 -
x!
:保存并退出编辑,仅当文件有修改时会保存,并修改文件时间属性
-
-
不退出
vim
执行命令行命令::! + 命令
:如 「:! gcc test.c」 即可在vim中编译.c文件
-
在
vim
中的分屏:: vs + 文件名
:如在 test.c 中打开或创建一个文件「: vs liren.c 」ctrl + w
:光标在分屏的多屏幕下进行切换
-
批量替换关键字:
: %s/要被修改的关键字/最终修改的关键字/g
:比如将makefile
中的mycmd
修改为mytest
,是%s/mycmd/mytest/g
五、vim 多行注释
vim
中多行注释和多行删除命令,这些命令也是经常用到的一些小技巧,可以大大提高工作效率。
-
多行注释:
1. 首先按esc
进入命令行模式下,按下Ctrl + v
,进入列(也叫区块)模式
2. 在行首使用上下键选择需要注释的多行
3. 按下键盘(大写)I
键,进入插入模式
4. 然后输入注释符(//
、#
等)
5. 最后按下Esc
键(在按下esc
键后,会稍等一会才会出现注释,不要着急~~时间很短的) -
删除多行注释:
- 首先按
esc
进入命令行模式下,按下Ctrl + v
, 进入列模式 - 选定要取消注释的多行
- 按下
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++
一、背景知识
-
预处理(宏定义、文件包含、条件编译、去注释等)
-
编译(生成汇编)
-
汇编(生成机器可识别代码)
-
连接(生成可执行文件或库文件)
二、gcc工作流程
格式: gcc [选项] 要编译的文件 [选项] [目标文件]
- 预处理(
-E
)(生成.i
文件)- 预处理功能主要包括:宏定义、文件包含、条件编译、去注释等
- 预处理指令是以
#
号开头的代码行 - 实例:gcc –E hello.c –o hello.i
- 选项
-E
,该选项的作用是让gcc
在预处理结束后停止编译过程 - 选项
-o
是指目标文件,.i
文件为已经过预处理的C原始程序
- 编译(
-S
)(生成.s
文件)- 编译过程为:扫描程序 --> 语法分析 --> 语义分析 --> 源代码优化 --> 代码生成器 --> 目标代码优化
- 扫描程序进行词法分析,从左向右,从上往下扫描源程序字符,识别出各个单词,确定单词类型
- 语法分析是根据语法规则,将输入的语句构建出分析树,或者语法树,也就是我们提到的分析树
parse tree
或者语法树syntax tree
- 语义分析是根据上下文分析函数返回值类型是否对应这种语义检测,可以理解语法分析就是描述一个句子主宾谓是否符合规则,而语义用于检测句子的意思是否是正确的
- 在这个阶段中,
gcc
首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc
把代码翻译成汇编语言。 - 用户可以使用
-S
选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码,生成的后缀文件为.s
- 实例:gcc –S hello.i –o hello.s
- 编译过程为:扫描程序 --> 语法分析 --> 语义分析 --> 源代码优化 --> 代码生成器 --> 目标代码优化
- 汇编(
-c
)(生成.o
文件)- 汇编阶段是把编译阶段生成的
.s
文件转成目标文件 - 可使用选项
-c
就可看到汇编代码已转化为.o
的二进制目标代码 - 实例: gcc –c hello.s –o hello.o
- 目标文件也称为 可重定向目标文件,该文件不可被执行,还得经过链接才能完成重定向
- 汇编阶段是把编译阶段生成的
- 链接(只需要
-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
: 文件输出到指定文件-I
(include
):后面跟着 头文件的绝对路径,让gcc
指定到该路径去**链接头文件**-L
(link
):后面跟着 库的绝对路径,让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 debug
或 objdump -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 + d
或quit
l + 行号
:显示binFile
源代码,接着上次的位置往下列,每次列10
行l + 函数名
:列出某个函数的源代码
上述的
l
就是list
的意思,可以将其替换为list
-
r
(run
):运行程序,从开始连续而非单步执行程序 -
n
(next
):单条执行,逐过程 -
s
(step
):进入函数调用,逐语句 -
c
(continue
):直接跳转到下一个断点 -
until 行号
:跳至某行 -
finish
:直接运行完毕对应的函数 -
b + 行号
(break
):在某一行设置断点 -
b + 函数名
:在某个函数开头设置断点 -
i b
(infomation
): 查看断点信息 -
d b
(delete
): 删除所有断点 -
d b + 行号
: 删除行号为n
的断点 -
disable b
(breakpoints
): 禁用断点 -
enable b
: 启用断点 -
p + 变量或表达式
(print
):打印表达式的值,通过表达式可以修改变量的值或者调用函数 -
display 变量名
:跟踪查看一个变量,每次停下来都显示它的值,相当于vs中的监视 -
undisplay 变量名
:取消对先前设置的那些变量的跟踪 -
bt
(breaktrace
):查看各级函数调用及参数,相当于vs
中的调用堆栈窗口 -
i locals
(info
):查看当前栈帧局部变量的值 -
set 变量名=n
:修改变量的值为n
-
shell + shell指令
:在gdb
界面使用shell
指令
Linux项目自动化构建工具–make/Makefile
一、背景
会不会写 makefile
,从一个侧面说明了一个人是否具备完成大型工程的能力。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile
定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作!
makefile
带来的好处就是“自动化编译”,一旦写好,只需要一个 make
命令,整个工程完全自动编译,极大的提高了软件开发的效率。
而 make
是一个命令工具,是一个解释 makefile
中指令的命令工具,一般来说,大多数的 IDE
都有这个命令,比如:Delphi
的 make
,Visual C++
的 nmake
,Linux
下 GNU
的 make
。可见,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
命令。此时:
-
make
会在当前目录下找名字叫Makefile
或makefile
的文件。 -
如果找到,它会找文件中的第一个目标文件(
target
),在上面的例子中,他会找到mytmp
这个文件,并把这个文件作为最终的目标文件。 -
如果
mytmp
文件不存在,或是mytmp
所依赖的后面的tmp.o
文件的文件修改时间要比mytmp
这个文件新(可以用touch
命令查看),那么他就会执行后面所定义的命令来生成mytmp
这个文件。 -
如果
mytmp
所依赖的tmp.o
文件不存在,那么make
会在当前文件中找目标为tmp.o
文件的依赖性,如果找到则再根据那一个规则生成tmp.o
文件。(这有点像一个堆栈的过程) -
当然,你的
.c
文件和.h
文件是存在的啦,于是make
会生成tmp.o
文件,然后再用tmp.o
文件声明make
的终极任务,也就是执行文件mytmp
了。 -
这就是整个
make
的依赖性,make
会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。 -
在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么
make
就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make
根本不理。 -
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
中的伪对象表示对象名称并不代表真正的文件名,与实际存在的同名文件没有相互关系,因此伪对象不管同名目标文件是否存在都会执行对应的生成指令。伪对象的作用有两个:- 使目标对象无论如何都要重新生成
- 并不生成目标文件,而是为了执行一些指令
一个问题:为什么如果源文件没有修改,make 后不会产生新的可执行文件呢?怎么证明?
首先我们得先了解一个东西,就是文件的一些时间问题:
一个文件的时间分为三种:Access
、Modify
、Change
,这三种分别有什么区别呢?
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、死代码删除是编译最优化技术,指的是移除根本执行不到的代码,或者对程序运行结果没有影响的代码,而并不是删除被注释的代码