Linux入门
Linux环境搭建
虚拟机配置
ifconfig指令
ifconfig 是一个经典的 网络接口配置工具,主要用于查看和管理 Linux 系统中的网络接口(如网卡)。
核心作用
- 查看网络信息
- 显示所有已启用网卡的 IP 地址、子网掩码、MAC 地址、MTU(最大传输单元)等。
- 显示网卡的收发数据包统计(RX/TX packets、errors、drops 等),帮助排查网络问题。
- 配置网络接口(需要 root 权限)
- 启用 / 禁用网卡:
ifconfig ens160 up/ifconfig ens160 down - 临时设置 IP 地址:
ifconfig ens160 192.168.1.100 netmask 255.255.255.0
- 启用 / 禁用网卡:
在现代 Linux 发行版(如 CentOS 8、Ubuntu 20.04+)中,ifconfig 属于 net-tools 包,默认可能未安装,推荐使用功能更强大的 ip 命令:
ip addr:查看 IP 地址(等价于ifconfig)ip link:查看链路状态ip route:查看路由表
设置管理员权限
在普通用户中,设置管理员权限,需要更改sudoers文件
- 切换到管理员用户下: su root
- 更改sudoers文件的权限,加上写权限:chmod u+w /etc/sudoers
- 修改该文件中的内容:vi /etc/sudoers
使用上下键找到以 root ALL= ... 开头的一行内容
将光标放在该行,按 yy 键 (复制),然后按 p 键(粘贴)
在复制出来的那行中,按 a 键进入编辑模式,将该行中的root改成自己的用户名 zpp
按Esc键 后 —-> shift + : 后输入wq保存并退出即可
将sudoers文件的写权限去除:chmod u-w /etc/sudoers
回到普通用户权限:指令exit 或者 ctrl + D快捷键
切换Linux镜像源
默认官方的centos 8镜像源已经不可用了,需要切换到国内的镜像源(阿里云)
切换步骤:
- 备份原有的仓库配置:
1 | sudo mkdir /etc/yum.repos.d/backup #创建一个用于存放备份的文件夹 |
- 下载阿里云的镜像文件
1 | sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo |
- 清理缓存并重建元数据
1 | sudo dnf clean all #清除缓存 |
网络问题
如何判断自己的虚拟机是否有外网,如果出现下面的情况说明有网
一直没有ip地址
虚拟机没有网
设置后有ip地址,但是关机重启后就没有了
解决方法:
- 看看虚拟机是否没有连接网络
- 上述连接后还没有网络,查看网络配置器,切换网络模式
- 如果上述操作还不行,需要配置网卡配置
1 | cat /etc/sysconfig/network-scripts/ifcfg-ens33 |
按照更改sudoers文件的内容形式改成将上面相关文件信息更改后,保存退出 —>重启虚拟机即可
- 检查IP地址是否存在
不存在的解决方案:
看一下虚拟机的网络编辑器:
看一下虚拟机的服务是否开启:如果没有开启,需要开启一下
看一下网络适配器:
- 如果上面的操作依然没有解决你的问题:重置一下虚拟机的网络
- 查看windows是否为家庭版,如果为家庭版,建议升级成专业版
查看设备管理器中的网络连接
总结:
虚拟机无法获取IP地址:网络管理冲突(一般发生在CentOS7中)、网络模式(NAT)、VM服务不正常
主机和虚拟机网络不互通:网络适配器不正常
虚拟机无法连接外网:配置了静态IP不正确,检查三个IP段是否一致
用户相关
Linux是支持多用户开发的,可以有一个管理员用户和多个普通用户
- 管理员用户:执行重要操作时无需输入密码
- 普通用户:正常开发合作的用户
切换账户
1 | su 账户名 |
如果是进入管理员帐号想退出可以用exit指令或su出去
建议exit回到「原发起用户」,不会占用内存,生命周期结束,若用su则是另建新角色,root还在
ls指令
1 | ls -l #详细信息 |
第二列是权限列:r-w-x对应读-写-可执行
权限列后一列是硬链接数,即 这个文件真实内容被多少个名字 “指向”。
之后是用户名+用户所在组名
Xshell
Xshell是一款Windows平台上的SSH(secure Shell)客户端软件,能够完成远程连接和管理linux服务,支持SSH1和SSH2协议,提供了安全的加密连接,能够防止数据被窃取和篡改。
下载地址:家庭/学校免费 – NetSarang Website
创建会话连接,主机ip可以在服务器内通过ifconfig指令得到
vim编辑器使用
vim是linux系统下的文本编辑器,可以对不同文本进行编辑,功能是对文件内容的编辑、保存、更改等操作
vim有三种模式:命令行模式、插入模式、底行模式
如何打开vim编辑器
- 先
touch一个文件,然后使用指令:vi/vim+ 文件名即可,这种方式打开文件,无论是否编辑文件,都会在文件系统中产生一个普通文件 - 直接使用
vi/vim+ 不存在的文件名,如果对文本内容进行更改,则保存退出后,会在文件系统上产生一个普通文件,如果没有更改数据,保存后退出,则不会在文件系统上创建该文件
命令行模式
1)使用vi + 文件名,刚进入编辑器的模式就是命令行模式
2)命令行模式的作用:主要完成对文本内容整体的复制、粘贴、剪切、删除、光标移动等操作
3)如何进入命令行模式:
刚进入编辑器的模式就是命令行模式
其他模式进入命令行模式只需要按:ESC键即可
4)命令行模式主要操作
yy: 复制当前行的文本内容nyy:复制从广播所在行及以后的n行文本内容p:将剪切板中的内容进行粘贴dd:删除光标所在的一行文本内容(剪切)ndd:删除光标所在行及以后的n行数据(剪切)u:撤销上一步操作ctrl+r:反撤销gg:将光标直接跳到首行位置nG:表示跳到第n行0:表示光标移动到当前行的行首位置$:表示光标移动到当前行的行尾位置
插入模式
1)功能:用于文件内容的编辑
2)如何进入插入模式,只能从命令行模式进入插入模式,不能直接从底行模式进入插入模式
键盘上特殊的键能从命令行模式进入插入模式
INSERT键:从光标所在的字符前进入插入模式i键:从光标所在的字符前进入插入模式I键:从光标所在的行行首进入插入模式a键:从光标所在的字符后面进入插入模式A键:从光标所在行的行尾进入插入模式o键:从光标所在行的下一行进入插入模式O键:从光标所在行的上一行进入插入模式s键:删除光标所在的字符后,从光标位置进入插入模式S键:删除光标所在的一行文本后,从当前行进入插入模式
底行模式
1)功能:完成对文本内容的保存、退出操作或者替换、查找工作
2)如何进入底行模式:从命令行模式中键入 shift + 冒号,就是输入一个冒号
3)主要操作
:w保存文本内容:q退出编辑器:q!强制退出:wq保存后退出:x保存退出:set number在编辑器左侧显示行号:set nonumber不显示行号:/string查找字符串string,并将光标定位在包含该字符串的行首:%s/string1/string2/g表示将所有的string1更换成string2:m,ns/string1/string2/g表示[m,n]行闭区间内的所有string1更换成string2
总结:
C++环境搭建
- 安装g++编译环境、gcc编译环境
1 | sudo yum install gcc //安装gcc编译器,用于编译c语言程序 |
- 安装gdb调试工具
1 | sudo yum install gdb //安装gdb调试工具 |
- CMake工具
1 | sudo yum install cmake //安装CMake脚本工具 |
可能出现的报错:
cmake: symbol lookup error: cmake:undefined symbol:archive write add filter zstd
核心原因:安装的 CMake 版本和系统里的 libarchive 库版本不兼容。
问题根源:
- 你用
yum install cmake安装的是 CentOS 8 官方源里的 CMake 3.20.2。 - 这个版本的 CMake 依赖
libarchive库中的archive_write_add_filter_zstd函数(用于 Zstd 压缩)。 - 但 CentOS 8 自带的
libarchive版本太旧,不包含这个函数,所以 CMake 启动时就会报 “未定义符号” 的错误。
解决方法:
1 | yum install cmake libarchive #更新libarchive库 |
Linux下C++程序
C++程序框架的介绍
1 |
|
编译步骤
- way1:
1 | #一步到位的编译,***是文件名称 |
- way2:
1 | #分步编译:(重要) ESc ---> iso |
执行可执行程序
语法格式:
1 | ./program_name |
sys库使用
man手册使用方法
man = manual(手册)
linux系统自带、最权威的命令帮助文档几乎所有命令、函数、配置文件都有 man 页,可以在该手册也中查看函数、指令的功能,也是相关操作的使用说明书,一共有七章内容,主要使用前三章,第一章是shell指令相关说明,第二章是系统调用函数相关说明(重点),第三章是库函数(重要)
使用方法
- 只需要键入 man + 相关函数/指令即可
1 | #例如 |
- 退出手册:键入 q
操作快捷键
- 上下箭头:滚动
/关键词:搜索n:下一个搜索结果q:退出
里面一般有什么
- NAME:命令简介
- SYNOPSIS:怎么用(语法格式)
- DESCRIPTION:详细说明
- OPTIONS:所有参数解释
- EXAMPLES:例子
如果想要查看C语言库函数相关功能,可能需要安装相关库
1 | sudo yum install man-pages man-pages-devel |
c/c++库函数printf查询案例
常用的内核提供的函数库 sys
1、文件的操作:open()、read()、write()、close()、lseek()等等
2、进程控制函数:fork()、exit()、wait()、execl()等等
3、信号操作:kill()、signal()等等
4、网络通信:socket()、bind()、listen()等等
案例:
1 |
|
使用GDB调试程序
在linux系统下的警告和错误,当程序出现bug时,linux终端会给大家两种不同的信息
- 警告(warning):有时的警告是不影响可执行程序的产生
- 错误(error): 错误如果不改正,是不能生产可执行程序的
总结:相比于gcc编译器,g++编译器要求更加严格
警告可以被忽略,继续产生可执行程序,但是错误必须更改后才能产生可执行程序
什么是GDB?
GDB, GNU项目调试器,允许您查看一个程序执行时“内部”发生了什么,或者一个程序崩溃时正在做什么。
官网:https://www.sourceware.org/gdb/
主要功能
- 启动程序,指定可能影响其行为的任何内容。
- 使程序在指定条件下停止。
- 检查程序停止时发生了什么。
- 更改程序中的内容,这样您就可以尝试纠正一个错误的影响,并继续了解另一个错误。
gdb可以调试指定的当前程序,向程序中传递参数
gdb还可以调试出错的文件,查看错误原因
gdb还可以调试正在运行的进程
gdb使用
- 准备c++程序
1 |
|
- 编译程序,编译选项中需要加上 -g
1 | g++ -g ***.cpp -o *** |
- 启动gdb调试
1 | gdb ./*** |
gdb常用指令
quit/q:表示退出gdb调试
run/r:表示执行可执行程序,如果没有设置断点,则将整个程序从头到尾执行一遍
list/l:展示可执行程序的相关行信息,默认展示10行
list m,n:表示展示从m行到n行的信息list func:表示展示func函数旁边的相关程序
break/b:表示设置断点,当调试器将程序运行到断点所在位置后,会暂停于此
break行号:表示在某行设置断点break func:表示在指定的函数处设置断点info break:查看所有断点的信息delete breakpoint断点编号:表示删除指定的断点
next/n:表示执行下一条语句
continue/c:表示从断点处继续向后执行,直到遇到下一个断点或者程序结束
step/s:能够跳入到指定函数中,查看相关函数内部代码
print/p 变量名/地址 :表示打印指定变量或地址信息
set variable 变量名=值:表示给某个变量设置相关的值
gdb使用技巧
shell:后面可以跟终端指令,表示执行终端相关操作
set logging on:设置开启日志功能,会在当前目录中生成一个gdb.txt文件记录接下来的调试内容
watchpoint :观察点,如果设置的观察点的值发生改变,则会将该值的旧值和新值全部展示出来
gdb调试出错的文件
当一个可执行程序出现错误时,会产生一个core文件,用于查看相关错误信息
linux系统默认是不产生core文件,需要进行相关设置后才能产生
通过ulimit -a 查看所有linux的限制内容
通过 ulimit -c unlimited来设置core文件的个数
查看错误原因
gdb调试其他正在运行的进程
./可执行程序 &:表示将可执行程序后台运行,不占用当前终端
gdb -p 进程号:调试指定的运行的进程
pidof a.out:查看进程
kill -p 进程号:杀死进程
1 | [zpp@localhost day2]$ g++ -g 05test.cpp //编译程序 |
库的制作(静态库与动态库)
为什么引入库
在上述案例中,主程序要是有的源程序代码,在add.cpp中,如果项目结束后,到了交付阶段,由于主程序的生成需要其他程序联合编译,那么就要将源程序打包一起发给老板,这样该程序的开发者自身的价值就不大了,该项目的知识产权就很容易被窃取。为了保护我们的知识产权,我们引入了库的概念
什么是库
库在linux中是一个二进制文件,它是由 .cpp文件(不包含main函数)编译而来,其他程序如果想要使用该源文件中的函数时,只需在编译生成可执行程序时,链接上该源文件生成的库文件即可。库中存储的是二进制文件,不容易被窃取知识产权,做到了保护作用。
库在linux系统中分为两类,分别是静态库和动态库
windows:
***.lib:静态库
***.dll: 动态库
linux:
- ***.a:静态库
- ***.so: 动态库
静态库及其制作
概念:将一个***.cpp的文件编译生成一个 lib***.a的二进制文件,当你需要使用该源文件中的函数时,只需要链接该库即可,后期可以直接调用
静态体现在:在使用g++编译程序时,会将你的文件和库最终生成一个可执行程序(把静态库也放入到可执行程序中),每个可执行程序单独拥有一个静态库,体积较大,但是,执行效率较高
案例:
- 准备程序
1 | //add.h |
- 编译静态库
1 | gcc -c ***.cpp -o ***.o //只编译不链接生成二进制文件 |
- 使用静态库
1 | gcc main.cpp -L 库的路径 -l库名 -I 头文件所在路径 |
指令拆解
| 部分 | 含义 |
|---|---|
g++ |
C++ 编译器(处理 .cpp 文件,链接 C++ 标准库) |
main.cpp |
要编译的主源文件(程序入口 main 函数在这里) |
-L . |
指定库搜索路径:-L = Library path,. 表示「当前目录」告诉编译器:去当前目录找静态库(.a)/ 动态库(.so) |
-ladd |
指定要链接的库:-l = link,add 对应 libadd.a(静态库)规则:-lxxx → 找 libxxx.a/libxxx.so |
-I . |
指定头文件搜索路径:-I = Include path,. 表示「当前目录」告诉编译器:去当前目录找 #include "add.h" 这类头文件 |
文件归类后可以如下操作
动态库及其制作
概念:将一个***.cpp的文件编译生成一个 lib***.so的二进制文件,当你需要使用该源文件中的函数时,只需要链接该库即可,后期可以直接调用
**动态体现在:**在使用g++编译程序时,会将你的文件和库中的相关函数的索引表一起生成一个可执行程序,每个可执行程序只拥有函数的索引表,当程序执行到对应函数时,会根据索引表,动态寻找相关库所在位置进行调用,体积较小,执行效率较低,但是可以多个程序共享同一个动态库,所以,动态库也叫共享库
案例:
- 准备程序
1 | //add.h |
- 编译生成动态库
1 | g++ -fPIC -c ***.cpp -o ***.o //编译生成二进制文件 |
- 使用动态库
1 | gcc main.cpp -L 库的路径 -l库名 -I 头文件的名字 |
报错解决方案
方法1:更改路径宏
1
export LD_LIBRARY_PATH=库的路径
当你执行 export LD_LIBRARY_PATH=. 时,它会将当前目录 . 设置为这个环境变量的唯一值。
系统查找库的顺序变为:
- 先在当前目录
.查找。 - 如果找不到,再去系统默认的库路径(如
/lib,/usr/lib,/usr/lib64等)中查找。
两个重要的局限性:
- 临时生效:这个环境变量只在当前终端会话中有效。如果你关闭终端或重新登录,设置就会失效,再次运行程序时又会报错。
- 优先级问题:如果当前目录下有一个与系统库同名的文件(例如
libc.so),程序会优先加载当前目录下的这个文件,这可能导致程序行为异常甚至崩溃。不过,这种情况在日常开发中很少见。
方法2:将自己的动态库放入到系统的库函数目录中 (/lib64 /usr/lib64)
1 | sudo mv libadd.so /lib64 |
- 动态库和静态库编译生成可执行程序的文件大小比较
第三方库使用
1、C/C++语言默认是支持标准输入输出库的,但是其他的相关函数库需要第三方引入,并且,编译程序时,需要链接上对应的库
2、使用数学库:#include<math.h>
3、线程支持类库:#include<pthread.h>
如果不能支持线程库:sudo yum install manpages-posix manpages-posix-dev
1 |
|
Makefile文件
什么是Makefile
用于工程项目管理的一个文本文件,文件名为Makefile的文本文件
Makefile可以大写,也可以小写,一般Makefile首字母使用大写
如果Makefile和makefile两个文件都存在,系统会默认使用小写的
什么是make
make是一个执行Makefile的工具,是一个解释器
用来对Makefile中的命令进行解析并执行一个shell指令
make这个指令在 /usr/bin 中,默认linux系统中都已经安装
如果没有安装 make,安装指令如下
1 | sudo yum install make |
查看是否安装成功:make --version
用处
描述了整个工程的编译、链接规则
软件项目的自动化编译,相当于给软件编译写一份脚本文件
学习Makefile必要性
Linux/Uinx环境下开发的必备技能
系统架构师、项目经理的核心技能
研究开源项目、Linux内核原码的必需品
加深对底层软件构造系统及过程的理解
理论基础
1 | 软件的构造过程、程序的编译和链接:预处理 --> 编译 --> 汇编-->链接 |
Makefile工作过程
Makefile本身是面向依赖进行编写的
源文件(.cpp) —> 编译(.s) —-> 目标文件(.o) —> 链接 —>可执行文件
hello.cpp—->hello.o —>hell 分两步进行撰写
本质上一步就可以生成可执行程序,但是,由于在生成可执行程序时,可能会有多个文件进行参与,后期其他文件可能要进行更改,更改后,会影响到可执行程序的执行,其他没有更改的文件也要参与编译,浪费时间
案例
- 编写程序
1 | //hello.cpp |
- 终端编译程序
- 使用Makefile管理工程
编写Makefile文件
1 | # Makefile中的注释是以#开头 |
简化的Makefile文件
1 | # Makefile中的注释是以#开头 |
- 执行Makefile文件
1 | make --->默认找到Makefile中的第一个目标开始进行执行 |
Makefile语法规则
1、规则
构成Makefile的基本单元,构成依赖关系的核心部件
其他内容可以看做为规则的服务
2、变量
类似于C++中的宏, 使用变量:$(变量名) 或者 ${变量名}
作用:使得Makefile更加灵活
3、条件执行
根据某一变量的值来控制make执行或者忽略Makefile的某一部分
4、函数
文本处理函数:字符串的替换、查找、过滤等等
文件名的处理:读取文件/目录名、前后缀等等
5、注释
Makefile中的注释,是以#号开头
规则
1、规则的构成:目标、目标依赖、命令
2、语法格式
1 | 目标:目标依赖 |
3、目标详解
1)默认目标
1 | 一个Makefile里面可以有多个目标,一般会选择第一个当做默认目标 |
2)多目标
一个规则中可以有多个目标,多个目标具有相同的生成命令和依赖文件
1 | clean distclean: |
3)多规则目标
多个规则可以是同一目标
1 | all:test1 |
4)伪目标
1 | #并不是一个真正的文件名,可以看做是一个标签 |
4、目标依赖
1)文件时间戳
1 | 根据时间戳来判断目标依赖是否要进行更新 |
2)模式匹配
1 | % ---->通配符匹配 |
1 | //头文件 |
1 | #第一个依赖关系 |
5、命令
1 | 1)命令的组成 |
变量
1、变量基础
1 | 1)变量定义:变量名 = 变量值1 变量值2 ... |
2、变量的分类
1 | 1)立即展开变量 |
3、变量的外部传递
可以通过命令行给变量进行赋值操作
1 | make ARCH=g++ |
1 | var1 = main.o #定义一个变量并赋值 |
条件执行
1、关键字
1 | ifeq 、else 、endif |
2、使用
1 | ifeq (要判断的量, 判断的值) |
上图案例需要终端输入条件指令如:make COMPILE=g++
总结
1、执行过程
1 | 进入编译目录、执行make命令 |
2、依赖解析阶段
1 | 解析Makefile,建立依赖关系树 |
3、命令执行阶段
1 | 把解析生成的依赖关系树加载到内存 |
4、make执行结果
1 | make的退出码 |
vscode配置
vscode官网:Download Visual Studio Code - Mac, Linux, Windows
mingw官网:mingw-w64
对 .vscode 文件夹的更改,linux系统里也一样
多文件编译
vsc调试工具使用
CMake
CMake是一个跨平台的安装编译工具,可以使用简单的语句来描述所有平台的安装(编译过程)
CMake可以说是已经成为大部分的C++开发项目的标配
可以使用几行或者几十行的代码来完成非常冗长的Makefile代码
为什么要用CMake
在不使用CMake时,编译工程如下
在上面的机制中,工程文件中添加一个源程序 bar.cpp
使用CMake来管理工程的状态
使用CMkake管理工程中添加一个新文件 bar.cpp
语法特性介绍
1> 基本语法:指令(参数1 参数2 ...)
参数使用括号括起来
参数之间使用空格或分号隔开
2> 注意:指令是大小写无关的,但是参数和变量是大小写相关的
1 | set(HELLO hello.cpp) # 定义一个变量名叫HELLO 变量的值为hello.cpp |
3> 变量使用${}进行取值,但是在if控制语句中,是直接使用变量名的
if(HELLO) 是正确的
if(${HELLO}) 是不正确的
4> 语句不以分号结束
CMake重要的指令
1> cmake_minimum_required:指定CMake的最小版本支持,一般作为第一条cmake指令
1 | # CMake设置最小支持版本为 2.8 |
2> project:定义工程的名称,并可以指定工程支持的语言
1 | # 指定工程的名称为HELLOWORLD |
3> set:显式定义变量
1 | # 定义变量 SRC 其值为 sayhello.cpp hello.cpp |
4> add_executable:通过依赖生成可执行程序
1 | # 编译main.cpp 生成main的可执行程序 |
5>include_directories:向工程添加多个特定的头文件搜索路径吗,类似于g++编译指令中的 -I
1 | # 将/usr/lib/mylibfolder 和 ./include添加到工程路径中 |
6> link_directories:向工程中国添加多个特定的库文件搜索路径,类似于g++编译指令的 -L选项
1 | # 将将/usr/lib/mylibfolder 和 ./lib添加到库文件搜索路径中 |
7> add_library:生成库文件(包括动态库和静态库)
1 | # 通过SRC 变量中的文件,生成动态库 |
8> add_compile_options:添加编译参数
1 | # 添加编译参数: -Wall -std=c++11 |
9> target_link_libraries:为target添加需要链接的共享库,类似于g++编译中的 -l 指令
1 | # 将hello 动态库文件链接到可执行程序main中 |
CMake常用变量
1> CMAKE_C_FLAGS:gcc编译选项的值
2> CMAKE_CXX_FLAGS:g++编译选项的值
1 | # 在CMAKE_CXX_FLAGS编译选项后追加 -std=c++11 |
3> CMAKE_BUILD_TYPE:编译类型(Debug 、Release)
1 | # 设定编译类型为Debug,调试时需要选择该模式 |
CMake编译工程
CMake目录结构:项目主目录中会放一个CMakeLists.txt的文本文档,后期使用cmake指令时,依赖的就是该文档
两种情况:
1> 包含源文件的子文件夹中包含CMakeLists.txt文件时,主目录的CMakeLists.txt要通过add_subdirector添加子目录
2> 包含源文件的子文件夹中不包含CMakeLists.txt文件时,,子目录编译规则,体现在主目录中的CMakeLists.txt
内部构建
内部构建:不推荐使用
内部构建会在主目录下,产生一大堆中间文件,这些中间文件并不是我们最终所需要的,和工程源文件放在一起时,会显得比较杂乱无章
1 | ## 内部构建 |
外部构建
将编译输出的文件与源文件放到不同的目录下,进行编译,此时,编译生成的中间文件,不会跟工程源文件进行混淆
1 | ## 外部构建步骤 |
CMake代码实战
同目录下文件编译
1 |
|
CMakeLists.txt文件
1 | # 设置最小版本支持 |
内部编译
外部编译
分文件编译
相关代码文件准备
1 | // include/swap.h |
分文件编译使用g++编译器生成可执行程序
创建工程管理文件 CMakeLists.txt
1 | # 指定最小编译版本 |



