Linux系统——OS学习笔记<1>

目录

一.Ubuntu 系统入门

1.VMware 创建虚拟机流程

2.Ubuntu 系统入门

<1>Shell 命令

1、目录信息查看命令 ls

2、目录切换命令 cd

3、当前路径显示命令 pwd

4、系统信息查看命令 uname

5、清屏命令 clear

6、切换用户执行身份命令 sudo

7、添加用户命令 adduser

8、删除用户命令 deluser

9、切换用户命令 su

10、显示文件内容命令 cat

11、显示和配置网络属性命令 ifconfig

12、系统帮助命令 man

13、 系统重启命令 reboot

14、系统关闭命令 poweroff

15、软件安装命令 install

<2>APT 下载工具

1、更新本地数据库

2、检查依赖关系

3、软件安装

4、软件更新

5、卸载软件

<3>Ubuntu 下文本编辑

<4>文件系统

1.Linux 文件系统结构

2.文件操作命令

1、创建新文件命令—touch

2、文件夹创建命令—mkdir

3、文件及目录删除命令—rm

4、文件夹(目录)删除命令—rmdir

5、文件复制命令—cp

6、文件移动命令—mv

3.文件压缩和解压缩

1、图形化压缩和解压缩

2、命令行进行文件的压缩和解压缩

①命令 zip

②命令 unzip

③命令 tar

4.文件查询和搜索

1、命令 find

2、命令 grep

5.文件类型

<5>Linux 用户权限管理

1.Ubuntu 用户系统

2.权限管理

3.权限管理命令

1、权限修改命令 chmod

2、文件归属者修改命令 chown

<6>Linux 磁盘管理

1.Linux 磁盘管理基本概念

2.磁盘管理命令

1、磁盘分区命令 fdisk

2、格式化命令 mkfs

3、挂载分区命令 mount

4、卸载命令 umount

3.Linux C 编程入门

<1>编写代码

<2>编译代码

<3>GCC 编译器

1、gcc 命令格式如下:

2、编译流程

<4>Makefile 基础

1、Makefile 简介

2、Makefile 的引入

3、Makefile 语法

①Makefile 规则格式

②Makefile 变量

③Makefile 模式规则

④Makefile 自动化变量

⑤Makefile 伪目标

⑥Makefile 条件判断

⑦Makefile 函数使用


参考资料:正点原子《DFZU2EG_4EV MPSoC 之 Linux 驱动开发指南》

一.Ubuntu 系统入门

        在虚拟机上安装 Ubuntu 操作系统,安装好以后 Ubuntu 的设置、基本操作。想详细的学习 Ubuntu 系统的话可以参考《鸟哥的 linux 私房菜》这本书使用的 CentOS 操作系统,但是 Ubuntu 下完全可以使用。当 Ubuntu 系统入门以后,我们重点要学的就是如何在 Linux 下进行 C 语言开发,如何 使用 gcc 编译器、如何编写 Makefile 文件等等。如果此前已经使用过 Ubuntu 操作系统,并且从事过 Linux C 编程工作的话本篇就不需要看了。

1.VMware 创建虚拟机流程

2.Ubuntu 系统入门

        本章的主要目的是教会读者掌握后续嵌入式开发所需的 Ubuntu 基本技能,比如系统的基本设置、常用的 shell 命令、vim 编辑器的基本操作等等,如果想详 细的学习 Ubuntu 操作系统请参考其它更为详细的书籍,本章参考了《Ubuntu Linux 从入门到 精通》

<1>Shell 命令

        将多个 Shell 命令按照一定的格式放到一个文本中,那么这个文本就叫做 Shell 脚本。严格意义上来讲,Shell 是一个应用程序,它负责接收用户输入的命令,然后根据命令做出相应的动作,Shell 负责将应用层或者用户输入的命令传递给系统内核,由操作系统内核来完成相应的工作,然后将结果反馈给应用层或者用户。

Shell 命令的格式如下:

command -options [argument]

command: Shell 命令名称。

options:选项,同一种命令可能有不同的选项,不同的选项其实现的功能不同。

argument:Shell 命令是可以带参数的,也可以不带参数运行。

        Shell 命令是支持自动补全功能的,因为 Shell 命令非常多,如果不作自动补全的话就需要用户去记忆这些命令的全部字母。使用自动补全功能以后我们只需要输入命令的前面一部分字母,然后按下 TAB 键,如果只有一个命令匹配的话就会自动补全这个命令剩下的字母。

常用 Shell 命令:

1、目录信息查看命令 ls
ls [选项] [路径]
主要参数有:
-a 显示所有的文件以及子目录,包括以“.”开头的隐藏文件。
-l 显示文件的详细信息,比如文件的形态、权限、所有者、大小等信息。
-t 将文件按照创建时间排序列出。
-A 和-a 一样,但是不列出“.”(当前目录)和“..”(父目录)。
-R 递归列出所有文件,包括子目录中的文件。

        Shell 命令里面的参数是可以组合在一起用的,比如组合“-al”就是显示所有文件的详细 信息,包括以“.”开头的隐藏文件。

2、目录切换命令 cd
cd [路径]
示例:
cd / //进入到根目录“/”下,Linux 系统的根目录为“/”,
cd /usr //进入到目录“/usr”里面。
cd .. //进入到上一级目录。
cd ~ //切换到当前用户主目录
3、当前路径显示命令 pwd
4、系统信息查看命令 uname
uname [选项]
可选的选项参数如下:
-r 列出当前系统的具体内核版本号。
-s 列出系统内核名称。
-o 列出系统信息。
5、清屏命令 clear
6、切换用户执行身份命令 sudo

        Ubuntu(Linux)是一个允许多用户的操作系统,其中权限最大的就是超级用户 root,有时候 我们执行一些操作的时候是需要用 root 用户身份才能执行,比如安装软件。通过 sudo 命令可以使我们暂时将身份切换到 root 用户。当使用 sudo 命令的时候是需要输入密码的,这里要注 意输入密码的时候是没有任何提示的!命令格式如下:

sudo [选项] [命令]
选项主要参数如下:
-h 显示帮助信息。
-l 列出当前用户可执行与不可执行的命令
-p 改变询问密码的提示符。

        假如我们现在要创建一个新的用户 test,创建新用户的命令为“adduser”,创建新用户的权限只有 root 用户才有,我们在装系统的时候创建的那个用户是没有这个权限的,比如我的 “zuozhongkai”用户。所以创建新用户的话需要使用“sudo”命令以 root 用户执行“adduser” 这个命令,如下图所示:

7、添加用户命令 adduser
adduser [参数] [用户名]
常用的参数如下:
-system 添加一个系统用户
-home DIR DIR 表示用户的主目录路径
-uid ID ID 表示用户的 uid。
-ingroup GRP 表示用户所属的组名。
8、删除用户命令 deluser
deluser [参数] [用户名]
主要参数有:
-system 当用户是一个系统用户的时候才能删除。
-remove-home 删除用户的主目录
-remove-all-files 删除与用户有关的所有文件。
-backup 备份用户信息
9、切换用户命令 su

        命令“su” 可以直接将当前用户切换为 root 用户,切换到 root 用户以后获得系统最高权限,在 root 用户下,所有的命令都可以无障碍执行,不需要在 前面加上“sudo”,“su”命令格式如下:

su [选项] [用户名]
常用选项参数如下:
-c –command 执行指定的命令,执行完毕以后回复原用户身份。
-login 改变用户身份,同时改变工作目录和 PATH 环境变量。
-m 改变用户身份的时候不改变环境变量
-h 显示帮助信息

        使用命令“sudo su”切换到 root 用户,su 命令不写明用户名的话默认 切换到 root 用户。然后输入密码,密码正确的话就会切换到 root 用户,可以看到切换到 root 用户以后提示符的“@”符号前面的用户名变成了“root”,表示当前的用户是 root 用户。并 且以“#”结束。

        注意!!由于 root 用户权限太大,稍微不注意就可能删除掉系统文件,导致系统奔溃, 因此强烈建议大家,不要以 root 用户运行 Ubuntu。当要用到 root 身份执行某些命令的时候使用“sudo”命令即可。

        要切换回原来的用户,使用命令“sudo su 用户名”即可。

10、显示文件内容命令 cat
cat [选项] [文件]
选项主要参数如下:
-n 由 1 开始对所有输出的行进行编号。
-b 和-n 类似,但是不对空白行编号。
-s 当遇到连续两个行以上空白行的话就合并为一个行空白行。
11、显示和配置网络属性命令 ifconfig
ifconfig interface options | address
主要参数如下:
interface 网络接口名称,比如 eth0 等。
up 开启网络设备。
down 关闭网络设备。
add IP 地址,设置网络 IP 地址。
netmask add 子网掩码。

        在图中有两个网卡:ens33 和 lo,ens33 是我的电脑实际使用的网卡,lo 是回测网 卡。可以看出网卡 ens33 的 IP 地址为 192.168.31.235,我们使用命令“ifconfig”将网卡 ens33 的 IP 地址改为 192.168.31.20,操作如下图所示:

12、系统帮助命令 man
man [命令名]

按“q”键退出到终端。

13、 系统重启命令 reboot
14、系统关闭命令 poweroff
15、软件安装命令 install
格式如下:
install [选项]... [-T] 源文件 目标文件
或:install [选项]... 源文件... 目录
或:install [选项]... -t 目录 源文件...
或:install [选项]... -d 目录...

        截至目前,我们都没有讲过 Ubuntu 下如何安装软件,因为 Ubuntu 安装软件不像 Windows 下那样,直接双击.exe 文件就开始安装了。Ubuntu 下很多软件是需要先自行下载源码,下载源码以后自行编译编译完成以后使用命令“intsall”来安装。当然 Ubuntu 下也有其它的软件安装方法,但是用的最多的就是自行编译源码然后安装,尤其是嵌入式Linux开发。

        “install”命令是将文件(通常是编译后的文件)复制到目的位置,在前三种形式中,将源文件复制到目标文件或将多个源文件复制到一个已存在的目录中同时设置其所有权和权限模式。在第四种形式会创建指定的目录。命令“install”通常和命令“apt-get”组合在一起使用的。

<2>APT 下载工具

        对于长时间使用 Windows 的我们,下载安装软件非常容易,Windows 下有很多的下载软 件,Ubuntu 同样有不少的下载软件,本节我们讲解 Ubuntu 下我们用的最多的下载工具:APT 下载工具,APT 下载工具可以实现软件自动下载、配置、安装二进制或者源码的功能。APT 下载工具和我们前面讲解的“install”命令结合在一起构成了 Ubuntu 下最常用的下载和安装软件方法。它解决了 Linux 平台下一安装软件的一个缺陷,即软件之间相互依赖

        APT 采用的 C/S 模式,也就是客户端/服务器模式,我们的 PC 机作为客户端,当需要下载软件的时候就向服务器请求,因此我们需要知道服务器的地址,也叫做安装源或者更新源。

打开“软件和更新”设置,打开方式如下图所示:

        在上图中的“Ubuntu 软件”选项卡下面的“下载自”就是 APT 工具的安装源,因为我们是在中国,所以需要选择中国的服务器,否则的话可能会导致下载失败!这个也就是网上说的 Ubuntu 安装成功以后要更新源。

        在我们使用 APT 工具下载安装或者更新软件的时候,首先会在下载列表中与本机软件对比,看一下需要下载哪些软件,或者升级哪些软件,默认情况下 APT 会下载最新的软件包, 被安装的软件包所依赖的其它软件也会被下载安装。说了这么多,APT 下载工具究竟怎么用呢?APT 工具常用的命令如下:

1、更新本地数据库
sudo apt-get update

这个命令会访问源地址,并且获取软件列表并保存在本电脑上。如果想查看本地哪些软件可以更新的话可以使用如下命令。

2、检查依赖关系
sudo apt-get check

        有时候本地某些软件可能存在依赖关系,所谓依赖关系就是 A 软件依赖于 B 软件。通过 如下命令可以查看依赖关系,如果存在依赖关系的话 APT 会提出解决方案。

3、软件安装
sudo apt-get install package-name

注:推荐使用 apt 替代 apt-get

4、软件更新
sudo apt-get upgrade package-name
5、卸载软件
sudo apt-get remove package-name

<3>Ubuntu 下文本编辑

        Ubuut 下有一个自带的文本编辑器,那就是 Gedit。Gedit 是一个窗口式的编辑器,本节我们重点讲解的是另外一 个编辑器:VI/VIM 编辑器。

        我们如果要在终端模式下进行文本编辑或者修改文件就可以使用 VI/VIM 编辑器,Ubuntu 自带了 VI 编辑器。VIM 编辑 器是 VI 编辑器升级版本,VI/VIM 编辑器都是一种基于指令式的编辑器,不需要鼠标,也没有菜单,仅仅使用键盘来完成所有的编辑工作。

安装 VIM 编辑器,命令如下:

sudo apt-get install vim

        VIM 编辑器有 3 中工作模式:输入模式、指令 模式和底行模式,通过切换不同的模式可以完成不同的功能。

        打开终端,输入命令:vi test.txt 。在终端中输入上图中所示的命令以后就会创建一个 test.txt 文档,并且用 VIM 打开了。VIM 默认是以只读模式打开的文档,因此我们要切换到输入模式,切换到输入模式的命令如下:

i 在当前光标所在字符的前面,转为输入模式
I 在当前光标所在行的行首转换为输入模式
a 在当前光标所在字符的后面,转为输入模式
A 在光标所在行的行尾,转换为输入模式
o 在当前光标所在行的下方,新建一行,并转为输入模式
O 在当前光标所在行的上方,新建一行,并转为输入模式
s 删除光标所在字符。 r 替换光标处字符

        但是不能使用快捷键 Ctrl+S 来保存,这是因为在 Ubuntu 下 Ctrl+S 快捷 键不是用来完成保存的功能的,而是暂停该终端!所以你一旦在使用终端的时候按下 Ctrl+S 快捷键,那么你的终端肯定不会再有任何反应,如果你按下 Ctrl+S 关闭了当前终端可以 按下 Ctrl+Q 来重新打开终端

        我们需要从 VIM 现在的输入模式切换到指令模式,方式就是按下键盘的 ESC

        指令模式顾名思义就是输入指令的模式,这些 指令是控制文本的指令,我们将这些指令进行分类,如下所示:

1、移动光标指令:
h(或左方向键) 光标左移一个字符。
l(或右方向键) 光标右移一个字符。
j(或下方向键) 光标下移一行。
k(或上方向键) 光标上移一行。
nG 光标移动到第 n 行首。
n+ 光标下移 n 行。
n- 光标上移 n 行。

2、屏幕翻滚指令
Ctrl+f 屏幕向下翻一页,相当于下一页。
Ctrl+b 屏幕向上翻一页,相当于上一页。

3、复制、删除和粘贴指令
cc 删除整行,并且修改整行内容。
dd 删除改行,不提供修改功能。
ndd 删除当前行向下 n 行。
x 删除光标所在的字符。
X 删除光标前面的一个字符。
nyy 复制当前行及其下面 n 行。
p 粘贴最近复制的内容。

        保存文档的命令是在底行模式中,我们要先进入到指令模式,进入底行模式的方式是先进入指令模式 下,然后在指令模式下输入“:”进入底行模式

常用的命令如下:

x 保存当前文档并且退出。
q 退出。
w 保存文档。
q! 退出 VI/VIM,不保存文档。

如果我们要退出并保存文本的话需要在“:”底行模式下输入“wq”

        还可以 在指令模式下输入“/”进入底行模式,在“/”后面输入要搜索的内容,然后按下回车键就会找到与字符串匹配的部分

<4>文件系统

        Linux 有多种文件系统,不同的文件系统支持不同的体系。文件系统是管理数 据的,而可以存储数据的物理设备有硬盘、U 盘、SD 卡、NAND FLASH、NOR FLASH、网 络存储设备等。不同的存储设备其物理结构不同,不同的物理结构就需要不同的文件系统去管 理,比如管理 NAND FLASH 的话使用 YAFFS 文件系统,管理硬盘、SD 卡的话就是 ext 文件 系统等等。

        Windows 下一般有 FAT、NTFS 和 exFAT 这些文件系统。同样的,在 Linux 下我们使用 fdisk 创建好分区以后也是要先在创建好的分区 上面创建文件系统,也就是格式化。 在 Windows 下有磁盘分区的概念,比如 C,D,E 盘等,在 Linux 下没有这个概念,因此 Linux 下你找不到像 C、D、E 盘这样的东西。前面我们说了 Linux 下可以给磁盘分割,在 Linux 下创建一个分区并且格式化好以后我们要将 其“挂载”到一个目录下才能访问这个分区。Windows 的文件系统挂载过程是其内部完成的, 用户是看不到的,Linux 下我们使用 mount 命令来挂载磁盘。挂载磁盘的时候是需要确定挂载 点的,也就是你的这个磁盘要挂载到哪个目录下。

        Linux 下的文件系统主要有 ext2、ext3、ext4 等文件系统。Linux 还支持其 他的 UNIX 文件系统,比如 XFS、JFS、UFS 等,也支持 Windows 的 FAT 文件系统和网络文 件系统 NFS 等。这里我们主要讲一下 Linux 自带的 ext2、ext3 和 ext4 文件系统。

在终端中输入如下命令来查询当前磁盘挂载的是什么文件系统:

df -T –h

1.Linux 文件系统结构

        Linux 只有一个根目录“/”。Ubuntu 是支持多用户的,Ubuntu 为每个用户创建了一个根目录,只要你创建了一个用户,那么系统就会在/home 这个目录下创建一个以这个用户名命名的文件 夹,这个文件夹就是这个用户的根目录。

我们来看一下根目录“/”中的 一些重要的文件夹:

/bin 存储一些二进制可执行命令文件,/usr/bin 也存放了一些基于用户的命令文件。
/sbin 存储了很多系统命令,/usr/sbin 也存储了许多系统命令。
/root 超级用户 root 的根目录文件。
/home 普通用户默认目录,在该目录下,每个用户都有一个以本用户名命名的文件夹。
/boot 存放 Ubuntu 系统内核和系统启动文件。
/mnt 通常包括系统引导后被挂载的文件系统的挂载点。
/dev 存放设备文件,我们后面学习 Linux 驱动主要是跟这个文件夹打交道的。
/etc 保存系统管理所需的配置文件和目录。
/lib 保存系统程序运行所需的库文件,/usr/lib 下存放了一些用于普通用户的库文件。
/lost+found 一般为空,当系统非正常关机以后,此文件夹会保存一些零散文件。
/var 存储一些不断变化的文件,比如日志文件
/usr 包括与系统用户直接有关的文件和目录,比如应用程序和所需的库文件。
/media 存放 Ubuntu 系统自动挂载的设备文件。
/proc 虚拟目录,不实际存储在磁盘上,通常用来保存系统信息和进程信息。
/tmp 存储系统和用户的临时文件,该文件夹对所有的用户都提供读写权限。
/opt 可选文件和程序的存放目录。
/sys 系统设备和文件层次结构,并向用户程序提供详细的内核数据信息。

2.文件操作命令
1、创建新文件命令—touch
touch [参数] [文件名]
使用 touch 创建文件的时候,如果[文件名]的文件不存在,那就直接创建一个以[文件名]
命名的文件,如果[文件名]文件存在的话就仅仅修改一下此文件的最后修改日期,常用的命令
参数如下:
-a 只更改存取时间。
-c 不建立任何文件。
-d<日期> 使用指定的日期,而并非现在日期。
-t<时间> 使用指定的时间,而并非现在时间。
2、文件夹创建命令—mkdir
mkdir [参数] [文件夹名目录名]
主要参数如下:
-p 如所要创建的目录其上层目录目前还未创建,那么会一起创建上层目录。
3、文件及目录删除命令—rm

        要删除一个文件或者文件夹可以使用 命令“rm”,此命令可以完成删除一个文件或者多个文件及文件夹,它可以实现递归删除。 对于链接文件,只删除链接,原文件保持不变,所谓的链接文件,其实就是 Windows 下的快 捷方式文件,此命令格式如下:

rm [参数] [目的文件或文件夹目录名]
命令主要参数如下:
-d 直接把要删除的目录的硬连接数据删成 0,删除该目录。
-f 强制删除文件和文件夹(目录)。
-i 删除文件或者文件夹(目录)之前先询问用户.
-r 递归删除,指定文件夹(目录)下的所有文件和子文件夹全部删除掉。
-v 显示删除过程。

        直接使用命令“rm”是无法删除文件夹(目录)的,我们需要加上 参数“-rf”,也就是强制递归删除文件夹(目录)

4、文件夹(目录)删除命令—rmdir

它可以不加任何参数的删除掉指定的文件夹(目 录),命令格式如下:

rmdir [参数] [文件夹(目录)]
命令主要参数如下:
-p 删除指定的文件夹(目录)以后,若上层文件夹(目录)为空文件夹(目录)的话就将其一起
删除。
5、文件复制命令—cp
cp [参数] [源地址] [目的地址]
主要参数描述如下:
-a 此参数和同时指定“-dpR”参数相同
-d 在复制有符号连接的文件时,保留原始的连接。
-f 强行复制文件,不管要复制的文件是否已经存在于目标目录。
-I 覆盖现有文件之前询问用户。
-p 保留源文件或者目录的属性。
-r 或-R递归处理,将指定目录下的文件及子目录一并处理

        通配符“*”,“*.c”就表示 test1 下的所有以“.c”结尾的文件,也就是 a.c 和 b.c。“../test2”中的“../”表示上级目录,因此“../test2”就是上级目录下的 test2 文件夹。

