Linux开发工具详解(一):软件包管理、Vim、GCC/G++、Makefile与进度条实战

Linux开发工具详解(一):软件包管理、Vim、GCC/G++、Makefile与进度条实战


🔥 星恒随风: 个人主页 ❄️ 个人专栏: 《指针合集》 | 《C语言基础》 | 《数据结构》 | 《机器学习导论》 | 《前端基础》 | 《python基础》 | 《C++从入门到入土》 | 《Linux的学习之旅》 ✨ 数据即知识,压缩即智能


文章目录

前言:Linux开发并不是只会写代码

1. 从"写代码"到"完成一个程序"

刚开始学习 C/C++ 时,我们可能只关心:

text 复制代码
写代码
↓
点一下运行
↓
得到结果

IDE 已经帮我们完成了大量工作。

但在 Linux 中,如果直接使用命令行开发,一个程序通常会经历:

text 复制代码
安装开发工具
    ↓
编辑源代码
    ↓
编译
    ↓
链接
    ↓
生成可执行程序
    ↓
运行
    ↓
修改
    ↓
重新构建

分别会涉及:

text 复制代码
apt / dnf / yum
        ↓
软件包管理

Vim
        ↓
代码编辑

GCC / G++
        ↓
编译与链接

make / Makefile
        ↓
自动化构建

本文就从这条开发链开始。


一、Linux软件包管理

1. 为什么需要软件包管理器?

1.1 直接从源码安装有什么问题?

理论上,Linux 软件完全可以:

text 复制代码
下载源码
↓
配置
↓
编译
↓
链接
↓
安装

例如:

bash 复制代码
./configure
make
sudo make install

但问题是:

text 复制代码
编译耗时
依赖复杂
版本不好管理
卸载困难

因此 Linux 发行版通常会把软件提前:

text 复制代码
编译
打包
建立依赖关系

形成:

text 复制代码
软件包

然后放入:

text 复制代码
软件仓库 Repository

用户通过包管理器完成安装。


2. 软件包与包管理器是什么关系?

2.1 可以类比手机应用商店

可以粗略理解为:

text 复制代码
软件包
≈ App

软件仓库
≈ 应用商店服务器

包管理器
≈ 应用商店客户端

用户执行:

bash 复制代码
sudo apt install git

背后实际上可能经历:

text 复制代码
查询仓库
↓
找到 git 软件包
↓
分析依赖
↓
下载依赖
↓
下载 git
↓
安装
↓
记录安装信息

因此包管理器最重要的价值之一就是:

text 复制代码
自动处理依赖

3. 不同Linux发行版使用什么包管理器?

3.1 Debian / Ubuntu

主要使用:

bash 复制代码
apt

例如:

bash 复制代码
sudo apt update
sudo apt install gcc

3.2 CentOS 7等较老的Red Hat系环境

很多课程环境使用:

bash 复制代码
yum

例如:

bash 复制代码
sudo yum install gcc

3.3 Fedora、RHEL 8/9等较新的系统

现代 Red Hat 系环境核心已经转向:

bash 复制代码
dnf

例如:

bash 复制代码
sudo dnf install gcc

部分系统中的:

bash 复制代码
yum

主要作为兼容入口继续存在。

所以实际使用时应先确定:

bash 复制代码
cat /etc/os-release

查看自己的发行版。


二、apt / dnf / yum常用操作

1. 查询软件

1.1 Ubuntu

bash 复制代码
apt search git

查看详细信息:

bash 复制代码
apt show git

1.2 RHEL / Fedora

bash 复制代码
dnf search git

也可以:

bash 复制代码
dnf info git

旧环境可能使用:

bash 复制代码
yum list | grep git

2. 安装软件

2.1 Ubuntu

bash 复制代码
sudo apt install -y git

2.2 Fedora / RHEL

bash 复制代码
sudo dnf install -y git

旧 CentOS:

bash 复制代码
sudo yum install -y git

其中:

text 复制代码
sudo
↓
以管理员权限执行

-y
↓
自动确认安装

3. 删除软件

Ubuntu:

bash 复制代码
sudo apt remove git

