欢迎来到Cefler的博客?
?博客主页:那个传说中的man的主页
?个人专栏:题目解析
?推荐文章:题目大解析3
目录
- ??什么是软件包?
- ??yum
- centos7 yum 换源
- ??Vim编辑器
- 编辑器和IDE概念
- vim基本操作
- 正常模式操作
- vim末行模式操作
- ??Vim中的注释
- ??Vim支持多文件编辑
- ??在sudoers名单(信任名单)上添加用户
- ??Vim 的配置
- vim 一键配置写好的脚本
- ??Linux编译器-gcc/g++使用
- 背景介绍
- gcc
- 静态库和动态库
- 静态链接和动态链接
- linux下安装静态库
- ??Linux项目自动化构建工具-make/Makefile
- 概念
- 依赖关系和依赖方法
- make编译与源文件变化的关系
- @修饰依赖方法
- makefile中的特殊字符——$
- ??输出缓冲区
- 打印倒计时
- 实现一个倒计时
??什么是软件包?
概念
软件包是一种用于组织和分发软件的方式。它是一个包含了相关文件和元数据的压缩文件,通常以特定的格式打包。软件包可以包含可执行文件、库文件、配置文件、文档等。
软件包的主要目的是简化软件的安装、更新和卸载过程。通过将相关文件和依赖项打包在一起,软件包可以提供一种方便的方式来分发和管理软件。用户可以通过安装软件包来将软件部署到他们的计算机上,并且可以轻松地更新或卸载软件包。
软件包管理系统是用于管理软件包的工具集合。它提供了一组命令和功能,用于安装、更新、卸载和查询软>件包。常见的软件包管理系统包括APT(Advanced Package Tool)用于Debian和Ubuntu系统、YUM(Yellowdog Updater, Modified)用于CentOS和Fedora系统、Homebrew用于macOS系统等。
通过使用软件包,开发者可以更方便地分发他们的软件,并且用户可以更轻松地安装和管理软件。软件包的使用也有助于确保软件的版本一致性和依赖项的满足性。
- 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序.
- 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安
装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装. - 软件包和软件包管理器, 就好比 “App” 和 “应用商店” 这样的关系.
- yum(Yellow dog Updater, Modified)是Linux下非常常用的一种包管理器. 主要应用在Fedora, RedHat,
Centos等发行版上
?注意:所谓安装,本质就是将可执行程序移动到某个目录下
在软件商店中,那些还没被下载的软件都放在哪里呢? ?
答:
软件商店中的软件通常存储在软件仓库或应用商店的服务器上。
当用户在软件商店中选择下载或安装应用程序时,软件商店客户端会与服务器进行通信,下载相应的软件包到用户的设备上。然后,用户可以通过安装软件包来将应用程序部署到他们的设备上。
需要注意的是,不同的操作系统和平台有不同的软件商店和软件仓库。例如,Android设备使用Google Play商店,iOS设备使用App Store,Linux系统使用各种发行版的软件仓库,而Windows系统使用Microsoft Store等。每个软件商店都有自己的服务器和软件包管理系统,用于存储和分发软件。
??yum
?yum概念
yum是一种在基于RPM的Linux发行版上用于软件包管理的工具。它是Yellowdog Updater, Modified的缩写,最初是为了简化Red Hat Linux系统上的软件包管理而开发的。
yum的主要功能是从软件源(repositories)中下载、安装、更新和卸载软件包。它可以自动解决软件包之间的依赖关系,确保所需的依赖项也被正确安装。这使得安装和更新软件包变得更加简单和高效。
以下是yum的一些关键特点和用法:
-
软件源(repositories):yum使用软件源来获取软件包。软件源是存储软件包的服务器,可以是官方的发行版仓库或第三方仓库。yum可以配置多个软件源,以便从不同的源获取软件包。
-
安装软件包:使用yum install <package_name>命令来安装指定的软件包。yum会自动解决依赖关系,并下载和安装所需的软件包及其依赖项。
-
更新软件包:使用yum update命令来更新系统中已安装的软件包到最新版本。yum会检查软件源中是否有可用的更新,并自动下载和安装更新的软件包。
-
卸载软件包:使用yum remove <package_name>命令来卸载指定的软件包。yum会删除软件包及其相关的文件和依赖项。
-
搜索软件包:使用yum search 命令来搜索包含指定关键字的软件包。yum会列出匹配的软件包及其描述信息。
-
列出已安装的软件包:使用yum list命令来列出系统中已安装的所有软件包。可以使用yum list installed命令来只列出已安装的软件包。
-
清理缓存:使用yum clean 命令来清理yum缓存。常见的选项包括all(清理所有缓存)和metadata(清理仅限元数据缓存)。
?以下是yum的一些常用选项:
- install:安装软件包。使用yum install <package_name>命令来安装指定的软件包。
install -y 可以取消交互询问是否下载
-
update:更新软件包。使用yum update命令来更新系统中已安装的软件包到最新版本。
-
remove:卸载软件包。使用yum remove <package_name>命令来卸载指定的软件包。
-
search:搜索软件包。使用yum search 命令来搜索包含指定关键字的软件包。
-
info:获取软件包信息。使用yum info <package_name>命令来获取指定软件包的详细信息,包括版本、大小、依赖关系等。
-
list:列出已安装的软件包。使用yum list命令来列出系统中已安装的所有软件包。
-
upgrade:升级系统。使用yum upgrade命令来升级系统中的所有软件包到最新版本。
-
clean:清理缓存。使用yum clean 命令来清理yum缓存,常见的选项包括all(清理所有缓存)和metadata(清理仅限元数据缓存)。
-
check-update:检查可用的更新。使用yum check-update命令来检查系统中是否有可用的软件包更新。
这些是一些常用的yum选项,可以根据需要使用不同的选项来执行相应的操作。可以通过yum --help命令来获取更详细的帮助信息和其他可用选项。
centos7 yum 换源
有时候,我们需要给Yum换源。
?有时候需要给yum更换软件源的原因有以下几点:
-
加快下载速度:默认的软件源可能位于国外服务器,如果您的网络连接到该服务器的速度较慢,那么下载软件包可能会很慢。通过更换为国内的镜像源,可以加快下载速度,提高软件包的获取效率。
-
提高稳定性和可靠性:默认的软件源可能会因为服务器故障、网络问题或其他原因而不可用。通过选择可靠的镜像源,可以提高软件包的可用性和稳定性,确保您能够顺利地下载和安装软件包。
-
获取特定版本的软件包:默认的软件源可能只提供最新版本的软件包,而您可能需要获取特定版本的软件包。通过更换为其他源,您可以找到并下载所需版本的软件包。
-
解决依赖关系问题:有时候默认的软件源可能无法满足软件包之间的依赖关系,导致安装或更新软件包时出现问题。通过更换为其他源,您可能能够找到满足依赖关系的软件包,从而解决依赖问题。
?如何换源?
要在CentOS 7上更换yum软件源,可以按照以下步骤进行操作:
-
打开终端或命令行界面。
-
以root用户或具有sudo权限的用户身份登录。
-
备份当前的yum源配置文件,以防需要恢复:
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
- 使用文本编辑器(如vi或nano)打开yum源配置文件:
vi /etc/yum.repos.d/CentOS-Base.repo
-
在打开的文件中,注释掉(在行首添加#)所有以baseurl开头的行和以mirrorlist开头的行。
-
在文件中找到以baseurl开头的行和以mirrorlist开头的行,将其替换为新的yum源地址。可以从国内的镜像站点或其他可靠的源获取新的yum源地址。以下是一些常用的国内yum源地址:
- 阿里云:http://mirrors.aliyun.com/centos/$ releasever/os/$basearch/
- 清华大学:https://mirrors.tuna.tsinghua.edu.cn/centos/$ releasever/os/$basearch/
- 163镜像站:http://mirrors.163.com/centos/$ releasever/os/$basearch/
例如,将baseurl行替换为阿里云的yum源地址:
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
-
保存并关闭文件。
-
清理yum缓存,以便下次使用新的yum源:
yum clean all
- 生成新的yum缓存:
yum makecache
??Vim编辑器
编辑器和IDE概念
?编辑器
编辑器是一种专门用于编辑文本文件的工具。它通常提供基本的文本编辑功能,如插入、删除、复制和粘贴等。编辑器可以用于编辑各种类型的文本文件,包括代码文件、配置文件和普通文本文件等。编辑器的设计目标是提供简洁、轻量级和高度可定制的编辑环境。一些常见的文本编辑器包括Vim、Emacs、Sublime Text和Notepad++等。
?IDE
IDE是一个综合性的开发工具,旨在为开发人员提供一个集成的开发环境。IDE不仅提供了文本编辑功能,还集成了许多其他开发相关的功能,如调试器、编译器、自动完成、版本控制、项目管理和构建工具等。IDE通过将这些功能整合到一个统一的界面中,提供了更强大、高效和便捷的开发体验。常见的IDE包括Visual Studio、Eclipse、IntelliJ IDEA和PyCharm等。
vim基本操作
进入vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面:
- vim test.c
不过有一点要特别注意,就是你进入vim之后,是处于[正常模式],你要切换到[插入模式]才能够输入文字。
vim 文件名 +n :可指定打开文件后,光标位于第n行
? [正常模式]切换至[插入模式]
- 输入a
- 输入i
- 输入o
[插入模式]切换至[正常模式]
目前处于[插入模式],就只能一直输入文字,如果发现输错了字,想用光标键往回移动,将该字删除,可
以先按一下「ESC」键转到[正常模式]再删除文字。当然,也可以直接删除。
[正常模式]切换至[末行模式] - 「shift + ;」, 其实就是输入「:」
退出vim及保存文件,在[正常模式]下,按一下「:」冒号键进入「Last line mode」,例如: - : w (保存当前文件)
- : wq (输入「wq」,存盘并退出vim)
- : q! (输入q!,不存盘强制退出vim)
正常模式操作
-
插入模式
按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。 -
从插入模式切换为命令模式
按「ESC」键。 -
移动光标
vim可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母「h」、「j」、「k」、「l」
,分别控制光标左、下、上、右移一格
按「G」:移动到文章的最后
按「 $ 」:移动到光标所在行的“行尾”
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字(单词)的开头
按「e」:光标跳到下个字(单词)的字尾
按「b」:光标回到上个字(单词)的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l
按[gg]:进入到文本开始
按[shift+g]:进入文本末端
n+shift+g == G:定位到代码的任意一行|最后一行
按「ctrl」+「b」:屏幕往“后”移动一页
按「ctrl」+「f」:屏幕往“前”移动一页
按「ctrl」+「u」:屏幕往“后”移动半页
按「ctrl」+「d」:屏幕往“前”移动半页
-
删除文字
「x」:每按一次,删除光标所在位置的一个字符
「#x」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符
「X」== shift+x:大写的X,每按一次,删除光标所在位置的“前面”一个字符
「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符
「dd」:删除(剪切)光标所在行
「#dd」:从光标所在行开始删除#行 -
复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完
成复制与粘贴功能。 -
替换
「r」:替换光标所在处的字符。
「n+r」:替换光标所在处后的多个字符。
「R」== shift +r:进入替换模式
,替换光标所到之处的字符,直到按下「ESC」键为止。 -
撤销上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回
复。
「ctrl + r」: 撤销的恢复 -
更改
「cw」:更改光标所在处的字到字尾处
「c#w」:例如,「c3w」表示更改3个字 -
跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。
❄️杂
- gg:定位到代码第一行
- n+shift+g == G:定位到代码的任意一行|最后一行
- shift+4 == ¥ :特定一行的结尾
- shift+6 == ^ :特定一行的开始
- shift + ` ==~:更改大小写
- shift +3 == # :高亮显示所有相关字的字符,n可同单词之间跳转
vim末行模式操作
-
列出行号
「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号。 -
跳到文件中的某一行
「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,
再回车,就会跳到文章的第15行。 -
查找字符
「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按
「n」会往后寻找到您要的关键字为止。
「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直
按「n」会往前寻找到您要的关键字为止。
问题:/ 和 ?查找有和区别?操作实验一下 -
保存文件
「w」: 在冒号输入字母「w」就可以将文件保存起来 -
离开vim
「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开vim。
「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。 -
set /nu/nonu :显示行号/不显示行号
-
:!cmd 直接在不退出vim的前提下,进行查看,编译、运行的操作
-
/搜索关键字,n表示下一个
??Vim中的注释
如何批量注释?
步骤如下:
1.ctrl+v:进入视图模式
2.运用j、k:划分待会需要注释的区间
3.shift+i == I: 进入insert模式,此时光标会移动到区间首行
4.//:对当前行进行注释
5.Esc:退出insert模式后,刚刚划分的注释区间将被注释
批量化删除注释:
1.ctrl+v:进入视图模式
2.运用j、k:划分待会需要删除注释的区间
3.d:即可删除
注:可以运用h、l,更改删除的宽度
n+j/k:可直接确定区分行数,就不用一个一个慢慢按了
??Vim支持多文件编辑
在底行模式下:
vs 文件名 //可打开/创建 文件
- ctrl +ww:可在文件中切换光标
?注意:光标所在处,即是当下所在编辑的文件
??在sudoers名单(信任名单)上添加用户
步骤如下:??
1.将账号切换成root账号
2.
vim /etc/sudoers //打开sudoers文件
3.光标定位到100行左右,将以下命令yy复制粘贴,将root名改为所添加用户名,然后在底行模式下wq!,保存退出即可
root ALL=(ALL) ALL
??Vim 的配置
在Linux下,Vim的配置是通过编辑位于✨用户主目录下的.vimrc
文件来实现的。该文件包含了各种设置和自定义命令,以满足个人偏好和需求。下面是一些常见的Vim配置选项:
-
设置行号:
在.vimrc中添加以下行,启用显示行号:set number
-
启用语法高亮:
语法高亮可以帮助您更清晰地看到代码结构。在.vimrc中添加以下行,启用语法高亮:syntax on
-
设置缩进:
缩进对于代码的可读性很重要。您可以在.vimrc中设置默认的缩进方式和缩进大小。例如,将缩进方式设置为空格,并将缩进大小设置为4个空格:set expandtab set tabstop=4
-
设置自动补全:
您可以启用自动补全功能,以便在输入代码时自动提供建议。例如,使用插件"vim-autocomplpop",在.vimrc中添加以下行:let g:acp_enableAtStartup = 1
-
设置主题:
您可以选择适合自己的Vim主题。首先,将主题文件(通常以.vim结尾)放入~/.vim/colors/目录中。然后,在.vimrc中添加以下行,设置使用的主题:colorscheme <theme_name>
-
自定义键映射:
您可以自定义按键映射,以便为常用操作创建快捷键。例如,将F2键映射为保存当前文件的快捷键,在.vimrc中添加以下行:nnoremap <F2> :w<CR>
-
安装插件管理器:
使用插件管理器可以方便地安装、更新和删除Vim插件。常见的插件管理器有Vundle、Pathogen和vim-plug等。
vim 一键配置写好的脚本
快速将vim打造成c++ IDE
前提先在yum下下好curl:
yum install curl
而后复制以下链接可下载脚本:
curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
下载成功后如下
??Linux编译器-gcc/g++使用
在linux编译下:
- gcc:只能编译c文件
- g++:可以编译c++文件,同时也可以编译c文件
centos7 yum下载g++
yum install gcc gcc-c++
背景介绍
当我们在Linux系统上编译和运行程序时,通常会经历以下几个步骤:预处理、编译、汇编、链接和执行。让我逐一解释这些步骤的含义。
-
预处理(Preprocessing):
在预处理阶段,编译器会对源代码进行处理。它会处理以#
开头的预处理指令(条件编译),并将宏定义替换、删除注释、包含其他文件等操作。预处理生成的结果称为预处理后的源代码。 -
编译(Compilation):
编译阶段是将预处理后的源代码转换为汇编代码的过程。在这个阶段,编译器会将高级语言(如C或C++)的源代码翻译成低级的中间表示形式,即汇编代码。 -
汇编(Assembly):
在汇编阶段,汇编器将汇编代码转换为机器码指令。汇编器会将每条汇编语句翻译成与特定硬件平台相关的二进制指令。 -
链接(Linking):
链接阶段是将多个目标文件(.o/.obj)和库文件合并成一个可执行文件的过程。在这个阶段,链接器会解析函数和变量之间的引用关系,并将它们连接起来,生成最终的可执行文件。 -
执行(Execution):
执行阶段是将生成的可执行文件加载到内存中,并按照程序的逻辑顺序执行。此时,计算机会按照指令一条一条地执行程序,完成所需的任务。
需要注意的是,这些步骤并不是严格线性的,而是在编译过程中交叉进行的。通常,编译器会自动处理这些步骤,我们只需要运行相应的编译命令即可。
gcc
?gcc常用选项:
- -c: 编译源文件为目标文件而不进行链接
- -o filename: 将编译出来的目标文件放在指定的文件中
- -Wall: 显示所有警告信息
- -g: 在可执行文件中增加调试信息
- -O level: 优化等级,可取-O, -O1, -O2, -O3等
- -I dir: 指定头文件搜索路径
- -L dir: 指定库文件搜索路径
- -l library: 指定要链接的库名
- -D macro: 定义宏
- -U macro: 取消已定义的宏
- -E: 只运行预处理器
- -S: 只编译生成汇编代码
- -shared: 生成动态链接库
- -fPIC: 生成位置无关代码
- -pthread: 指定链接pthread库
静态库和动态库
在Linux中,静态库(Static Library)和动态库(Dynamic Library)是常用的代码重用方式。它们都是将一组函数和符号打包成一个文件,供其他程序使用。
- 静态库:
是c/c++或者第三方提供的所有方法的集合,以拷贝的方式,将所需的代码拷贝到可执行程序当中
静态库是将一组函数和符号的实现编译成一个独立的可执行文件,当需要使用这些函数和符号时,链接器会将静态库的代码复制到最终的可执行文件中。优点是简单、方便,不依赖于外部环境;缺点是每个使用该库的可执行文件都会包含一份完整的库代码,导致可执行文件变大。
静态库的文件扩展名通常为.a
(如libexample.a
)。使用静态库的步骤如下:
-
编译静态库:
gcc -c library.c // 编译源文件生成目标文件 ar rcs libexample.a library.o // 使用ar命令将目标文件打包成静态库
-
编译可执行文件并链接静态库:
gcc -o executable main.c -L/path/to/library -lexample // 编译可执行文件并链接静态库
这里
-L
选项指定了库文件的路径,-l
选项指定了要链接的静态库。
- 动态库:
是c/c++或者第三方提供的所有方法的集合,以动态链接的方式将所有程序链接起来,但其本质上也是拷贝,只是将要连接的库中的方法函数的地址拷贝到可执行程序的特定位置
动态库是在程序运行时被加载到内存中的共享库,它可以被多个可执行文件共享使用。优点是节省内存空间,可执行文件较小;缺点是需要依赖于外部环境,如果系统中没有相应的动态库,程序将无法正常运行。
可执行文件与编译器中的链接器在还没加载到内存时,就会先建立联系,链接器会告诉可执行文件动态库,即共享库的位置,等到所有代码加载到内存当中时,要调用动态库中的某一方法,就会依据链接器给的地址寻到对应的动态库。
若共享库一旦被销毁,其共享的所有可执行文件都会受到影响
动态库的文件扩展名通常为.so
(如libexample.so
)。使用动态库的步骤如下:
-
编译动态库:
gcc -shared -o libexample.so library.c // 编译源文件生成动态库
-
编译可执行文件并链接动态库:
gcc -o executable main.c -L/path/to/library -lexample // 编译可执行文件并链接动态库
这里
-L
选项指定了库文件的路径,-l
选项指定了要链接的动态库。
除了上述方法,还可以使用dlopen
和dlsym
等函数动态加载和使用动态库。
总结来说,静态库适合于独立的、不需要频繁更新的代码,而动态库适合于共享的、可能需要更新的代码。
?:在Windows下,静态库一般表示为.dll
,动态库表示为.lib
-
.i文件
:只执行过预处理生成的文件 -
.s文件
:经过预处理、汇编生成的文件(里面是汇编转成了二进制文件) -
.o文件
:目标文件,还未经过链接
.s和.o文件都是可执行文件
静态链接和动态链接
在Linux系统中,静态链接和动态链接是用于将程序与库文件进行连接的两种方式。
静态链接是指在编译过程中,将程序所需要的库文件的代码复制到可执行文件中,形成一个独立的、完整的可执行文件。这意味着程序不再依赖于外部的库文件,可以在任何没有相关库文件的系统上运行。静态链接的优点是可移植性好,不受外部环境的影响,且执行速度较快。缺点是可执行文件的体积较大
,并且每个使用相同库的程序都会有一份该库的副本,造成资源浪费。
动态链接是指在编译过程中,程序只包含对库文件的引用,而不将库文件的代码复制到可执行文件中。在程序运行时,系统会根据需要加载并链接相应的库文件。这样可以节省内存空间,并且当库文件更新时,所有使用该库的程序都能受益于更新。动态链接的优点是节省内存,减小可执行文件的体积,并且方便库文件的更新和维护。缺点是可能会存在版本兼容性问题
,如果系统上没有相应的库文件,则无法运行程序。
选择静态链接还是动态链接取决于具体情况。如果程序需要在多个系统上运行,或者需要独立部署,那么静态链接是一个较好的选择。如果程序依赖于一些常用的库文件,并且希望能够方便地更新和维护这些库文件,那么动态链接是一个更合适的选择。
- gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件
- gcc默认生成的二进制程序,是动态链接的,这点可以通过
file
命令验证
所以在我们平常使用的开发环境中,其默认要为我们做的事需要有:
- 下载开发环境include ,lib
- 设置好合理的查找路径
- 规定好我们形成的可执行程序的链接方式
linux下安装静态库
我们知道,linux下是默认带有动态库的,所以静态库需要我们自己去安装。
c静态库:
yum install glibc-static
c++静态库:
sudo yum install -y libstdc++-static
??Linux项目自动化构建工具-make/Makefile
概念
Make是一种被广泛使用的构建工具,主要用于自动化构建和管理软件项目。它通过读取Makefile文件中的规则和指令来执行编译、链接、测试等操作,从而简化了项目构建的过程。
Makefile是Make工具所使用的配置文件,其中包含了一系列规则和指令,用于指导Make进行构建过程。Makefile采用了一种基于依赖关系的编程模型,通过定义目标(target)和依赖关系(dependencies)来描述源文件之间的关系,以及如何生成目标文件。
一个典型的Makefile文件包含了以下几个重要的部分:
-
变量定义:可以定义一些变量,用于存储编译选项、文件路径等信息,提高可维护性和灵活性。
-
规则定义:包括目标、依赖关系和执行命令。每个规则指定了生成某个目标文件所需的依赖文件,以及生成目标文件的命令。
-
默认规则:如果没有明确指定目标,默认规则会被执行。通常情况下,这个规则用来构建整个项目。
在Makefile中,目标和依赖关系之间通过规则连接起来。当我们运行make命令时,Make会检查目标文件和依赖文件的时间戳,确定哪些文件需要重新编译,然后按照依赖关系执行相应的命令,生成目标文件。
通过使用Make和Makefile,可以实现项目的自动化构建和管理,提高开发效率和可维护性。它是Linux开发中非常重要且常用的工具之一。
依赖关系和依赖方法
依赖关系指的是源文件之间的相互关系,即一个文件是否依赖于其他文件。如果一个文件发生了变化,那么依赖于它的文件也需要重新编译。Makefile使用依赖关系来确保只有需要重新编译的文件才会被重新编译,从而提高编译效率。
依赖方法是指在Makefile中定义依赖关系的方式。常见的依赖方法有两种:
- 显式规则:使用显式规则可以明确指定目标文件所依赖的源文件和命令。格式如下:
target: dependencies
command
其中,target
是要生成的目标文件,dependencies
是 target
所依赖的源文件,command
是编译或链接命令。
例如,假设我们有一个名为 program
的目标文件,依赖于 file1.c
和 file2.c
两个源文件,可以使用以下规则:
program: file1.c file2.c
gcc -o program file1.c file2.c
- 隐式规则:使用隐式规则可以根据文件的后缀名自动生成编译命令。Makefile会根据规则自动推导出依赖关系。例如,对于
.c
文件,Makefile会使用gcc
命令进行编译。
program: file1.c file2.c
在这个例子中,Makefile会自动推导出编译命令:
gcc -o program file1.c
gcc -o program file2.c
通过定义正确的依赖关系和依赖方法,Makefile可以自动构建程序,并根据源文件的变化来判断是否需要重新编译。这样可以提高开发效率,并确保只有必要的文件被重新编译。
make编译与源文件变化的关系
我们知道一个文件有一个ACM属性
当Modify的时间更改了,即源文件内容修改后,此时去make 编译,make才会允许再编译
而这里我们要引入一个新概念:.PHONY
修饰的伪目标
✨伪目标不受任何情况拦截,其依赖方法总是被执行
这里被.PHONY修饰的clean命令,无论源文件是否有被修改,都可以执行clean命令
@修饰依赖方法
@修饰方法,会隐藏该方法的编译过程
makefile中的特殊字符——$
在Makefile中,$
符号是用于引用变量的特殊字符。它可以用来表示已定义的变量的值、函数的返回值以及其他一些特殊用途。
下面是一些常见的 $
的用法:
-
引用变量:可以使用
$
来引用已定义的变量。例如,如果有一个变量SRC
定义为source.c
,可以通过$SRC
来引用该变量的值。
SRC = source.c
$(CC) -c $(SRC)
- 特殊变量:Makefile中有一些特殊的预定义变量,如
$@
、$^
等。前者代表是:
左侧内容,后者是:
右侧内容
program: source.c header.h
$(CC) -o $@ $^
- 函数调用:可以使用
$()
或${}
来调用函数,并使用函数的返回值。Makefile提供了一些内置函数,如$(shell)
、$(wildcard)
、$(subst)
等。可以根据需要使用相应的函数。
files = $(shell ls *.c)
objs = $(patsubst %.c, %.o, $(files))
- 命令替换:可以使用
$()
或 ````符号来执行命令,并将命令的输出作为变量的值。这在需要根据运行时的结果来设置变量时非常有用。
timestamp = $(shell date +%Y-%m-%d-%H:%M:%S)
请注意,$
符号在Makefile中是特殊字符,如果想要表示 $
字符本身,需要使用 $$
进行转义。
LOG_FILE = $$(date +%Y-%m-%d).log
通过灵活地使用 $
符号,可以更好地处理变量、函数和命令的值,并使Makefile更加强大和可扩展。
??输出缓冲区
?概念
在 Linux 系统中,输出缓冲区是一个临时的存储区域,用于暂时存储应用程序产生的输出,直到它们被发送到目标设备或显示到屏幕上。
输出缓冲区位于内核和实际设备之间。当应用程序产生输出时,数据会首先被写入输出缓冲区中,然后由内核负责将缓冲区中的内容发送到目标设备。这种缓冲机制可以提高输出的效率,避免频繁的系统调用和设备访问。
Linux 系统中的输出缓冲区有多种类型,包括标准输出缓冲区(stdout)、标准错误缓冲区(stderr)以及文件和设备特定的缓冲区。其中,stdout 和 stderr 是常用的两个缓冲区。
默认情况下,stdout 是行缓冲
的,也就是说当我们在应用程序中使用 printf 或 cout 等函数输出字符时,输出会被缓冲并在换行符出现时立即刷新,或者当输出缓冲区被填满时才触发刷新操作。例如:
printf("Hello, World!\n"); // \n刷新 stdout 缓冲区
而 stderr 是无缓冲的,它会直接将输出内容发送到目标设备,不进行缓冲。这样可以确保错误消息尽快显示,以便更及时地进行错误处理。
除了标准输出和标准错误外,应用程序还可以使用文件操作函数(如 fwrite、fprintf)来操作文件缓冲区。对于特定设备的输出,例如串口或网络套接字,也会有相应的缓冲机制。
需要注意的是,在某些情况下,当应用程序异常终止或程序结束时,输出缓冲区中的内容可能不会被刷新到目标设备上,导致部分输出丢失。为了避免这种情况,可以手动调用 fflush 函数
来刷新输出缓冲区。
总结起来,输出缓冲区在 Linux 系统中起到了重要的作用,它提供了一个缓冲机制,可以提高输出效率并避免频繁的系统调用和设备访问。不同类型的输出缓冲区有不同的刷新机制,并且可以通过手动刷新来确保输出内容尽快显示。文章来源:https://uudwc.com/A/woLY6
打印倒计时
#include <stdio.h>
2 #include <unistd.h>
3 int main()
4 {
5 int count = 9;
6 while(count)
7 {
8 printf("%d\r",count);
9 fflush(stdout);//刷新输出缓冲区
10 count--;
11 sleep(1);
12
13 }
14 return 0;
15 }
实现一个倒计时
#include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #define MAX_RATE 100
5 #define MAX_SIZE 101
6 #define ch '#'
7 int main()
8 {
9 char str[MAX_SIZE] = {0};
10 int rate = 0;
11 while(rate<=MAX_RATE)
12 {
13 printf("%-100s][%d%%]\r",str,rate);
14 fflush(stdout);
15 usleep(1000*20);
16 str[rate++] =ch;
17 }
18 printf("\n");
19
20 return 0;
21 }
如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注???❤️ ? ?,学海无涯苦作舟,愿与君一起共勉成长
文章来源地址https://uudwc.com/A/woLY6