6、文件移动命令—mv
mv [参数] [源地址] [目的地址]
主要参数描述如下:
-b 如果要覆盖文件的话覆盖前先进行备份。
-f 若目标文件或目录与现在的文件重复,直接覆盖目标文件或目录。
-I 在覆盖之前询问用户。

3.文件压缩和解压缩

Ubuntu 下图形化以及命 令行这两种压缩和解压缩操作:

1、图形化压缩和解压缩

在要压缩或者解压的文件上点击鼠标右键, 然后选择要进行的操作——压缩/提取

2、命令行进行文件的压缩和解压缩

命令行下进行压缩和解压缩常用的命令有三个:zip、unzip 和 tar:

①命令 zip

zip 命令是针对.zip 文件的,用于将一个或者多个文件压缩成一个.zip 结尾的文件,格式如下:

zip [参数] [压缩文件名.zip] [被压缩的文件]
主要参数函数如下:
-b<工作目录> 指定暂时存放文件的目录。
-d 从 zip 文件中删除一个文件。
-F 尝试修复已经损毁的压缩文件。
-g 将文件压缩入现有的压缩文件中,不需要新建压缩文件。
-h 帮助。
-j 只保存文件的名,不保存目录。
-m 压缩完成以后删除源文件。
-n<字尾符号> 不压缩特定扩展名的文件。
-q 不显示压缩命令执行过程。
-r 递归压缩,将指定目录下的所有文件和子目录一起压缩。
-v 显示指令执行过程。
-num 压缩率,为 1~9 的数值。

使用 zip 命令进行 test2 文件夹的压缩,我们使用的命令如下: zip -rv test2.zip test2

②命令 unzip
unzip [参数] [压缩文件名.zip]
主要参数如下:
-l 显示压缩文件内所包含的文件。
-t 检查压缩文件是否损坏,但不解压。
-v 显示命令显示的执行过程。
-Z 只显示压缩文件的注解。
-C 压缩文件中的文件名称区分大小写。
-j 不处理压缩文件中的原有目录路径。
-L 将压缩文件中的全部文件名改为小写。
-n 解压缩时不要覆盖原有文件。
-P<密码> 解压密码。
-q 静默执行,不显示任何信息。
-x<文件列表> 指定不要处理.zip 中的哪些文件。
-d<目录> 把压缩文件解到指定目录下。
③命令 tar

        Linux 下最常用的.bz2 和.gz 这两种压缩格式。其它格式的压缩和解压使用 命令 tar,tar 将压缩和解压缩集合在一起,使用不同的参数即可,命令格式如下:

tar [参数] [压缩文件名] [被压缩文件名]
常用参数如下:
-c 创建新的压缩文件。
-C<目的目录> 切换到指定的目录。
-f<备份文件> 指定压缩文件。
-j 用 tar 生成压缩文件,然后用 bzip2 进行压缩。
-k 解开备份文件时,不覆盖已有的文件。
-m 还原文件时,不变更文件的更改时间。
-r 新增文件到已存在的备份文件的结尾部分。
-t 列出备份文件内容。
-v 显示指令执行过程。
-w 遭遇问题时先询问用户。
-x 从备份文件中释放文件,也就是解压缩文件。
-z 用 tar 生成压缩文件,用 gzip 压缩。
-Z 用 tar 生成压缩文件,用 compress 压缩。

在上面命令中,-vcjf 表示创建 bz2 格式的压缩文件,-vczf 表示创建.gz 格式的压缩文 件。

        上述两行命令中,-vxjf 用来完成.bz2 格式压缩文件的解压,-vxzf 用来完成.gz 格式压缩文 件的解压。要熟练掌握使用 tar 命令来完成.bz2 和.gz 格式的文件压缩和解压缩。

4.文件查询和搜索

        在嵌入式 Linux 开发中常常需要在 Linux 源码文件中查询某个文件是否存在,或者搜索哪些文件都调用了某个函数等等。本节我们就讲解两个最 常用的文件查询和搜索命令:find grep

1、命令 find

find 命令用于在目录结构中查找文件,其命令格式如下:

find [路径] [参数] [关键字]
路径是要查找的目录路径,如果不写的话表示在当前目录下查找,关键字是文件名的一部
分,主要参数如下:
-name<filename> 按照文件名称查找,查找与 filename 匹配的文件,可使用通配符。
-depth 从指定目录下的最深层的子目录开始查找。
-gid<群组识别码> 查找符合指定的群组识别码的文件或目录。
-group<群组名称> 查找符合指定的群组名称的文件或目录。
-size<文件大小> 查找符合指定文件大小的文件。
-type<文件类型> 查找符合指定文件类型的文件。
-user<拥有者名称>查找符合指定的拥有者名称的文件或目录。
find 命令的参数有很多,常用的就这些,关于其它的参数大家可以自行上网查找
2、命令 grep

        在文件中搜索一串关键字,grep 就是完 成这个功能的,grep 命令用于查找包含指定关键字的文件,如果发现某个文件的内容包含所指 定的关键字,grep 命令就会把包含指定关键字的这一行标记出来,grep 命令格式如下:

grep [参数] 关键字 文件列表
grep 命令一次只能查一个关键字,主要参数如下:
-b 在显示符合关键字的那一列前,标记处该列第 1 个字符的位编号。
-c 计算符合关键字的列数。
-d<进行动作> 当指定要查找的是目录而非文件时,必须使用此参数!否则 grep 指令将回
报信息并停止搜索。
-i 忽略字符大小写。
-v 反转查找,只显示不匹配的行。
-r 在指定目录中递归查找。
5.文件类型

使用命令“ls -l”来查看用户根目录下所有文件的详细信息

在上图中,每个文件的详细信息占一行,每行最前面都是一个符号就标记了当前文件类型, 比如 test1 的第一个字符是“d”,test1.tar.bz2 文件第一个字符是“-”。这些字符表示的文件类型如下:

- 普通文件,一些应用程序创建的,比如文档、图片、音乐等等。
d 目录文件。
c 字符设备文件,Linux 驱动里面的字符设备驱动,比如串口设备,音频设备等。
b 块设备文件,存储设备驱动,比如硬盘,U 盘等。
l 符号连接文件,相当于 Windwos 下的快捷方式。
s 套接字文件。
p 管道文件,主要指 FIFO 文件。

后面学习 Linux 驱动开发的时候基本是在和字符设备文件块设备文件打交道。

<5>Linux 用户权限管理

1.Ubuntu 用户系统

        装系统的时候创建的用户其权限比后面创建的用户大一点,但是没有 root 用户权限大, Ubuntu 下用户类型分为以下 3 类:

● 初次创建的用户,此用户可以完成比普通用户更多的功能。

● root 用户,系统管理员,拥有所有权利。

● 普通用户,安装完操作系统以后被创建的用户。

        以上三种用户,每个用户都有一个 ID 号,称为 UID,操作系统通过 UID 来识别是哪个用 户,用户相关信息可以在文件/etc/passwd 中查看到

        从配置文件 passwd 中可以看到,每个用户名后面都有两个数字,比如用户“zuozhongkai” 后面“1000:1000”,第一个数字是用户的 ID,另一个是用户的 GID,也就是用户组 ID。Ubuntu 里面每个用户都属于一个用户组里面,用户组就是一组有相同属性的用户集合。