Fedora / RHEL:

bash 复制代码
sudo dnf remove git

4. 更新软件包索引

Ubuntu 常见:

bash 复制代码
sudo apt update

升级:

bash 复制代码
sudo apt upgrade

Fedora / RHEL:

bash 复制代码
sudo dnf upgrade

三、什么是软件源?

1. 软件到底从哪里下载?

执行:

bash 复制代码
sudo apt install vim

并不是从:

text 复制代码
互联网随机搜索 Vim

而是从已经配置好的:

text 复制代码
软件仓库

下载。


2. 为什么会有镜像源?

官方软件源可能距离用户较远。

于是很多组织建立:

text 复制代码
Mirror
镜像站

定期同步官方仓库。

这样用户就可以:

text 复制代码
从距离较近的服务器下载软件

通常速度更稳定。


3. 国内常见镜像站

常见的有:

text 复制代码
清华大学 TUNA
中国科学技术大学 USTC
阿里云镜像站
上海交通大学镜像站

具体是否需要更换,应根据:

text 复制代码
所在网络
发行版
当前下载速度

决定。


四、Vim:Linux终端中的经典编辑器

1. vi与Vim是什么关系?

1.1 vi

vi 是 Unix/Linux 中非常经典的:

text 复制代码
多模式文本编辑器

1.2 Vim

Vim:

text 复制代码
Vi IMproved

可以理解成:

text 复制代码
vi 的增强版本

增加了很多功能,例如:

text 复制代码
语法高亮
更丰富的命令
插件能力
可视模式

五、Vim最重要的三个模式

1. 正常模式 Normal Mode

进入 Vim:

bash 复制代码
vim test.c

默认进入:

text 复制代码
正常模式

这里主要用于:

text 复制代码
移动
复制
删除
粘贴
查找
执行命令

而不是普通地输入文本。


2. 插入模式 Insert Mode

在正常模式按:

text 复制代码
i

即可开始输入。

常用方式:

text 复制代码
i
↓
在当前光标位置前开始输入

a
↓
在当前光标位置后开始输入

o
↓
在当前行下方创建新行

返回正常模式:

text 复制代码
Esc

3. 末行模式 Command-line Mode

正常模式输入:

text 复制代码
:

进入末行模式。

常用于:

text 复制代码
保存
退出
配置
替换
跳转

例如:

vim 复制代码
:w

保存。

vim 复制代码
:q

退出。

vim 复制代码
:wq

保存并退出。

vim 复制代码
:q!

放弃修改并强制退出。


六、Vim模式切换必须先掌握

1. 最核心切换关系

text 复制代码
                 i / a / o
       Normal ─────────────→ Insert
          ↑                     |
          └──────── Esc ────────┘


                 :
       Normal ─────────────→ Command-line
          ↑                     |
          └──────── Esc ────────┘

如果刚开始使用 Vim 时发现:

text 复制代码
键盘输入出来的不是文字

第一反应应该是:

text 复制代码
我现在处于什么模式?

七、Vim正常模式常用命令

1. 光标移动

1.1 基础移动

text 复制代码
h → 左
j → 下
k → 上
l → 右

这是 Vim 最经典的一组按键。


1.2 按单词移动

text 复制代码
w
↓
下一个单词开头

e
↓
当前/下一个单词结尾

b
↓
上一个单词开头

1.3 行内移动

text 复制代码
0
↓
行开头

^
↓
本行第一个非空白字符

$
↓
行末尾

1.4 文件移动

text 复制代码
gg
↓
文件开头

G
↓
文件结尾

跳到第 50 行:

text 复制代码
50G

2. 删除

删除当前字符:

text 复制代码
x

删除当前行:

text 复制代码
dd

删除 5 行:

text 复制代码
5dd

3. 复制和粘贴

复制当前行:

text 复制代码
yy

复制 5 行:

text 复制代码
5yy

粘贴:

text 复制代码
p

于是经典组合:

text 复制代码
yy
p

就是:

text 复制代码
复制当前行
↓
粘贴

4. 撤销与重做

撤销:

text 复制代码
u

重做:

text 复制代码
Ctrl + r

