嵌入式学习之Linux入门篇

嵌入式学习之Linux入门篇

以下内容整理自:【北京迅为】嵌入式学习之Linux入门篇_哔哩哔哩_bilibili

1. Ubuntu

Ubuntu是Linux的发行版之一,其他发行版还有radhat centos debian opewrt等

Ubuntu分为:没有界面的Ubuntu(Ubuntu-core);有界面的Ubuntu(Ubuntu-desktop)。

Ubuntu的组成:Ubuntu -core + 第三方桌面

Ubuntu-core + gnome = Ubuntu

​ Ubuntu-core + kde = kubuntu

​ Ubuntu-core + lxde = lubuntu

1.1 启用root用户

命令行:**当前操作用户@主机名:~(**(代表不是root用户)

打开root:

sudo passwd
复制代码

然后设置密码

完成后输入:

su root
复制代码

输入密码进入root模式(#代表root用户)

退出root用户:

exit
复制代码

1.2 使用apt-get下载

实现软件自动下载、安装、配置

设置下载源:在software&updates中设置

更新下载源:

sudo apt-get update//这个命令会访问源列表里面的每个网址,并读取软件列表,然后保存在本地电脑。
复制代码

安装软件:

sudo apt-get install <软件名>// eg: apt-get install vim
复制代码

软件更新:

sudo apt-get upgrade//这个命令它会与我们使用apt-getupdate下载的软件列表的软件进行对比,如果发现安装的版本过低,就会提示更新,如果软件已经是最新版本,就不必要更新了。
复制代码

软件卸载:

sudo apt-get remove <软件名>//eg: apt-get remove vim
复制代码

1.3 Vim编辑器的使用

vi编辑器是Unix系统最初的编辑器。它使用控制台图形模式来模拟文本编辑窗口,允许查看文件中的行、在文件中移动、插入、编辑和替换文本。尽管它可能是世界上最复杂的编辑器,但其拥有的大量特性使其成为Unix系统管理员多年来的支柱性工具。在GNU项目将vi编辑器移植到开源世界时,他们决定对其做一些改进。由于它不再是以前Unix中的那个原始的vi编辑器了,开发人员也就将它重命名为viimproved,或vim

vim是vi的加强版

打开vim编辑器,直接在控制台输入:

vi <filename> //eg: vi helloworld.c
//如果打开的文件不存在,它会新建一个文件,如果说这个文件存在,那么他就直接打开了。
复制代码

1.3.1 Vim编辑器的三种模式:

进入后直接是普通模式;在键盘上按 i 进入编辑模式(按esc退出编辑模式);命令行模式,输入 : 进入命令行模式(按esc退出命令行模式)

按方向键实现光标移动,vim也有独有的用来移动光标的命令

K:向上移动
J:向下移动
H:向左移动
L:向右移动
Ctrl+F(PageDown):下翻一屏
Ctrl+B(PageUp):上翻一屏
复制代码

1.3.2 快速定位:

gg:将光标定位到第一行
G:将光标定位到最后一行
ngg:将光标定位到第n行
复制代码

1..3.3 文本复制和粘贴:

复制单行:双击 yy

复制多行:

  1. 先定位到要复制内容的首行,按 v,然后移动光标选择文本,选择完成后按 y ;移动光标到要粘贴的地方,按 p 粘贴内容。
  2. 先定位到要复制内容的首行,输入 nyy (eg:3yy) 复制3行

1.3.4 删除文本:

  1. 编辑模式:使用delete键删除

  2. 普通模式:使用dd命令删除光标所在整行

    ​ 使用ndd删除多行

  3. 命令行模式:使用n1, n2d 删除指定范围的行

1.3.5 撤销操作:

普通模式下,直接按 u

反撤销:按 ctrl + r

1.3.6 查找文本

命令行模式,用 “/ + 查找内容” eg: /abc

按“n“查找下一个

1.3.7 替换文本

: %s /oldtext/newtext/g
复制代码

1.3.8 保存退出

:q!  //强行退出
:wq  //保存退出
:q   //未修改直接退出
复制代码

1.3.9 文件的对比

使用:

vimdiff  fiel1 file2
复制代码

1.4 Ubuntu常用命令

1.4.1 查看文件夹命令 ls

我们用 ls 命令来查看文件信息

ls
复制代码

查看隐藏文件 -a;显示文件所有信息 -l

ls-al
复制代码

第一列参数含义:

d://目录文件
-://普通文件
p://管理文件
l://链接文件
b://块设备文件
c://字符设备文件
s://套接字文件
复制代码

文件权限:

r://自读权限
w://写权限
x://可执行权限
-://没有权限
复制代码

1.4.2 切换目录命令 cd

cd ..//返回上一级
复制代码

1.4.3 查看当前目录命令 pwd

2. Linux

2.1 文件路径

2.1.1 绝对路径(完整路径)和相对路径

绝对路径:从根目录开始,linux的根目录是 /

相对路径:相对于当前位置的路径,一般以 **./ **开头

2.1.2 Linux家目录和根目录概念

根目录是Linux中最底层的目录,用 / 表示

cd /
复制代码

家目录,当前用户所在的路径,在/home目录下,用 ~ 表示

root用户的家目录是:/root

2.2 Linux常用命令

2.2.1 创建文件夹命令 mkdir

mkdir test//创建test文件夹
复制代码

创建多级目录:使用 -p 参数

mkdir -p test/test1/test2
复制代码

2.2.2 删除文件夹命令 rmdir

rmdir foldername//只能删除空文件夹

复制代码

2.2.3 删除文件或目录命令 rm

参数:

-r:递归删除该目录下所有子目录(删除目录一定要加r)
-f:强制删除
-i:删除时确认提示
复制代码

2.2.4 创建文件命令touch

touch filename
复制代码

2.2.5 刷新屏幕命令 clear

clear  //清屏,但保存历史记录
复制代码

2.2.6 初始化屏幕命令 reset

reset  //清屏,同时清除记录
复制代码

2.2.7 复制文件或目录命令 cp

cp 旧文件(目录)名 新文件(目录)名
cp old_filename new_filename  //复制文件
cp -r old_foldername new_foldername //复制文件夹,记得添加-r参数,递归复制
cp filenale /path  //将文件复制到新的路径下
复制代码

2.2.8 修改文件(目录)名命令 mv

mv old_filename new_filename  //修改文件名
mv old_foldername new_foldername  //修改文件夹名
复制代码

**移动多个文件可使用通配符 ***

2.2.9 压缩和解压命令 tar

tar [参数] 压缩文件名 要压缩的文件或目录
复制代码
参数:
-c: 创建一个新的压缩包
-x: 对打包文件进行解压缩
-z: gzip格式进行压缩或解压,如果与c结合就是压缩,与-x结合就是解压
-j: bzip2格式进行压缩或解压,如果与c结合就是压缩,与-x结合就是解压
-f: 表示要操作的文件,一般放在参数最后
-v: 显示正在处理的文件
-C: 格式 -C 路径,表示将压缩文件解压到指定路径
复制代码
tar -czf test.gzip test.c //将test.c文件压缩成test.gzip
tar -xzf test.gzip  //解压test.gzip文件

tar -xzf test.gzip -C ../newfolder  //将test.gzip解压到newfolder中

复制代码

2.2.10 查看和配置网络状态命令 ifconfig

ifconfig  //查看当前网络信息
ifconfig 网卡 ip  //设置ip地址 eg: ifconfig ens33 192.168.3.45
ifconfig 网卡 down  //关闭网卡 eg: ifconfig ens33 down
ifconfig 网卡 up  //打卡网卡 eg:ifconfig ens33 up
复制代码

2.2.11 查看文件内容命令 cat

cat filename  //查看文件内容
cat -b filename  //添加-b参数,显示文件内容的行号
复制代码

2.2.12 重启系统命令 reboot

reboot  //重启系统
复制代码

2.2.13 关机命令 poweroff

poweroff  //关机
复制代码

2.2.14 查看windows电脑的ip ipconfig

ipconfig  //查看windows电脑ip
复制代码

2.2.15 ping命令

可以测试本机与目标机器的网络是否联通、速度如何、稳定性如何。

windows ip : 192.168.0.107

ping 192.168.0.107  //测试连接状态
复制代码

2.3 Linux帮助手册

man man //手册一共有9页
1. 可执行的程序或者 shell 命令
2. 系统调用
3. 库调用
4. 设备和特殊文件的帮助,通常在/ dev 下面
5. 配置文件的帮助
6. 游戏的帮助
7. 杂项的帮助
8. 超级用户可以执行的系统命令的帮助
9. 内核相关的
复制代码

按 q 退出手册

查看命令说明

man 1 pwd  //查看pwd使用说明
man -f pwd  //不知道命令在哪儿的情况下,查找命令位置
复制代码

2.4 Linux权限管理

Ubuntu 是一个支持多用户的操作系统,我们可以给不同的使用者创建各种账号,每个使用者有自己的 账号来登录,好处就是可以很好地管理每个用户,我们也可以控制每个用户对系统权限的访问

Ubuntu 的用户分为三类:

  1. root用户
  2. 系统初次创建的用户
  3. 普通用户//开发人员基本不用

用户的信息全部被保存在 /etc/passwd 文件里

使用 ls -l 命令,对于文件一般有三个权限,读权限 r ,写权限 w ,执行权限 x

9 个英文字符划分成三组,每三个字母为一组。第一组:文件拥有者的权限;第二组:文件拥有者所在用户组的权限;第三组:其他用户的权限。第三列: topeet 代表文件拥有者;第四列:topeet 文件拥有者所在的组

因为我们每个文件的权限是由 9 位来表示的,每 3 位为一组,这样我们就可以组合成 8 种不同的情况

2.4.1 chmod命令

功能:改变文件或文件夹的权限

chmod 参数 权限 文件名  //eg: chmod 777 test.c
复制代码

2.5 Linux下连接档的概念

Linux 下的连接档有两个种类。一个是类似于 win 电脑的快捷方式,我们称为软链接,软连接也可以叫做符号链接。另一种是通过文件系统的 inode 连接来产生的,类似于 windows 电脑的复制,但是不产生新的文件,我们称为硬链接。硬链接也可以称作为实体连接

2.5.1 索引节点

inode 也叫做索引节点,内核为每一个新创建的文件都会分配一个索引节点,就是 inode 。inode 是用来存放文件信息的,每个文件都会占用一个 inode ,并且这个 inode 号是唯一的,可以把 inode 简单的理解为一个指针,它永远指向本文本的具体存储位置,文件的属性保存在 inode 里,系统是通过 inode 而不是文件名来定义每一个文件的。

使用 ls -i 命令则可以看到 inode 号

ls -i
复制代码

2.5.2 硬链接

硬链接是一个新的链接到某个 inode 号码的记录。这个链接指向 inode ,系统并给他重新分配 inode 。也就是说会有多个文件对应同一个 inode如果两个文件的 inode 一样,那么这两个文件就是完 全一样的。可以用 ln 命令来建立硬链接

ln 源文件 目标文件
//常用参数 -f ,就是说强制创建,无论目标文件是否存在都要创建连接。
复制代码

使用命令 touch test1.c 创建文件 test1.c,然后使用 ln test1.c test2.c 创建一个硬链接

touch test1.c
ln test1.c test2.c
复制代码

他们的 inode 号码都是 524652 。因为 inode 号一样, 所有这个两个文件的权限和属性也是一模一样的,也就是 test1.c 和 test2.c 是两个完全一样的文件。

我们再创建一个硬连接。使用 ln test1.c test3.c -f 命令后,则会发现我们这个连接数从 2 变成了 3,如 下图所示:

硬链接的优缺点:

优点:

  1. 方便,虽然类似于 windows 的复制,但是通常并不占用实际空间。不管我们是修改 test1.c 或者 是修改 test2.c 还是 test3.c ,只要修改一个,我们的文件就会被同时修改,因为他们的 inode 号都是相同 的。
  2. 安全,防止误删除。我们删除 test1.c 或者是 test2.c 或者 test3.c 任意一个,我们还是可以通 过剩下的连接来访问文件,除非都删掉。我们可以利用这个特点来做文件的备份。

缺点:

  1. 只能在同一个文件系统才可以创建硬连接(因为不同的文件系统管理方式不同),甚至有的文 件系统没有索引号,它不是索引文件系统。哪怕他有索引号,两个文件系统的索引号含义不一定是相同的, 即使它的索引号相同,我们连接几个文件,他有相同的 inode ,但是不同的文件系统中也有可能使用该 inode 的其他文件,这样就会发生冲突,所以说我们只能在同一个文件系统中才能创建硬连接。
  2. 目录之间不能创建硬连接(太复杂,现在还不支持)。如果说硬连接到我们的目录,那么我们 连接的数据需要连同被连接目录下所有数据都要创建硬连接,如果说我们将根目录下的 etc 用硬连接创建 一个硬连接的目录,那么不光是我们的文件要被创建,这个文件下面所有的文件名都要创建一个硬连接, 这样呢就会给工作环境造成一个很大的工作量,而且非常的复杂,所以现在还不支持。

2.5.3 软链接

类似于 windows 上的快捷方式。可以用 ln 命令来建立软链接

ln -s 源文件 目标文件 //(必须加上-s 参数,使用 ln 如果不加任何参数的话,
					//那么就是硬连接 ,而且源文件要用绝对路径)
ln -s /home/topeet/test/test3.c test1.c  //给 test3.c 这个文件创建一个软连接
复制代码

test1.c 和 test3.c 的 inode 号是不一样的,所以这两个文件是完全独立的,总之 软连接就是创立了一个新的文件,当访问这个链接文件的时候,系统就会发现他是一个链接文件,然后读 取链接文件找到真正要访问的文件

因为类似于 windows 上的快捷方式,我们删掉源文件 test3.c ,那么 test1.c 就不能打开了

2.6 Linux目录结构

Linux 整个文件系统是以**“ / ”目录开始,根目录是最顶层,前面讲根目录和家目录概念的时候已经 提到了。它下边包括众多的目录,这些目录又称为子目录,子目录下边又包含更多的目录,它形成了一个 像树一样的结构,大家可以把它想像成一个倒挂的树**,就是从树根开始往下,它的枝叶是一支一支的,也 就是一级一级的。

这个结构是虚拟出来的,没有任何的限制,它只是一个虚拟的概念。所以说从理论上来讲,linux 目录结构可以是随意安排的,就是说我想往哪延伸就往哪延伸,没有任何的限制,但是如果我们所有的人都这样做,不同的人想法不同,那么我们很容易就出现混乱了。

为了解决不同的开发人员之间不统一的问题,研究出层次标准,也就是文件层次标准,简称 FHS ,全 称 filesystem hierarch standard 。FHS 定义了两层规范:

  1. / 目录下面文件夹要存放什么文件,比如说 /etc 下面就应该放配置文件,/bin 或 /sbin 下边就应该放可执行文件
  2. 针对 linux 下 /usr/var 这两个目录的子目录来定义的。比如 /usr/share 下面就应该放共享数据文件。FHS 仅仅给出了最上层顶目录以及子层 /usr和/share 要存放的数据,我们在其他的子目录层,我们就可以随意的来配置

2.6.1 linux 根目录

FHS 对 linux 根文件系统的基本目录都做了一些比较详细的规定,比如说哪些文件夹要放置哪些文件。 进到了 ubuntu 的根目录下,各个文件的规定如下:

2.7 Linux文件系统

操作系统中负责管理和存储文件系统的软件称为文件系统。

Linux 系统必须要挂载一个文件系统,如果系统不能从指定的设备挂载,系统就会出错。

linux 常见文件系统的类型有 ext3 , ext4 , proc 文件系统 , sysfs 文件系统。

  1. ext3 文件系统是从 ext2 发展过来的,它完全兼容 ext2 文件系统,并且比 ext2 要小,要 可靠。
  2. ext4 文件系统是在 ext3 的基础上改进的,并且 ext4 文件系统在性能和可靠性上都要比 3 的表现更好,而且功能也非常的丰富,并且 ext4 完全兼容 ext3 ,ext3 只支持 32000 个子目录,但是 ext4 支持无限数量的子目录,所以比 3 更优秀。
  3. Proc 文件系统是 linux 系统中特殊的文件系统,实际上它是只存在内存中的,他是一个伪文件系统。这个文件系统是内核和内核模块用来向进程发送消息的机制。

2.7.1 ubuntu 的文件系统

ubuntu 的文件系统类型可以用 df 命令来查看。df 命令可以显示磁盘分区上的可以使用的磁盘空间 使用 df -T 可以显示文件系统的类型,用 man 手册来查看下。

输入**“df -Th”**命令,以人们更容易读的方式显示:

2.8 Linux第一个程序HelloWorld

有过单片机或者 ARM 嵌入式开发经验的小伙伴,都知道我们写完一个程序之后,我们要对程序进行编译,那么在单片机上有 keil 、IAR 这样的集成环境供我们选择,但是我们一旦进入了 linux 的世界,这些常见的就都不见踪影了,一切都要从新开始。在 linux 上也就是 ubuntu 上我们编译程序使用的是 gcc

2.8.1 gcc 基本使用

gcc 全称(gnu compiler collection)即编译套件,gcc 可以支持多种计算机体系结构,比如 X86、 ARM 、 MIPI .我们使用的 ubuntu 默认自带的 gcc

gcc -v  //查看 gcc 的版本
复制代码

创建hello.c文件,添加如下内容

vi hello.c
复制代码
#include <stdio.h>
int main(void)
{
	printf(“hello world!\”);
	return 0;
}
复制代码

然后我们编译 hello.c,命令格式:

gcc 选项 文件
//-o 参数为指定生成文件的文件名 eg: gcc hello.c -o hello
//如果我们不使用 -o 参数指定我们生成文件的名称,直接输入 gcc hello.c 编译完会得到一个 a.out 文件,执行这个 a.out 的结构和执行 hello 是一样的

//-c 参数告诉gcc对源文件进行编译会汇编,但不进行链接。此时,将生成目标文件,如果没有指定输出文件,就生成同名的.o文件。
//当-c后跟多个源文件,会为每个源文件生成一个.o文件,但此时是不能使用-o的。
复制代码

2.8.2 file 命令

查看文件类型。格式:

file 文件名  // eg:file hello
复制代码

使用 gcc 编译器编译出来的可执行文件是 X86 的,不能在 arm 开发板上运行。

2.8.3 编译流程

从 hello.c 编译得到 hello 或者 a.out 要经历四个步骤预处理,编译,汇编,链接

hello.i 预处理得到的 C 语言代码
hello.s 汇编语言文件
hello.o 目标文件
复制代码
  1. 预处理阶段,编译器会对头文件或者宏定义进行展开,或者条件编译的选择。我们可以使用 -E 参数得到预处理文件。
gcc -E hello.c -o hello.i  //使用 gcc -E hello.c -o hello.i 得到预处理后的文件
复制代码
  1. 编译,把文件编译成汇编代码。-S 参数 将 hello.i 文件编译成 hello.s 文件
gcc -S hello.i -o hello.s
复制代码
  1. 汇编,把汇编文件编译机器码。-c 参数 可以把 hello.s 文件编译成 hello.o 文件
gcc -c hello.s -o hello.o
复制代码
  1. 链接。直接把目标文件编译成可执行文件。链接分为静态链接动态链接,gcc 默认的是动态链接,生成的程序小,但是需要依赖库。静态链接:使用 -static 参数就是静态链接,因为程序里面包含了需要的库,所以体积比较大。
gcc hello.o -o hello  //动态链接
gcc hello.o -o hello -static  //静态链接
复制代码

2.9 Linux 环境变量

2.9.1 环境变量

环境变量是系统预设值的参数。Linux 是一个多用户的操作系统,所以每一个用户也都有自己的环境变量。举例:比如我们之前学习的命令不管在哪个路径下输入,都是可以执行成功的,因为系统已经把命令的搜索路径提前设置好了。

常用变量 PATH 决定了要去哪个路径下去寻找我们的程序或者命令,在以后的开发过程中,我们要经常修改这个变量。

2.9.2 echo 命令

功能:在标准输出上显示一段文字

echo $PATH //$表示引用
复制代码

2.9.3 修改 ubunu 的环境变量

两种常用方法:(举例:把 /home/topeet/test 路径加到 PATH 变量)

  1. 直接使用命令设置
export 变量=新增的变量值:$变量
export PATH=home/topeet/test/:$PATH
复制代码

使用这个方法环境变量是立刻生效的,但是只是临时改变,我们重新打开再关闭终端就没有了,而且只对当前用户生效

  1. 修改 .bashrc 文件,直接在这个配置文件里边加上我们的环境变量。在配置文件的最底行加入增加的环境变量。
export 变量=新增的变量值:$变量
export PATH=home/topeet/test/:$PATH
复制代码

设置完不是立刻生效的,要使用命令 source .bashrc 更新一下,或者重新打开关闭终端也可以生效。修改这个文件是永久的,但是也是仅对当前用户有效

source .bashrc
复制代码

2.10 Linux 编写第一个自己的命令

2.10.1 命令的概念

命令就是可执行程序。比如说我们输入 ls -alls 就是可执行程序的的名字-al 就是要传递进去的参数

2.10.2 ps 命令

显示进程的动态。
复制代码

当 shell 接收到我们的命令以后,会根据我们输入的字符到环境变量和默认路径中去找,环境变量上一 章提过,可以通过打印查看都有哪些环境变量,然后它会去寻找有没有名字和我们输入命令一样的程序。

2.10.3 定义一个自己的命令

编译前面编写的 hello.c 文件

gcc hello.c -o hello
./hello  //运行hello文件
复制代码

我们现在可以执行hello这个可执行文件 , 但是现在我们现在的这个可执行程序只能在 /home/dlxy/桌面 这个路径下运行,而且我们还要加上当前目录,如果我切换到上一级目录,就不能用 **“ ./hello ”**来运行hello ,因为上一级目录下没有 hello 这个文件,我们直接输入命令 “hello ”也不行,会提示错误。

  1. 我们上一章学了环境变量,环境变量里边 PATH 变量决定了我们的程序或者是命令都要去哪些路径下找,那我们可以把存放可执行程序的路径加到环境变量里面,那么在任意路径下输入 hello 这个命令, 它就会自动找到 hello 这个可执行文件来帮助我们执行。

  1. 我们前面学到的根目录下的 bin 文件是专门存放可执行文件的,我们直接把生成的这个 hello 可执行性文件拷贝到根目录下 bin 文件夹也是可以的。

本章是把我们之前学到的进行一个串通。比如说环境变量的修改gcc 的编译。同时我们也知道了平常使用的命令就是一个可执行程序,而且在键盘上输入了我们的命令之后,这个命令发给了 shell 。也就是 如下图的这个 bash,是发送给它的,然后它会根据我们输入的这个字符串去环境变量里面去找,去看看有没有和我们的名字一样的程序。

2.11 Linux 工具之 make 工具和 makefile 文 件

前面我们在编写 linux 上第一个简单程序 hello.c 的时候是直接使用gcc命令的。但是如果我们以后工作的时候要编译一个工程,这个工程里面有很多的源文件,这时 候我们全部使用这个命令来编译那就非常的麻烦了,而且如果我们修改了一个源文件,那么我们使用命令来编译就要再次执行一遍这个过程,就会非常的耗时间。

如果有小伙伴以前学习过单片机,大家可以类比下单片机开发软件 keil 里面的单独编译全部编译。单独编译是很省时间的,全部编译就会非常的耗时间,我们使用命令来编译就相当于我们单片机软件中的 全部编译

为了解决编译一个工程非常繁琐这个问题,前人就给我们发明了编译辅助工具 make 工具,它的编译思路是非常简单的,它会在编译之前先比较哪个文件的时间发生了改变,如果说这个文件它修改的时间要晚于编译生成的文件,那么它就会按照要求重新构建这些文件,而不是说再浪费时间重新构建其他的文件了。

假如在单片机上用 keil 写了一个 c 文件,这个工程里边别的文件没有改,那么我们就不用点全部编译,只要编译一下我们修改过的文件就可以了。make 也是这样的,只不过它比较聪明,它不用再人为的去判断了,在编译之前会自动帮我们判断

2.11.1 使用 make 工具

make 工具是编译辅助工具,用来解决使用命令编译工程非常繁琐的问题。

调用这个命令工具:我们在 windows 上编程使用 ide ,我们有图形界面,有相应的按钮,比如说 build 或者 run 来编译。其实 make 这个编译辅助工具使用也是非常简单的,我们在控制台上直接输入 make 命令, 它就会自动调用 make 工具。

直接在这个目录下输入 make ,然后报错了,因为我没有告诉 make 这个工具它按照什么规则来编译我们的程序。如下图所示:

2.11.2 makefile

Makefile 就是描述了整个工程编译连接等规则的文件。我们在终端输入完 make 命令之后,调用 make 工具,make 就会在当前目录按照文件名就会找 makefile 文件,Makefile 的命名必须是 makefile 或 Makefile ,m 大写小写都是可以的。

刚才输入命令报错的原因是因为在当前目录下是没有 makefile 这个文件的。新建一个Makefile 文件,然后在当前目录下输入 make 命令,我输入完 make 命令,它就会调用 make 工具,make 工具就会在当前目录下找到 makefile 这个文件,这里又报错了,因为这里创建的 makefile 文件,他虽然找到了但是里面是空的,因为没有包含任何的规则

先写一个简单的来试一下,打开 makefile 文件,敲的时候一定要按 Tab 首行缩进不能用 空格,然后我们输入内容,保存退出,如下图所示:

make之后运行hello:

2.12 makefile 基本语法

2.12.1 设置 vim 首行缩进

sudo vi /etc/vim/vimrc // rc 结尾的一般为配置文件
复制代码

在最后一行输入 “set tabstop=4”,保存后退出即可。便发现 vim 打开后的缩进变成四个空格了。

2.12.2 Makefile 基本语法

语法格式:

目标:依赖

(tab)命令

all:
	gcc hello.c -o hello
//目标: all
//依赖:空
//命令: gcc hello.c -o hello
复制代码

上面的例子也可写成:

all:hello.o
	gcc hello.o -o hello
hello.o:hello.c
	gcc -c hello.c -o hello.o  //使用-c参数告诉gcc对源文件进行编译会汇编,但不进行链接。
					//此时,将生成目标文件,如果没有指定输出文件,就生成同名的.o文件
//目标:all 和 hello.c
//依赖:hello.o 和 hello.c
//命令: gcc hello.c -o hello 和 gcc -c hello.c -o hello.o
复制代码

因为 all 依赖 hello.o 文件,所以要先执行 gcc -c hello.c 得到 hello.o 文件,然后才可以执行 gcc hello.c -o hello 。所以输入 make 命令后执行顺序如下图所示:

在编译的时候,我们可以使用 make 目标来编译,如果我们不指定目标的话,默认执行的是第一个目标所对应的规则。也就是说 make 和 make all 是一样

当要重新编译时,需要删除上一次编译生成的文件,使用clean来解决,如下:

all:hello.o
	gcc hello.o -o hello
hello.o:hello.c
	gcc -c hello.c -o hello.o
	
clean:
	rm -rf *.o hello  
复制代码

然后我们输入命令“ make clean ”就可以直接执行 rm -rf *.o hello 命令。

但是,我们在当前目录下不能和 makefile 目标名一样的文件。比如我在当前目录下创建一个名为 clean 的文件,然后执行“ make clean ”命令就会报错。

为了解决这个问题,makefile 引入了一个新的概念,叫做伪目标,我们使用伪目标来声明 clean 就可以避免与当前目录下的同名文件发生冲突。

伪目标格式:
.PHONY:目标
复制代码
all:hello.o
	gcc hello.o -o hello
hello.o:hello.c
	gcc -c hello.c -o hello.o
.PHONY:clean
clean:
	rm -rf *.o hello  
复制代码

然后我们在执行 make clean 命令。尽管当前目录下有 clean 同名文件, make clean 命令也可以执行 成功。如下图所示

2.12.3 Makefile 变量和变量赋

变量可以对许多地方使用,比如目标,依赖。或者命令。

变量的赋值可以使用:“ = ” “ ?= ” “ := ” “ +=

变量的使用:通过$() 来完成变量的引用

  1. 使用 “:= ”来赋值:是立刻赋值,在执行 var1:=aaa 的同时变量值已经被确定了,所以最后打 印为 aaabbb,而不是 cccbbb。
var1:=aaa
var2:=$(var1)bbb
var1:=ccc
all:
	echo $(var2)  //aaabbb
复制代码
  1. 使用“=” 赋值:是延迟赋值,使用它来赋值是 makefile 里面最后被指定的值。因为我们最后给变量 var1 赋值为 ccc ,所以最后打印为 cccbbb ,而不是 aaabbb ,如
var1=aaa
var2=$(var1)bbb
var1=ccc
all:
	echo $(var2)  //cccbbb
复制代码
  1. 使用 “?=”来赋值:如果 var1 变量前面没有被赋值,那么就给它赋值为 ccc ,如果前面已经赋值了, 就适应前面的值,所以,打印为 aaabbb ,而不是 ccc
#这是注释  //makefile 中的注释为 #
var1?=aaa
var2?=$(var1)bbb
var1?=ccc
all:
	echo $(var2)  //aaabbb
复制代码

使用“+=”来赋值:追加赋值,是在我们前面定义的好的字符串里面在添加进去新的字符串,所以运行 会打印 aaa cccbbb 。不过中间会有空格。

var1:=aaa
var2=$(var1)bbb
var1+=ccc
all:
	echo $(var2)  //aaa cccbbb
复制代码

2.12.4 自动化变量

自动化变量就是不用定义且会随着上下程序的不同而发生变化的变量叫做自动化变量。

这里介绍三个最常用的自动化变量:

先来写几个程序:

  1. main.c
#include <stdio.h>
#include <hello.h>

void main(void)
{
		hello();
}
复制代码
  1. hello.c
#include <stdio.h>
#include <hello.h>

void hello(void)
{
	printf("hello world!\n");
}
复制代码
  1. hello.h
#ifndef _HELLO_
#define _HELLO_

void hello(void);

#endif
复制代码
  1. Makefile
hello:hello.o main.o
	gcc hello.o main.o -o hello
hello.o:hello.c
	gcc -c hello.c -o hello.o
main.o:main.c
	gcc -c main.c -o main.o
clean:
	rm -rf *.o hello
复制代码

使用这个 makefile 虽然也可以成功编译。

但是,一旦编译的文件多了,如果我们还这样来编写 makefile 就会变得非常复杂。所以,自动化变量就派上用场啦。接下来我们一步一步的来简化这个 makefile

  1. 用变量表示依赖文件
var:=hello.o main.o  //用变量表示依赖文件
hello:$(var)
	gcc $(var) -o hello
hello.o:hello.c
	gcc -c hello.c -o hello.o
main.o:main.c
	gcc -c main.c -o main.o
clean:
	rm -rf *.o hello
复制代码
  1. 使用通配符 % ,和自动化变量 <<** 、**@ 代替依赖和目标,简化完如下:
var:=hello.o main.o
hello:$(var)
	gcc $(var) -o hello
%.o:%.c
	gcc -c $< -o $@  //$< 表示第一个依赖文件,如果依赖模式是%,那么它就表示一系列文件。(%为通配符,类似 linux上的 *);$@ 表示所有目标

clean:
	rm -rf *.o hello
复制代码

3.使用自动化变量 “$^”表示所有文件依赖的列表,简化完下:

var:=hello.o main.o
hello:$(var)
	gcc $^ -o hello
%.o:%.c
	gcc -c $< -o $@  //$^ 表示所有依赖

clean:
	rm -rf *.o hello
复制代码

2.12.5 wildcard 函数

功能: 展开指定的目录

格式: $ (wildcard PATTENR)
复制代码

eg:在 test1 目录有一个“a.c”的 c 文件和一个 test1 的文件夹,在test1/test1 文 件夹下有一个 “b.c”的文件

在test1目录下新建Makefile文件:

var=$(wildcard ./*.c ./test1/*.c)
all:
	@echo $(var) #echo 命令前面加了@符号,该条命令执行的时候不显示命令,只显示结果
复制代码

执行make如下:

2.12.6 notdir 函数

功能:去掉路径。只取文件名

格式: $ (notdir $ (var))
复制代码

eg:我们在上面的 makefile 中加上以下代码,因为上面的例子我们得到的结果是 ./a.c 和 ./test/b.c 是有路径的,我们可以直接使用这个变量。

var=$(wildcard ./*.c ./test1/*.c)
var1=$(notdir $(var))
all:
	@echo $(var1)
复制代码

执行make如下:因为 notdir 函数可以去掉路径,所以 /a.c 和 ./test/b.c 去掉路径就得到a.c 和 b.c

2.12.7 dir 函数

功能:取出目录,这里的目录指的是最后一个反斜杠/ 之前的部分,如果没有反斜杠/就返回当前。

格式: $(dir <names...>)
复制代码

eg: 我们在上面的例子中加入以下代码,如下所示:

var=$(wildcard ./*.c ./test1/*.c)
var1=$(notdir $(var))
var2=$(dir $(var))
all:
	@echo $(var2)
复制代码

执行make如下:因为 var2 的值为 ./a.c 和 ./test/b.c ,所以取出目录就是 ./ 和 ./test

2.12.8 patsubst 函数

功能:替换文件后缀

格式: $(patsubst 原文件,目标文件,文件列表)
复制代码

eg:我们在上面的例子中加入以下代码,如下所示:

var=$(wildcard ./*.c ./test1/*.c)
var1=$(notdir $(var))
var2=$(dir $(var))
var3=$(patsubst %.c,%.s,$(var1))
all:
    @echo $(var3)
复制代码

这个函数会把 var1 变量的 a.c 和 b.c 的 .c 后缀替换为 .s ,如下

但是这个替换并不会改变当前目录下的后缀名。这个函数能做什么呢?我们可以用这个函数来替换我们的后缀名,进行其他的操作,这个函数都是会配合其他函数来用的。

替换我们可以使用这个,也可以使用 $(var:a=b) 这个格式来替换,var 代表我们要替换的文件的 名字,a 是原文件,b 是目标文件。我们来改一下上面的代码,如下所示:

var=$(wildcard ./*.c ./test1/*.c)
var1=$(notdir $(var))
var2=$(dir $(var))
var3=$(patsubst %.c,%.s,$(var1))
var4=$(var1:%.c=%.o)
all:
    @echo $(var4)
复制代码

2.12.9 foreach 函数

功能:把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串

格式:$(foreach <var>,<list>,<text>)
eg:
var=$(wildcard ./*.c ./test1/*.c)
var1=$(notdir $(var))
var2=$(dir $(var))
var3=$(patsubst %.c,%.s,$(var1))
var4=$(var1:%.c=%.o)
var5=$(foreach n,$(var2),$(wildcard $(n)*.c))
all:
    @echo $(var5)
复制代码

因为 var2 变量的值为 ././test1 ,所以先把 ./ 取出来放在 n 变量,然后再执行 wildcard 函数取 出 ./test1./test1/ 下面的 c 文件的路径。所以执行结果如下图所示:

2.13 安装samba软件

sudo apt-get install  //安装
sudo vi /etc/samba/smb.conf  //修改配置文件
复制代码

添加如下内容:这些信息都是 samba 的说明和设置,把这些复制上,格式要设置对,使用 Tab 键缩进,然后把注释删除,不然可能会出错。

[ubuntu_samba]
	comment = arm ubuntu samba dir #说明
	path = /home/samba #共享的 samba #目录
	available = yes #允许访问
	browseable = yes #可以浏览
	public = yes #公开
	writable = yes #可写
	create mask = 0755 #当外部创建新文件时的权限
	security = share #共享模式
	force user = root #在外部添加新文件时,文件的所有者
	arm force group =root #在外部添加新文件时,文件的所在组
复制代码
sudo service smbd restart  //重启
ifconfig  //查看虚拟机ip  192.168.0.103

在windows中输入  \\192.168.0.103
添加网络驱动映射

设置samba自启动:
编辑配置文件:
sudo vim /etc/rc.local
添加命令:
/etc/init.d/smbd start
exit 0
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享