2.权限管理

        对于嵌入式开发一般不关注用户的权限问题,因为嵌入式基本是单用户,做嵌入式开发重点关注的是文件的权限问题。 对于一个文件通常有三种权限:读(r)、写(w)和执行(x),使用命令“ls -l”可以查看某个目 录下所有文件的权限信息,如:

-rw-rw-r-- 1 zuozhongkai zuozhongkai 0 12 月 25 20:44 test.c

        其中“-rw-rw-r--”表示文件权限与用户和用户组之间的关系,第一位表示文件类型,上一 小节已经说了。剩下的 9 位以 3 位为一组分别表示文件拥有者的权限,文件拥有者所在用户组的权限以及其它用户权限。后面的“zuozhongkai zuozhongkai”分别代表文件拥有者(用户) 和该用户所在的用户组,因此文件 test.c 的权限情况如下:

        ①、文件 test.c 的拥有者是用户 zuozhongkai,其对文件 tesst.c 的权限是“rw-”,也就是 对该文件拥有读和写两种权限。

        ②、用户 zuozhongkai 所在的用户组也叫做 zuozhongkai,其组内用户对于文件 test.c 的权 限是“rw-”,也是拥有读和写这两种权限。         

        ③、其它用户对于文件 test.c 的权限是“r--”,也就是只读权限。 对于文件,可读权限表示可以打开查看文件内容,可写权限表示可以对文件进行修改,可执行权限就是可以运行此文件(如果是软件的话)。对于文件夹,拥有可读权限才可以使用命令 ls 查看文件夹中的内容,拥有可执行权限才能进入到文件夹内部

        除了用 r、w 和 x 表示以外, 我们也可以使用二进制数表示,三种权限就可以使用 3 位二进制数来表示,一种权限对应一个 二进制位,如果该位为 1 就表示具备此权限,如果该位为 0 就表示没不具备此权限,如下表所示:

        前面的文件 test.c 其权限为“rw-rw-r--”,因此其十进制表示就是:664。

        另外我们也开始使用 a、u、g 和 o 表示文件的归属关系,用=、+和-表示文件权限的变化, 如下表所示:

        对于文件 test.c,我们想要修改其归属用户(zuozhongkai)对其拥有可执行权限,那么就可以 使用:u+x。如果希望设置归属用户及其所在的用户组都对其拥有可执行权限就可以使用:gu+x。

3.权限管理命令

        可以使用 Shell 来操作文件的权限管理,主要用到“chmod”和“chown”这两个命令:

1、权限修改命令 chmod

        命令“chmod”用于修改文件或者文件夹的权限,权限可以使用前面讲的数字表示也可以 使用字母表示,命令格式如下:

chmod [参数] [文件名/目录名]
主要参数如下:
-c 效果类似“-v”参数,但仅回显更改的部分。
-f 不显示错误信息。
-R 递归处理,指定目录下的所有文件及其子文件目录一起处理。
-v 显示指令的执行过程。

        在上图中,我们修改文件 test 的权限为 766,修改完成以后的 test 文件权限为“rwxrw-rw-”, 和我们设置的一样,说明权限修改成功。上面我们是通过数字来修改权限的,我们接下来使用字母来修改权限,操作如下图所示:

        上面两个例子都是修改文件的权限,接下来我们修改文件夹的权限,新建一个 test 文件夹, 在文件夹 test 里面创建 a.c、b.c 和 c.c 三个文件,test 文件夹下的文件 a.c、b.c 和 c.c 的权限均为“rw-rw-r--”,我们将 test 文件夹 下的所有文件权限都改为“rwxrwxrwx”,也就是数字 777,操作如下图所示:

2、文件归属者修改命令 chown

命令 chown 用来修改某个文件或者目录的归属者用户或者用户组,命令格式如下:

chown [参数] [用户名.<组名>] [文件名/目录]
其中[用户名.<组名>]表示要将文件或者目录改为哪一个用户或者用户组,用户名和组名用
“.”隔开,其中用户名和组名中的任何一个都可以省略,命令主要参数如下:
-c 效果同-v 类似,但仅回显更改的部分。
-f 不显示错误信息。
-h 只对符号连接的文件做修改,不改动其它任何相关的文件。
-R 递归处理,将指定的目录下的所有文件和子目录一起处理。
-v 显示处理过程。

<6>Linux 磁盘管理

1.Linux 磁盘管理基本概念

        Linux 的磁盘管理体系和 Windows 有很大的区别,在 Windows 下经常会遇到“分区”这个概念,在 Linux 中一般不叫“分区”而叫“挂载点”。 “挂载点”就是将一个硬盘的一部 分做成文件夹的形式,这个文件夹的名字就是“挂载点”,不管在哪个发行版的 Linux 中,用 户是绝对看到不到 C 盘、D 盘这样的概念的,只能看到以文件夹形式存在的“挂载点”。

文件/etc/fstab 详细的记录了 Ubuntu 中硬盘分区的情况:

        “/ was on /dev/sda1 during installation”,意思是根目录“/”是在/dev/sda1 上的,其中“/”是挂载点,“/dev/sda1”就是我们装 Ubuntu 系统的硬盘。由于我们的系统是安装在虚拟机中的,因此图 中没有出现实际的硬盘。可以通过如下命令查看当前系统中的磁盘:

ls /dev/sd*

上述命令就是打印出所有以/dev/sd 开头的设备文件

        在图中有四个磁盘设备文件,其中 sd 表示是 SATA 硬盘或者其它外部设备,最后面的数字表示该硬盘上的第 n 个分区,比如/dev/sda1 就表示磁盘 sda 上的第一个分区。图中都是以/dev/sda 开头的,说明当前只有一个硬盘。如果再插上 U 盘、SD 卡啥的就可能会出 现/dev/sdb,/dev/sdc 等等。如果你的 U 盘有两个分区那么可能就会出现/dev/sdb1、dev/sdb2 这 样的设备文件。比如我现在插入我的 U 盘,插入 U 盘会提示 U 盘是接到主机还是虚拟机

2.磁盘管理命令
1、磁盘分区命令 fdisk

如果要对某个磁盘进行分区,可以使用命令 fdisk,命令格如下:

fdisk [参数]
主要参数如下:
-b<分区大小> 指定每个分区的大小。
-l 列出指定设备的分区表。
-s<分区编号> 将指定的分区大小输出到标准的输出上,单位为块。
-u 搭配“-l”参数,会用分区数目取代柱面数目,来表示每个分区的起始地址。

        比如我要对 U 盘进行分区,千万不要对自己装 Ubuntu 系统进行分区!!!可以使用如下命令:

sudo fdisk /dev/sdb

p 显示现有的分区

n 建立新分区

t 更改分区类型

d 删除现有的分区

a 更改分区启动标志

w 对分区的更改写入到硬盘或者存储器中

q 不保存退出

2、格式化命令 mkfs

        使用命令 fdisk 创建好一个分区以后,我们需要对其格式化,也就是在这个分区上创建一 个文件系统,Linux 下的格式化命令为 mkfs,命令格式如下:

mkfs [参数] [-t 文件系统类型] [分区名称]
主要参数如下:
fs 指定建立文件系统时的参数
-V 显示版本信息和简要的使用方法。
-v 显示版本信息和详细的使用方法。

比如我们要格式化 U 盘的分区/dev/sdb1 为 FAT 格式,那么就可以使用如下命令:

mkfs –t vfat /dev/sdb1
3、挂载分区命令 mount

        我们需要将/dev/sdb1 这个分区挂载到一个文件夹中,然后通过这个文件访问 U 盘, 磁盘挂载命令为 mount,命令格式如下:

mount [参数] -t [类型] [设备名称] [目的文件夹]
命令主要参数有:
-V 显示程序版本。
-h 显示辅助信息。
-v 显示执行过程详细信息。
-o ro 只读模式挂载。
-o rw 读写模式挂载。
-s-r 等于-o ro。
-w 等于-o rw。

        一般我们把挂载点放到“/mnt” 目录下,在“/mnt”下创建一个 tmp 文件夹,然后将 U 盘的/dev/sdb1 分区挂载到/mnt/tmp 文 件夹里面,操作如图所示:

4、卸载命令 umount

        当我们不在需要访问已经挂载的 U 盘,可以通过 umount 将其从卸载点卸除,命令格式如下:

umount [参数] -t [文件系统类型] [设备名称]
-a 卸载/etc/mtab 中的所有文件系统。
-h 显示帮助。
-n 卸载时不要将信息存入到/etc/mtab 文件中
-r 如果无法成功卸载,则尝试以只读的方式重新挂载。
-t <文件系统类型> 仅卸载选项中指定的文件系统。
-v 显示执行过程。

        上面我们将 U 盘挂载到了文件夹/mnt/tmp 里面,这里我们使用命令 umount 将其卸载掉, 操作如图所示:

3.Linux C 编程入门

        Ubuntu 下也有一些可以进行编程的工具,但是大多都只是编辑 器,也就是只能进行代码编辑,如果要编译的话就需要用到 GCC 编译器,使用 GCC 编译器 肯定就要接触到 Makefile。本章就讲解如何在 Ubuntu 下进行 C 语言的编辑和编译、GCC 和 Makefile 的使用和编写。

        代码编写工具很多,比如 VIM 编辑器、Emacs 编辑器、VScode 编辑器等等,本教程使用 Ubuntu 自带的 VIM 编辑器。

<1>编写代码

首先设置 TAB 键为 4 字节

        VI 编辑器默认 TAB 键为 8 空格,我们改成 4 空格,用 vi 打开文件/etc/vim/vimrc,在此文件最后面输入如下代码:

set ts=4

接着设置 VIM 编辑器显示行号:

set nu

然后使用vim编写代码保存。

<2>编译代码

Ubuntu 下的 C 语言编译器是 GCC,GCC 编译器在我们安装 Ubuntu 的时候就已经默认安 装好了,可以通过如下命令查看 GCC 编译器的版本号:

gcc -v

        如果输入命令“gcc -v”命令以后,你的终端输出信息,那么说明你 的电脑已经有 GCC 编译器了。最后下面的“gcc version 5.4.0”说明本机的 GCC 编译器版本为 5.4.0 的。注意观察在图 3.1.2.1 中有“Target: x86_64-linux-gnu”一行,这说明 Ubuntu 自带的 GCC 编译器是针对 X86 架构的,因此只能编译在 X86 架构 CPU 上运行的程序。如果想要编译在 ARM 上运行的程序就需要针对 ARM 架构的 GCC 编译器,也就是交叉编译器!我们进行 ARM 开发,因此肯定要安装针对 ARM 架构的 GCC 交叉编译器,当然了,这是后面的事, 现在我们不用管这些,只要知道不同的目标架构,其 GCC 编译器是不同的。

        如何使用 GCC 编译器来编译 main.c 文件呢?GCC 编译器是命令模式的,因此需要输入命 令来使用 gcc 编译器来编译文件,输入如下命令:

gcc main.c -o main

        我们使用“gcc main.c –o main”来编译 main.c 文件,使用参数“-o”来指 定编译生成的可执行文件名字。

<3>GCC 编译器

1、gcc 命令格式如下:
gcc [选项] [文件名字]
主要选项如下:
-c 只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o<输出文件名> 用来指定编译结束以后的输出文件名,如果不使用这个选项的话 GCC
默认编译出来的可执行文件名字为 a.out。
-g 添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编
译的时候生成调试所需的符号信息。
-O 对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进
行优化,这样产生的可执行文件执行效率就高。
-O2 比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
2、编译流程

        GCC 编译器的编译流程是:预处理、汇编、编译和链接。预处理就是对程序中的宏定义等相关的内容先进行前期的处理。汇编是先将 C 文件转换为汇编文件。当 C 文件转换为汇编文件以后就是文件编译了,编译过程就是将 C 源文件编译成.o 结尾的目标文件。编译生成的.o 文件不能直接执行,而是需要最后的链接,如果你的工程有很多个 c 源文件的话最终就会有很多.o 文件,将这些.o 文件链接在一起形成完整的一个可执行文件

<4>Makefile 基础

1、Makefile 简介

        当文件数量很多时用终端输入 GCC 命令的方法显然是不现实的。编写一个文件,这个文件描述了编译哪些源码文件、如何编译,每次需要编译工程的时只需要使用这个文件就行了,为此提出了一个 解决大工程编译的工具Make描述哪些文件需要编译、哪些需要重新编译的文件就叫做 Makefile,Makefile 就跟脚本文件一样,Makefile 里面还可以执行系统命令。使用的时候只需要一个 make 命令即可完成整个工程的自动编译,极大的提高了软件开发的效率。如果大家以 前一直使用 IDE 来编写 C 语言的话肯定没有听说过 Makefile 这个东西,其实这些 IDE 是有的, 只不过这些 IDE 对其进行了封装,提供给大家的是已经经过封装后的图形界面了,我们在 IDE 中添加要编译的 C 文件,然后点击按钮就完成了编译。在 Linux 下用的最多的是 GCC 编译器, 这是个没有 UI 的编译器,因此 Makefile 就需要我们自己来编写了。作为一个专业的程序员, 是一定要懂得 Makefile 的,一是因为在 Linux 下你不得不懂 Makefile,再就是通过 Makefile 你就能了解整个工程的处理过程。如果想详细的研究 Makefile,推荐阅读《跟我一起写 Makefile》这份文档。

2、Makefile 的引入

        我们完成这样一个小工程,在这个工程中我们有 main.c、input.c 和 calcu.c 这三个 C 文件和 input.h、calcu.h 这两个头文件。其中 main.c 是主体。接下来使用 gcc 的方法来对其进行编译, 在终端输入如下命令:

gcc main.c calcu.c input.c -o main

       如果有一个文件被修改了,使用上面的命令编译的时候所有的文件都会重新编译。最好的办法肯定是哪个文件被修改了,只编译这个修改的文件即可,其它没有修改的文件就不需要再次重新编译了,为此我们改变我们的编译方法,如果第一次编译工程,我们先将工程中的文件都编译一遍,然后后面修改了哪个文件就编译哪个文件, 命令如下:

gcc -c main.c
gcc -c input.c
gcc -c calcu.c
gcc main.o input.o calcu.o -o main

        上述命令前三行分别是将 main.c、input.c 和 calcu.c 编译成对应的.o 文件,所以使用了“-c” 选项,“-c”选项我们上面说了,是只编译不链接。最后一行命令是将编译出来的所有.o 文件链接成可执行文件 main。假如我们现在修改了 calcu.c 这个文件,只需要将 caclue.c 这一个文 件重新编译成.o 文件,然后再将所有的.o 文件链接成可执行文件,只需要下面两条命令即可:

gcc -c calcu.c
gcc main.o input.o calcu.o -o main

        但是这样就又有一个问题,如果修改的文件一多,会非常麻烦,为此我们需要这样一个工具:

1、如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。

2、如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可

3、如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且 链接成可执行文件。

        很明显,能够完成这个功能的就是 Makefile 了,在工程目录下创建名为“Makefile”的文件, 文件名一定要叫做“Makefile”!!!区分大小写

        Makefile 和 C 文件可以处于同一个目录的,在 Makefile 文件中输入如下代码:

main: main.o input.o calcu.o
    gcc -o main main.o input.o calcu.o
main.o: main.c
    gcc -c main.c
input.o: input.c
    gcc -c input.c
calcu.o: calcu.c
    gcc -c calcu.c

clean:
    rm *.o
    rm main

        上述代码中所有行首需要空出来的地方一定要使用“TAB”键!不要使用空格键!这是 Makefile 的语法要求。(可以看出这里的Makefile文件类似于脚本,把所有文件编译指令集合)

        Makefile 编写好以后我们就可以使用 Make 命令来编译我们的工程了,直接在命令行中输 入“make”即可,Make 命令会在当前目录下查找是否存在“Makefile”这个文件,如果存在 的话就会按照 Makefile 里面定义的编译方式进行编译。

        使用命令“Make”编译完成以后就会在当前工程目录下生成各种.o 和可执行文件,说明我们编译成功了。使用 make 命令编译工程的时候可能会提示如图所示错误:

错误来源一般有两点:

1、Makefile 中命令缩进没有使用 TAB 键!

2、VI/VIM 编辑器使用空格代替了 TAB 键,修改文件/etc/vim/vimrc,在文件最后面加上 如下所示代码:

set noexpandtab

        之后再输入make指令只会重新编译被修改的文件和最后的可执行文件,其它没有修改过的文件就没有编译。

3、Makefile 语法
①Makefile 规则格式

Makefile 里面是由一系列的规则组成的,这些规则格式如下:

目标…... : 依赖文件集合……
    命令 1
    命令 2
    ……

比如下面这条规则:

main : main.o input.o calcu.o
    gcc -o main main.o input.o calcu.o

        这条规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,如果要更新 目标 main,就必须要先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目 标也必须更新,“更新”就是执行一遍规则中的命令列表

        命令列表中的每条命令必须以 TAB 键开始,不能使用空格! make 命令会为 Makefile 中的每个以 TAB 开始的命令创建一个 Shell 进程去执行

        在之前的代码中一共有 5 条规则,1~2 行为第一条规则,3~4 行为第二条规则,5~6 行为第三 条规则,7~8 行为第四条规则,10~12 为第五条规则,make 命令在执行这个 Makefile 的时候其执行步骤如下:

        首先更新第一条规则中的 main,第一条规则的目标成为默认目标只要默认目标更新了那么就完成了 Makefile 的工作,完成了整个 Makefile 就是为了完成这个工作。在第一次编译的时候由于 main 还不存在,因此第一条规则会执行。

        第一条规则依赖于文件 main.o、input.o 和 calcu.o 这个三个.o 文件,这三个.o 文件目前还都没有,因此必须先更新这三个文件。make 会查找以这三个.o 文件为目标的规则并执行。以 main.o 为例,发现更新 main.o 的是第二条规则,因此会执行第二条规则,第二条规则里面的命令为“gcc –c main.c”,这行命令很熟悉了 吧,就是不链接编译 main.c,生成 main.o,其它两个.o 文件同理。

        最后一个规则目标是 clean, 它没有依赖文件,因此会默认为依赖文件都是最新的,所以其对应的命令不会执行,当我们想要执行 clean 的话可以直接使用命令“make clean”执行以后就会删除当前目录下所有的.o 文件以及 main,因此 clean 的功能就是完成工程的清理

我们在来总结一下 Make 的执行过程:

1) make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。

2) 当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。

3) 当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标

        除了 Makefile 的“终极目标”所在的规则以外,其它规则的顺序在 Makefile 中是没有意义的,“终极目标”就是指在使用 make 命令的时候没有指定具体的目标时,make 默认的那个目标,它是 Makefile 文件中第一个规则的目标,如果 Makefile 中的第一个规则有多个目标, 那么这些目标中的第一个目标就是 make 的“终极目标”。

②Makefile 变量

跟 C 语言一样 Makefile 也支持变量的,先看一下前面的例子:

 main: main.o input.o calcu.o
     gcc -o main main.o input.o calcu.o

        上述 Makefile 语句中,main.o input.o 和 calcue.o 这三个依赖文件,我们输入了两遍,我们 这个 Makefile 比较小,如果 Makefile 复杂的时候这种重复输入的工作就会非常费时间,而且非常容易输错,为了解决这个问题,Makefile 加入了变量支持。Makefile 中的变量都是字符串类似 C 语言中的宏。使用变量将上面的代码修改,修改以后如下所示:

#Makefile 变量的使用
objects = main.o input.o calcu.o
main: $(objects)
    gcc -o main $(objects)

        第 1 行是注释,Makefile 中可以写注释,注释开头要用符号“#”,第 2 行我们定义了一个变量 objects, 并且给这个变量进行了赋值,其值为字符串“main.o input.o calcu.o”,第 3 和 4 行使用到了变 量 objects,Makefile 中变量的引用方法是“$(变量名)”,比如本例中的“$(objects)”就是使用 变量 objects。

        在“示例代码中我们在定义变量 objects 的时候使用“=”对其进行了赋值,Makefile 变量的赋值符还有其它两个“:=”和“?=”,我们来看一下这三种赋值符的区别:

1、赋值符“=”

        使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值,比如如下代码:

name = zzk
curname = $(name)
name = zuozhongkai

print:
	@echo curname: $(curname)

        我们来分析一下上述代码,第 1 行定义了一个变量 name,变量值为“zzk”,第 2 行也定义了一个变量 curname,curname 的变量值引用了变量 name,按照我们 C 写语言的经验此时 curname 的值就是“zzk”。第 3 行将变量 name 的值改为了“zuozhongkai”,第 5、6 行是输 出变量 curname 的值。在 Makefile 要输出一串字符的话使用“echo”,就和 C 语言中的“printf” 一样,第 6 行中的“echo”前面加了个“@”符号,因为 Make 在执行的过程中会自动输出命令执行过程,在命令前面加上“@”的话就不会输出命令执行过程,大家可以测试一下不加“@” 的效果。使用命令“make print”来执行上述代码。借助另外一个变量,可以将变量的真实值推到后面去定义。也就是变量的真实值取决于它所引用的变量的最后一次有效值

2、赋值符“:=”

        修改上述代码第 2 行,将 其中的“=”改为“:=”。此时的 curname 是 zzk,不是 zuozhongkai 了。这是因为赋值符“:=” 不会使用后面定义的变量,只能使用前面已经定义好的,这就是“=”和“:=”两个的区别。