八、Vim查找

1. 向下查找

vim 复制代码
/main

继续寻找下一个:

text 复制代码
n

反方向:

text 复制代码
N

2. 向上查找

vim 复制代码
?main

九、Vim常用配置

1. 用户配置文件

一般使用:

text 复制代码
~/.vimrc

例如:

bash 复制代码
vim ~/.vimrc

2. 一份基础配置

vim 复制代码
syntax on

set number

set tabstop=4
set shiftwidth=4
set expandtab

set autoindent
set smartindent

set cursorline

其中:

text 复制代码
set number
↓
显示行号

tabstop
↓
Tab 显示宽度

shiftwidth
↓
自动缩进宽度

expandtab
↓
把 Tab 转为空格

对于刚开始学习 Linux 开发来说,不需要一开始就在 Vim 上安装大量插件。

先掌握:

text 复制代码
编辑
保存
查找
复制
删除
模式切换

更重要。


十、GCC与G++到底是什么?

1. GCC

GCC 可以理解为:

text 复制代码
GNU Compiler Collection

其中支持:

text 复制代码
C
C++
Fortran
...

多种语言。


2. gcc与g++

日常使用中:

bash 复制代码
gcc test.c

通常用于 C。

bash 复制代码
g++ test.cpp

通常用于 C++。

对于 C++ 项目更推荐直接使用:

bash 复制代码
g++

因为它会自动按照 C++ 的方式完成:

text 复制代码
编译
以及
C++ 标准库链接

十一、一个C程序到底是怎样变成可执行文件的?

1. 四个阶段

从:

text 复制代码
hello.c

到:

text 复制代码
hello

通常可以分成:

text 复制代码
源文件 .c
   |
   | 预处理
   v
.i 文件
   |
   | 编译
   v
.s 汇编文件
   |
   | 汇编
   v
.o 目标文件
   |
   | 链接
   v
可执行程序

也就是:

text 复制代码
预处理
↓
编译
↓
汇编
↓
链接

十二、第一阶段:预处理

1. 预处理主要做什么?

例如:

text 复制代码
宏替换
头文件展开
条件编译
去除注释

代码:

cpp 复制代码
#include <stdio.h>

#define NUM 10

这些:

text 复制代码
以 # 开头的预处理指令

首先由预处理器处理。


2. 只进行预处理

bash 复制代码
gcc -E hello.c -o hello.i

其中:

text 复制代码
-E
↓
完成预处理后停止

可以:

bash 复制代码
vim hello.i

查看展开后的结果。

你会发现一个非常小的:

cpp 复制代码
#include <stdio.h>

最终可能展开出非常多内容。


十三、第二阶段:编译

1. 从C代码到汇编

执行:

bash 复制代码
gcc -S hello.i -o hello.s

得到:

text 复制代码
hello.s

这里会进行:

text 复制代码
语法分析
语义分析
中间表示
优化
代码生成

最终得到:

text 复制代码
汇编代码

2. 为什么要经过汇编?

C/C++ 是:

text 复制代码
高级语言

CPU 真正能够执行的是:

text 复制代码
机器指令

汇编语言可以看作:

text 复制代码
机器指令的人类可读表示

所以编译器需要逐步把高级语义转换成底层机器代码。


十四、第三阶段:汇编

执行:

bash 复制代码
gcc -c hello.s -o hello.o

得到:

text 复制代码
hello.o

.o 文件已经包含:

text 复制代码
机器代码

但通常还不能直接运行。

因为程序中可能还引用:

text 复制代码
printf
malloc
其他源文件中的函数

这些符号还没有全部解决。


十五、第四阶段:链接

bash 复制代码
gcc hello.o -o hello

得到:

text 复制代码
hello

然后:

bash 复制代码
./hello

运行。


十六、为什么printf不用自己实现?

假设:

c 复制代码
#include <stdio.h>

int main()
{
    printf("hello\n");
}

stdio.h 主要提供:

text 复制代码
printf 的声明

真正的实现位于:

text 复制代码
C 标准库

中。

链接器负责把:

text 复制代码
程序中对 printf 的引用

