为了可以在 Linux 下能够进行 C/C++ 程序的开发,需要学习一些工具(工具其实也是指令)
手机上的应用商店的软件,其实是在远端的服务器上,并不在本地的手机上,应用商店是通过网络在远端的服务器上下载的,我们可以把东西传到服务器上,也可以从服务器拿下来
例如:我们买的云服务器不是在本地的,而是在远端,我们是通过远程登录工具 xshell 来登录的
yum 类似于手机上的应用商店,帮助我们从远端的服务器上下载安装需要的软件包
手机上为什么有人会给我们提供各式各样的软件?,因为这些公司想赚我们的注意力,从而通过广告等各种方式来盈利
那为什么会有人花钱提供并维护远端的服务器,并且还会有人无偿提供 Linux 下的软件呢?
与手机和 Windows 不一样的是,Linux 下都没有图形化界面,也就不能通过广告来盈利,而开源的软件一般都会成立自己的社区,这些开源组织成立的社区,是乐于捐赠的,那为什么会有人捐赠呢?因为软件开源了,所以软件稳定性,安全性等都很好,并且用这些软件的成本低,也就使得用这个软件的企业越来越多,那这些企业就不希望这个软件不维护了,所以这些企业就一定会给这些社区捐钱,捐设备等
其实也就是因为企业再用,企业会给开源社区捐钱,因此我们便可以跟着免费用这个开源软件
开源的生态:开源方便传播
yum 的使用一般都建议使用 root 账户,因为安装或卸载软件时,需要更改系统目录中的内容,防止没有权限
-y 选项表示不要询问
一般使用的软件不会是特别新的,因为新的软件虽然解决了一些曾经的问题,但肯定会带来一些新的问题,这些新的问题还没有完全暴露出来,但是旧的软件的大部分问题以及暴露出来了
因此软件会被分成 官方软件 和 扩展软件,新的软件刚诞生时,是不能进入官方软件的(软件可能比较强大,但是也存在许多问题),而是被放到扩展软件中,当人们用了两三年之后,发现这个软件写的很好,才会纳入官方软件中
远端的服务器有成百上千,应用商店是怎么知道要到哪里下载?
由于软件被分为官方软件和扩展软件,同样 yum 下载的软件也是分为官方软件和扩展软件的
如果没有扩展 yum 源:sudo yum -y install epel-release ,根据官方 yum 源,找到和他匹配的扩展 yum 源
wget url
功能:远程从 url 获取资源
yum [options] [command] [package …]
options:可选
command:要进行的操作
package:安装的包名
vim 可以满足我们在 Linux 下的常规开发,还可以处理在 Linux 出现的紧急情况, 当我们将一个写好的程序在 Linux 环境下运行起来时,发现存在问题,这时就可以使用 vim 在 Linux 的环境下对文件进行修改
vi 是 vim 的前身,vim 是 vi 的升级版本,兼容 vi 的所有指令,而且还有一些新的特性,vim 是一种多模式的编辑器,其中最常用的 5 种模式:命令模式、底行模式、插入模式、替换模式、视图模式
vim 回车:确认是否安装了 vim,没有安装则使用 sudo yum -y install vim
vim 文件:打开文件,如果文件不存在 vim 会自动创建,打开文件后就不要用鼠标操作了
vim 打开文件后默认在命令模式,只能由命令模式进入其他模式,Esc 键即可从其他模式回到命令模式
k 上
h l 左 右
j 下
命令模式下的指令基本上都可以在前面加上数字,代表重复多少次的意思
命令模式下的指令:
shift + ; [:] 进入底行模式,在底行模式中,执行一条指令后,会回到命令模式
底行模式下的指令:
Esc 回到命令模式
默认是在光标之前开始输入的
从命令模式进入插入模式:
Esc 回到命令模式时,光标会往前一格,因为输入是在光标之前开始输入的,如果在一行输入到末尾时,结束时,光标字符可能不存在
vim 在启动的时候,会自动在当前用户的目录下寻找 vim 的配置文件(.vimrc),如果没有配置文件,则 vim 就是默认的配置
Linux 中软件和程序只安装一份,这样所有用户都可以使用,对于 vim 的配置文件,每个用户可以自己配置,不影响其他用户,不想要配置文件时,直接删除即可
自己配置(太麻烦了):需要在家目录下创建一个 .vimrc 配置文件,然后在网上查找 vim 配置选项,在配置文件中输入对应的选项或字段即可,如果选项不想要了,在选项前加上一个“(代表注释)
在 vim 配置文件中的内容是及时生效的,重新打开 vim 就可以看到效果
自动化配置:gitee 上搜索 vimforcpp(目前只支持 centos 7.x)
在自己的用户下执行指令 curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh 即可(不推荐在 root 下执行)
卸载自动化配置:,在自动化配置的用户下执行指令 bash ~/.VimForCpp/uninstall.sh
gcc 和 g++ 的选项基本上是一模一样的,gcc 用来编译 C语言,g++ 用来编译 C++
sudo yum -y install gcc 安装 gcc,sudo yum -y install gcc-c++ 安装 g++
编译器是用来将文本文件翻译成二进制可执行文件的
选项合起来 ESc、后缀合起来 iso(镜像文件后缀),这样可以方便记忆
对于第三方库文件,我们在写 C/C++代码时一直在使用(调用语言库文件中的函数),所以对于第三方库文件(除了语言库文件还有其他的库文件)我们是离不开的
Linux 系统中 C语言头文件(/usr/include),Linux 系统下 C语言标准库(/lib64/libc.so.6->/libc-2.17.so)
链接方式分为动态链接和静态链接
ldd 可执行文件
功能:显示该文件生成的过程中依赖的动态库文件
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ldd test
linux-vdso.so.1 => (0x00007fff02b98000)
libc.so.6 => /lib64/libc.so.6 (0x00007f442ed5e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f442f12b000)
常识:为了代码可以编译成可执行程序,系统中必须携带语言级别的头文件和语言对应的库
在安装 vs2022 的时候,最重要的一个工作也就是下载安装语言对应的头文件和库文件
常识:对于翻译型语言,库分两种(本质也是文件):
在 Linux 下去掉前缀 lib 和 后缀 .a/.so 就是库的名称
我们用的相当一部分指令都是 C语言写的,通过 ldd /usr/bin/ls 即可看到依赖了 C标准库
如何看待指令呢?指令==程序==工具,他们都是一样的(都是 C语言写的,都是经过编译形成的,都和 C标准库有关)
//代码中引用的头文件一方面告诉了程序员该文件有什么方法可以调用,另一方面告诉编译器库函数所在的位置
在代码中总有一些功能我自己是无法独立完成的,比如需要和硬件交互的IO函数等,这些需要我们了解操作系统的知识,通过系统调用接口来实现,就算我们了解了操作系统的知识,自己写,难免会踩坑,而别人的库大多数坑已经暴露了,因此使用别人的库,便可以提高开发效率
动态库(存放可执行的库函数代码的文件):为了让用户的程序可以动态链接
动态链接:把在动态库中需要的库函数的地址拷贝自己的程序中(程序运行时需要跳转到动态库中执行库函数),动态链接成功后,程序运行时依赖动态库
任何程序都可以从动态库中拷贝需要的库函数地址到自己的程序,所以动态库是被共享的,动态库也被称为共享库
由于动态库中保存的都是库函数的代码,所以动态库文件具有只读属性,不能修改的,使用时,通过链接时拷贝的地址,直接到库中调用即可
很多程序编译链接好后,都从依赖的动态库中拷贝了所调用的函数的地址,运行时便通过地址跳转到动态库中执行函数,如果动态库没了,所有依赖这个库的程序也就无法正常使用了
很多语言都是 C语言写的,很多程序都依赖于 C标准动态库,如果 C标准动态库被删了,系统中的绝大多数指令,就无法运行了
以前听说的在可执行程序中的符号表,要么保存的是数据,要么保存的就是函数地址
在 Linux 中默认采用的就是动态链接的方式
静态库(存放可执行的库函数代码的文件):为了让用户的程序可以静态链接
静态链接:把在静态库中需要的库函数的代码拷贝到自己的程序中(程序运行时无需跳转),静态链接成功后,也就不依赖静态库了
静态链接生成的可执行文件的大小,比动态链接生成的可执行文件大小大很多(正常情况下,相差了 120 倍)
在 gcc 中 加上 -static 选项,即可采用静态链接的方式
一般的云服务器,默认只安装了动态库,sudo yum -y install glibc-static 安装 C语言静态库,sudo yum -y install libstdc++-static 安装 C++静态库
file 可执行文件
功能:可以查看文件的链接方式
dynamic link 动态链接,static link 静态链接
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 4
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ gcc -o test_dynamic test.c
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 16
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
-rwxrwxr-x 1 admin admin 8496 Jan 12 18:00 test_dynamic
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ file test_dynamic
test_dynamic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=cfbf492c2da1edde1b484f4b2410bb33fcdb1f8e, not stripped
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 16
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
-rwxrwxr-x 1 admin admin 8496 Jan 12 18:00 test_dynamic
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ gcc -o test_static test.c -static
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 860
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
-rwxrwxr-x 1 admin admin 8496 Jan 12 18:00 test_dynamic
-rwxrwxr-x 1 admin admin 861432 Jan 12 18:16 test_static
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ file test_static
test_static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=2b55b0963638034b837eca52dfe74ef60c8b9deb, not stripped
-std=c99 表示支持 C99 标准
调试器主要是为了帮助程序员找到 bug 的位置,定位问题
sudo yum -y install gdb 安装 gdb
在 Linux 中用 gcc/g++ 默认编译形成的是 release 版本的可执行程序,需要在 gcc/g++ 编译时,指定 -g 选项,才能生成 debug 版本的可执行程序
debug 是调试版本,会添加调试信息,供程序员调试,release 是发布版本,供用户使用的,不会添加调试信息,因为用户不会去调试代码,并且不加调试信息还可以减小可执行程序的体积,方便用户下载
readelf -S 可执行文件 读取可执行文件的二进制构成,Linux 可执行文件遵守 ELF 格式,其中如果含有 debug 就代表包含调试信息
gdb 可执行文件 进入调试,ctrl + d 或者 q [quit] 退出调试,gdb 支持 tab 命令自动补全
make/Makefile 其实挺复杂的,目前只需要写一些简单的就好
在编译源文件时,如果指令写错,可能会导致源文件被清空(gcc -o test.c test),删除编译产生的文件时,如果指令写错,可能导致源文件被删了
为了避免频繁的写 gcc 指令和降低风险,所以想实现一定程度的自动化编译和自动化清理,因此可以使用自动化构建工具 make/Makefile
make 是一个命令,Makefile 是一个文件,需要自己在当前源代码的目录下创建
Makefile 是一个围绕依赖关系和依赖方法构建的一个自动化构建工具,完成一件事情,必须得有正确的依赖关系和正确的依赖方法(世界的运转规则就是这样)
简单的 Makefile 内容如下:
test:test.c
gcc -o test test.c
.PHONY:clean
clean:
rm test
Makefile 中写好内容后,在命令行中输入 make,make 会自动查找当前目录下的 Makefile 文件,然后从 Makefile 文件中的第一个依赖关系开始解析,如果依赖关系的依赖的对象不存在,则会继续向下扫描依赖对象的依赖关系的依赖对象,直到依赖对象存在,便执行对应的依赖方法,然后回退到上一个依赖关系,默认是执行第一个依赖关系,也可以在命令行中指定依赖关系,如 make test,make clean
当我们写好源代码时,make 即可生成可执行文件,make clean 即可清理掉可执行文件
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 8
-rw-rw-r-- 1 admin admin 61 Jan 12 19:01 Makefile
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ cat Makefile
test:test.c
gcc -o test test.c
.PHONY:clean
clean:
rm test
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ make
gcc -o test test.c
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 20
-rw-rw-r-- 1 admin admin 61 Jan 12 19:01 Makefile
-rwxrwxr-x 1 admin admin 8536 Jan 12 19:01 test
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ./test
110 100
PRINT
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 20
-rw-rw-r-- 1 admin admin 61 Jan 12 19:01 Makefile
-rwxrwxr-x 1 admin admin 8536 Jan 12 19:01 test
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ make clean
rm test
[admin@iZ2vcer6gtjgqa43cdpeeaZ ~]$ ll
total 8
-rw-rw-r-- 1 admin admin 61 Jan 12 19:01 Makefile
-rw-rw-r-- 1 admin admin 210 Jan 12 17:56 test.c
在生成目标文件的依赖关系中,当我们执行 make 后,再执行 make(这里指 make test),便会提示 make: `test’ is up to date.test(test 是最新的了),这种情况称作不是总是执行的,如果想让 make 不报错,也就是 make(这里指 make test) 总是被执行,可以在依赖关系上面加上 .PHONY:test
.PHONY 修饰的目标被称作伪目标(因为总是被执行的,也就代表执行该依赖关系时,目标总是会被替换成新的)
在开发中源文件的时间,一定是早于可执行文件的,并且修改文件的内容后,会自动更新文件的时间,而 make 是根据这一原理,通过依赖文件的最近修改时间和目标文件的创建时间来判断目标文件是否是最新的,如果依赖文件的最近修改时间小于目标文件的创建时间,也就代表目标文件是最新的
在 vs 中,有时我们修改了源代码,但是运行的结果却还是之前的源代码的结果,就是因为 vs 把我们修改了的源代码的文件时间任然识别成了老的文件(vs 的 bug),便直接运行了上一次生成的可执行文件,这时候清理一下解决方案,再重新生成便可以解决了
.PHONY 原理:根据 make 判断目标文件是否是最新的方式,我们可以用 touch 修改依赖文件的时间,来欺骗 make,以达到总是被执行
stat 文件
功能:查看文件的时间
touch 文件
功能:文件存在时,将文件的时间更新为最新
一般不会在编译文件的依赖关系加上 .PHONY,当我们源文件很多时,编译文件是一件非常花时间的事情
clean 虽然也被修饰为总是被执行的,但是如果没有要删除的文件,指令会报错,为什么还要用.PHONY 来修饰 clean 呢? 其实,想达到的目的是,你要我清理,我就执行清理,但是能不能清理成功就不知道了,重点是我执行了清理
进度条样式
[################### ][num%][\]
预备知识:
通过显示并覆盖,便可以实现进度条,其中 usleep 函数的单位是微秒
//Makefile
test:progress.c test.c
gcc -o test progress.c test.c
.PHONY:clean
clean:
rm test
//progress.h
#include
#include
#define C '='
void progress();
//progress.c
#include "progress.h"
void progress()
{
char str[102] = {0};
char* ch = "|/-\\";
int i = 0;
for(i = 0; i <= 100; ++i)
{
//C语言 printf 是可以输出彩色内容的
//感兴趣的话可以百度一下 C语言输出颜色格式,改进进度条代码
printf("[%-100s][%d%%][%c]\r", str, i, ch[i % 4]);
fflush(stdout);
usleep(100000);
str[i] = C;
if(i < 99) str[i + 1] = '>';
}
printf("\n");
}
//test.c
#include "progress.h"
int main()
{
progress();
return 0;
}
凡是向显示器打印的东西都是字符,printf 函数会把我们输出的数据转换为字符串,然后用 putc 一个字符一个字符的显示出来,如 printf(“%d”, 123); 输出的内容是 1 字符,2 字符,3 字符,所以键盘和显示器也称作字符设备
git 是一个版本控制工具,git 很强大,除了版本管理之外,还有分支管理,版本回退,版本标签等,这些内容就能支持我们进行多人协作
版本管理是什么?
以写实验报告为例,当张三第一次写完时,去找老师询问报告是否合格,老师说这里需要改改,当张三改完之后,再次去询问老师是否合格,老师说还需要改改,再次改完之后,再去询问老师,老师说,这次改的没有以前的好,把你的第一个版本给我吧,由于张三每次都是在当前的版本上进行修改,导致张三没有以前的版本,这时候就很麻烦,后来张三想到了一个办法,我每次写完一个版本时,我就记录一下,写完一个就记录一个,当我想要以前的版本的时候,我就可以很轻松的拿到了(这就是版本管理),后来,由于张三版本管理做的很好,就想着推广一下,让别人也可以用到自己的版本管理,于是每天就会有很多人发自己的版本给张三记录,张三每天就只能 ctrl c,ctrl v,的进行版本管理,张三便想到了一个办法,把这个版本管理做成一个软件,客户端和服务端的软件,需要用版本管理的人,用这个软件上传到服务端自己的账号下就可以了,并且可以浏览自己上传的内容,后来想到客户端和服务器其实没必要写成不一样的,就将客户端和服务器改成是一样的,也就是如果用户可以直接选择是否上传自己的版本到远端,也可以用客户端的软件,在自己的本地进行版本管理,也可以上传到远端进行管理(防止本地电脑出现问题),后来这个软件用的人很多了,但是软件是纯命令行的,后来就有公司将服务端做成了可视化界面(网站),用浏览器便可以直接查看修改直接的文件,并将客户端也做成了双击就可以上传等,这种网站和客户端就本称作 gitee 和 github,gitee 和 github 这些平台,底层的相关技术就是采用 git 来实现的
克隆到本地的仓库其实就是一个文件夹(.git),删除 .git 文件夹,也就代表删除了本地仓库
遇到问题时先找有没有现成的解决方案