3、赋值符“?=”

        如果变量 curname 前面没有被赋值,那么此变量就是“zuozhongkai”如果前面已经赋过值了,那么就使用前面赋的值

4、变量追加“+=”

        Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进 去,此时就要使用到符号“+=”,比如如下所示代码:

    objects = main.o inpiut.o
    objects += calcu.o

一开始变量 objects 的值为“main.o input.o”,后面我们给他追加了一个“calcu.o”,因此 变量 objects 变成了“main.o input.o calcu.o”,这个就是变量的追加。

③Makefile 模式规则

        上述 Makefile 中第 3~8 行是将对应的.c 源文件编译为.o 文件,每一个 C 文件都要写一个对应的规则,如果工程中 C 文件很多的话显然不能这么做。为此,我们可以使用 Makefile 中的模式规则,通过模式规则我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件

        模式规则中,至少在规则的目标定定义中要包涵“%”,否则就是一般规则,目标中的“%” 表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾 的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件

        当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值,使用 方法如下:

%.o : %.c
    命令
objects = main.o input.o calcu.o
main: $(objects)
	gcc -o main $(objects)

%.o : %.c
	#命令

clean:
	rm *.o 
	rm main

        修改以后的 Makefile 还不能运行,因为第 6 行的命令还没写,第 6 行的命令我们需要借助另外一种强大的变量—自动化变量

④Makefile 自动化变量

        上面讲的模式规则中,目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,如何通过一行命令来从不同的依赖文件中生成对应的目标呢?自动化变量就是完成这个功能的!所谓自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个取出直至所有的符合模式的文件都取完,自动化变量只应该出现在规则的命令中,常用的自动化变量如表所示:

        表中的 7 个自动化变量中,常用的三种:$@、$<和$^,我们使用自动化变量来完 成“示例代码中的 Makefile,最终的完整代码如下所示:

objects = main.o input.o calcu.o
main: $(objects)
	gcc -o main $(objects)

%.o : %.c
	gcc -c $<
	
clean:
	rm *.o 
	rm main

⑤Makefile 伪目标

        Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,而伪目标不代表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令

        使用伪目标的主要是为了避免 Makefile 中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的,比如在前面代码规则“clean”代码用来完成清理工程的功能。

        上述规则中并没有创建文件 clean 的命令,因此工作目录下永远都不会存在文件 clean,当 我们输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行。可是如果我们“手贱”,在工作目录下创建一个名为“clean”的文件,那就不一样了,当执行“make clean”的 时候,规则因为没有依赖文件,所以目标被认为是最新的,因此后面的 rm 命令也就不会执行, 我们预先设想的清理工程的功能也就无法完成。为了避免这个问题,我们可以将 clean 声明为 伪目标,声明方式如下:

.PHONY : clean
objects = main.o input.o calcu.o
main: $(objects)
	gcc -o main $(objects)
	
.PHONY : clean

%.o : %.c
	gcc -c $<
	
clean:
	rm *.o 
	rm main

        上述代码第 5 行声明 clean 为伪目标,声明 clean 为伪目标以后不管当前目录下是否存在名为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行

⑥Makefile 条件判断

语法有两种如下:

<条件关键字>
    <条件为真时执行的语句>
endif
以及:
<条件关键字>
    <条件为真时执行的语句>
else
    <条件为假时执行的语句>
endif

        其中条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,这四个关键字其实分为两对、ifeq 与 ifneq、ifdef 与 ifndef,先来看一下 ifeq 和 ifneq,ifeq 用来判断是否相等,ifneq 就是判断是 否不相等,ifeq 用法如下:

ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘<参数 2>’ 
ifeq “<参数 1>”,“<参数 2>”
ifeq “<参数 1>”,‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”

        上述用法中都是用来比较“参数 1”和“参数 2”是否相同,如果相同则为真,“参数 1” 和“参数 2”可以为函数返回值。ifneq 的用法类似,只不过 ifneq 是用来了比较“参数 1”和 “参数 2”是否不相等,如果不相等的话就为真。

        ifdef 和 ifndef 的用法如下:

ifndef <变量名>

        如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以 是一个函数的返回值。ifndef 用法类似,但是含义与 ifdef 相反。

⑦Makefile 函数使用

        Makefile 支持函数,类似 C 语言一样,Makefile 中的函数是已经定义好的,我们直接使用, 不支持我们自定义函数。make 所支持的函数不多,但是绝对够我们使用了,函数的用法如下:

$(函数名 参数集合)
或者
${函数名 参数集合}

        可以看出,调用函数和调用普通变量一样,使用符号“$”来标识。参数集合是函数的多个参数,参数之间以逗号“,”隔开函数名和参数之间以“空格”分隔开,函数的调用以“$” 开头。接下来我们介绍几个常用的函数,其它的函数大家可以参考《跟我一起写 Makefile》这份文档。

1、函数 subst

函数 subst 用来完成字符串替换,调用形式如下:

$(subst <from>,<to>,<text>)

2、函数 patsubst

函数 patsubst 用来完成模式字符串替换,使用方法如下:

$(patsubst <pattern>,<replacement>,<text>)

        此函数查找字符串<text>中的单词是否符合模式<pattern>,如果匹配就用<replacement>来
替换掉,<pattern>可以使用包括通配符“%”,表示任意长度的字符串,函数返回值就是替换
后的字符串。如果<replacement>中也包涵“%”,那么<replacement>中的“%”将是<pattern>
中的那个“%”所代表的字符串,比如:

$(patsubst %.c,%.o,a.c b.c c.c)

        将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的 字符串为“a.o b.o c.o”。

3、函数 dir

函数 dir 用来获取目录,使用方法如下:

$(dir <names…>

        此函数用来从文件名序列中提取出目录部分,返回值是文件名序列的目 录部分,比如:

$(dir </src/a.c>)

        提取文件“/src/a.c”的目录部分,也就是“/src”。

4、函数 notdir

函数 notdir 看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:

$(notdir <names…>)

        上个例子“dir”改成“notdir”结果是文件名“a.c”。

5、函数 foreach

foreach 函数用来完成循环,用法如下:

$(foreach <var>, <list>,<text>)

        此函数的意思就是把参数<list>中的单词逐一取出来放到参数<var>中,然后再执行<text>
所包含的表达式。每次<text>都会返回一个字符串,循环的过程中,<text>中所包含的每个字
符串会以空格隔开,最后当整个循环结束时,<text>所返回的每个字符串所组成的整个字符串
将会是函数 foreach 函数的返回值。

6、函数 wildcard

        通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时, 通配符不会自动展开,这个时候就要用到函数 wildcard,使用方法如下:

$(wildcard PATTERN…)

比如:

$(wildcard *.c)

        上面的代码是用来获取当前目录下所有的.c 文件,类似“%”。

4.其他资料

9个Linux系统常用监控命令icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/29235669

Linux系统命令 - 查看内存使用情况icon-default.png?t=N7T8https://blog.csdn.net/renfufei/article/details/105851728

图像识别小车(jetson nano部分)——电赛学习笔记(3)icon-default.png?t=N7T8https://blog.csdn.net/qq_32971095/article/details/131511658

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

switch_swq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值