与库中的:

text 复制代码
printf 实现

联系起来。


十七、静态库与动态库

1. Linux中的常见扩展名

静态库:

text 复制代码
.a

动态库:

text 复制代码
.so

Windows 常见:

text 复制代码
.lib
.dll

2. 静态链接

静态链接时:

text 复制代码
需要的库代码
↓
进入最终可执行文件

优点:

text 复制代码
运行时对外部库依赖较少
部署简单

缺点:

text 复制代码
可执行文件通常更大
多个程序可能重复包含相同库代码
库升级后通常需要重新链接

3. 动态链接

动态链接时:

text 复制代码
程序文件
+
运行时需要的共享库

共同完成执行。

优点:

text 复制代码
多个程序可共享同一个库
程序体积通常更小
库升级更方便

缺点:

text 复制代码
运行环境必须存在兼容的共享库

4. 查看程序依赖的动态库

bash 复制代码
ldd ./hello

可能看到:

text 复制代码
libc.so.6
libstdc++.so.6
...

5. 查看文件类型

bash 复制代码
file hello

这是排查:

text 复制代码
ELF 类型
架构
是否动态链接
是否包含调试信息

非常常用的命令。


十八、GCC/G++常用选项

1. 输出文件

bash 复制代码
gcc main.c -o app

2. 仅编译不链接

bash 复制代码
gcc -c main.c -o main.o

3. 生成调试信息

bash 复制代码
gcc main.c -g -o app

后面的 GDB 调试依赖:

text 复制代码
-g

生成的调试信息。


4. 开启警告

推荐:

bash 复制代码
gcc main.c \
    -Wall \
    -Wextra \
    -o app

需要注意:

text 复制代码
-Wall

并不是"开启世界上所有 GCC 警告"。

它代表:

text 复制代码
开启一组常用的重要警告

而:

text 复制代码
-Wextra

会再增加一组检查。

对于学习阶段非常建议:

text 复制代码
不要用 -w 把警告全部关掉

很多编译器 Warning 正是在提前帮你发现 Bug。


5. 优化选项

常见:

text 复制代码
-O0
-O1
-O2
-O3
-Og
-Os

其中:

text 复制代码
-O0
↓
基本不优化,也是默认等级

-O2
↓
常见发布构建优化等级

-O3
↓
更加激进的优化

-Og
↓
兼顾一定优化与调试体验

学习 GDB 时可以:

bash 复制代码
gcc main.c \
    -g \
    -O0 \
    -Wall \
    -Wextra \
    -o app

避免过度优化导致:

text 复制代码
变量被优化掉
代码执行顺序和源码差异较大

十九、为什么需要Makefile?

1. 一个文件时还没问题

只有:

text 复制代码
main.c

时:

bash 复制代码
gcc main.c -o app

非常简单。


2. 多文件项目开始麻烦

假设:

text 复制代码
main.c
process.c
process.h
util.c
util.h

手工:

bash 复制代码
gcc -c main.c
gcc -c process.c
gcc -c util.c

gcc main.o process.o util.o -o app

如果:

text 复制代码
只修改了 process.c

其实只需要重新:

text 复制代码
编译 process.c
↓
重新链接

没有必要重新编译所有文件。

于是需要:

text 复制代码
自动分析依赖
+
增量构建

这就是:

text 复制代码
make
+
Makefile

二十、make与Makefile是什么关系?

1. make

text 复制代码
make

是:

text 复制代码
构建工具

2. Makefile

text 复制代码
Makefile

是:

text 复制代码
描述构建规则的文件

可以理解成:

text 复制代码
Makefile
↓
说明项目应该怎么构建

make
↓
读取这些规则并执行

二十一、Makefile最核心的规则

1. 基本语法

makefile 复制代码
target: prerequisites
	command

注意:

command 前通常必须是 Tab,不是普通空格。

例如:

makefile 复制代码
app: main.c
	gcc main.c -o app

这里:

text 复制代码
target
↓
app

prerequisite
↓
main.c

recipe
↓
gcc main.c -o app

二十二、make如何判断要不要重新构建?

1. 基于文件修改时间

假设:

makefile 复制代码
app: main.o
	gcc main.o -o app

make 会比较:

text 复制代码
main.o 的修改时间

和

app 的修改时间

如果:

text 复制代码
main.o 比 app 更新

说明:

text 复制代码
依赖发生了变化

于是重新执行链接。

所以 make 能实现:

text 复制代码
增量构建

二十三、一个多文件Makefile

makefile 复制代码
app: main.o process.o
	gcc main.o process.o -o app

main.o: main.c process.h
	gcc -c main.c -o main.o

process.o: process.c process.h
	gcc -c process.c -o process.o

依赖图:

text 复制代码
        app
       /   \
      /     \
 main.o   process.o
   |        |
main.c   process.c
     \     /
     process.h

修改:

text 复制代码
process.c

时:

text 复制代码
只重新构建 process.o
↓
重新链接 app

二十四、clean为什么要写成.PHONY?

1. 普通clean

makefile 复制代码
clean:
	rm -f *.o app

使用:

bash 复制代码
make clean

2. 潜在问题

如果目录中恰好真的存在:

text 复制代码
clean

这个文件,make 可能认为目标:

text 复制代码
clean

已经存在并且无需构建。


3. 声明伪目标

makefile 复制代码
.PHONY: clean

clean:
	rm -f *.o app

.PHONY 的含义不是简单的:

text 复制代码
忽略所有时间比较

更准确地说:

clean 不代表一个真正需要生成的文件,而代表一个需要执行的动作。

因此:

bash 复制代码
make clean

会执行对应 recipe,而不会把它当普通文件目标处理。


二十五、Makefile变量

1. 定义变量

makefile 复制代码
CC = gcc
TARGET = app

使用:

makefile 复制代码
$(CC)
$(TARGET)

例如:

makefile 复制代码
CC = gcc
TARGET = app

$(TARGET): main.c
	$(CC) main.c -o $(TARGET)

二十六、自动变量

Makefile 中非常重要的一组变量:

text 复制代码
$@
↓
当前目标

$<
↓
第一个依赖

$^
↓
所有依赖

例如:

makefile 复制代码
app: main.o process.o
	gcc $^ -o $@

展开:

bash 复制代码
gcc main.o process.o -o app

二十七、模式规则

例如:

makefile 复制代码
%.o: %.c
	gcc -c $< -o $@

表示:

text 复制代码
任意 xxx.o
依赖
同名 xxx.c

于是:

text 复制代码
main.o ← main.c
process.o ← process.c
util.o ← util.c

都可以复用这一条规则。


二十八、一份更实用的Makefile

makefile 复制代码
CC = gcc

CFLAGS = -Wall -Wextra -g
TARGET = processbar

SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)

$(TARGET): $(OBJ)
	$(CC) $^ -o $@

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

.PHONY: clean

clean:
	rm -f $(OBJ) $(TARGET)

执行:

bash 复制代码
make

编译。

清理:

bash 复制代码
make clean

二十九、综合实践:Linux终端进度条

1. 为什么这个案例值得做?

它可以一次串联:

text 复制代码
\r 和 \n
stdout 缓冲
fflush
数组
字符串
函数拆分
多文件编译
Makefile

三十、\r与\n不是一回事

1. \n:换行

c 复制代码
printf("hello\n");

让输出进入下一行。


2. \r:回车

c 复制代码
printf("\r");

表示:

text 复制代码
光标回到当前行开头

而不一定进入下一行。

因此:

text 复制代码
10%
20%
30%

如果想让它们一直刷新在:

text 复制代码
同一行

就可以利用:

text 复制代码
\r

三十一、为什么必须fflush(stdout)?

1. stdout通常存在缓冲

例如:

c 复制代码
printf("hello");

sleep(3);

你可能发现:

text 复制代码
hello

没有立刻显示。

原因之一是:

text 复制代码
stdout 缓冲机制

2. 手动刷新

c 复制代码
printf("hello");

fflush(stdout);

sleep(3);

fflush(stdout):

text 复制代码
要求把当前标准输出缓冲中的内容立即提交

进度条之所以能够:

text 复制代码
实时刷新

很大程度上依赖:

c 复制代码
fflush(stdout);

三十二、先写一个倒计时

c 复制代码
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    int i = 10;

    while (i >= 0)
    {
        printf("%-2d\r", i);

        fflush(stdout);

        --i;

        sleep(1);
    }

    printf("\n");

    return 0;
}

关键:

text 复制代码
\r
↓
不断回到行首

fflush
↓
立即显示

三十三、进度条核心代码

c 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define WIDTH 50

void ProgressBar(void)
{
    char bar[WIDTH + 1];

    memset(
        bar,
        0,
        sizeof(bar)
    );

    const char* spinner =
        "|/-\\";

    int spinner_len =
        strlen(spinner);

    for (int i = 0;
         i <= 100;
         ++i)
    {
        int count =
            i * WIDTH / 100;

        memset(
            bar,
            '=',
            count
        );

        bar[count] = '\0';

        printf(
            "[%-50s] [%3d%%] [%c]\r",
            bar,
            i,
            spinner[
                i % spinner_len
            ]
        );

        fflush(stdout);

        usleep(50000);
    }

    printf("\n");
}

三十四、进度条为什么能够"动起来"?

1. 第一次打印

text 复制代码
[=====                                             ] [10%]

末尾:

text 复制代码
\r

光标回到本行开头。


2. 下一次重新覆盖

text 复制代码
[==========                                        ] [20%]

并没有:

text 复制代码
打印 100 行

而是不断:

text 复制代码
覆盖同一行

于是视觉上产生动画效果。


三十五、完整开发流程总结

现在可以把 Linux 基础开发工具串起来:

text 复制代码
apt / dnf
    ↓
安装开发工具
    ↓
Vim
    ↓
编辑 C/C++
    ↓
GCC / G++
    ↓
预处理 → 编译 → 汇编 → 链接
    ↓
Makefile
    ↓
自动化构建
    ↓
运行程序

这套流程的意义并不是:

text 复制代码
"以后不用 IDE"

而是让我们真正知道:

IDE 的 Build、Run、Clean、Debug 按钮背后究竟发生了什么。


总结

这一阶段最重要的不是死记几十条命令,而是理解整个 Linux 开发工具链。

1. 软件包管理

text 复制代码
apt
dnf
yum

解决:

text 复制代码
软件安装
依赖处理
升级
卸载

2. Vim

核心是:

text 复制代码
Normal
Insert
Command-line

三个模式之间的切换。


3. GCC/G++

代码经历:

text 复制代码
.c/.cpp
↓
预处理
↓
编译
↓
汇编
↓
链接
↓
可执行程序

4. Makefile

本质是:

text 复制代码
描述依赖关系
+
描述依赖生成方法

让:

text 复制代码
重复手工编译

变成:

bash 复制代码
make

5. 最终形成

text 复制代码
编辑
↓
构建
↓
运行
↓
修改
↓
重新构建

这才是一个真正的开发循环。


相关推荐
Chill6041 分钟前
服务器home文件夹太小怎么把配置迁移到其他盘
运维·服务器
LRL_42 分钟前
【K8s 存储】Longhorn v1.12.1 离线安装全流程:外网制作离线包 + 内网部署(附踩坑实录)
linux·windows·node.js
传奇开心果编程1 小时前
【ArkUI进阶练中学】第10课:架构设计与工程化最佳实践
学习·ui·华为·harmonyos
小小、码农1 小时前
Ubuntu / Linux 软件安装完整笔记
linux·笔记·ubuntu
在猴站学算法1 小时前
(SQL注入学习)联合查询注入(UNION-Based)
sql·学习·网络安全
yunwei371 小时前
eBPF 开发实践:使用 sockops 加速网络请求转发
linux·后端·性能优化
rest10241 小时前
做io测试
linux·服务器·网络
一条破秋裤1 小时前
Linux 网络编程基础:网络分类、分层模型与数据封装
linux·运维·网络
欣欣之王来了1 小时前
5G的行业应用:工业互联网、车联网、智慧医疗中的网络支撑
网络·学习·计算机网络·安全·教程