前言:学了Linux的指令,再就是Linux基础开发工具,熟练掌握基础开发工具是提升效率的关键。本文学习Linux的基础开发工具,无论是软件安装、代码编辑,还是编译调试、版本控制,一套顺手的工具链能让你在开发路上少走很多弯路。本文将结合实战,详细讲解 Linux 下核心开发工具的使用方法。
一、软件包管理器
1.1 什么是软件包/软件管理器?
软件包
:简单来说就是,开发人员把软件提前编译好,并且做成软件包(即安装程序)放在服务器上(APP)
软件管理器
:通俗来说就是管理软件包的(应用商店),能自行解决依赖关系、下载和安装软件包。
yum
(yellow dog updater modified):Linux下非常常用的一种包管理器,主要用于Centos,RedHat等apt
:也是一种包管理器,多用于Ubuntu 。
1.2 Linux软件生态
操作系统的好坏评估,就是看其生态问题,首先有一个问题:为什么会有人免费给特定社区提供软件,还发布?还提供云服务器让你下载?
是因为要提供相关软件与云服务,构建专属生态,增强社区粘性与影响力。一个软件有一个好的生态环境,就会有更多人去使用,讨论问题,分享经验,解决问题,如Linux的生态环境。
- 下载软件的图示过程:
还有一个问题,国外发行的软件版本,国内是怎么用上的呢?
国内的一些社会性公司会购买国外的软件包服务器,将该服务器内的软件等拷贝到国内的软件包服务器上,然后上线到国内的一些网站上,即镜像网站。
一些镜像网站:
- 阿里云:https://developer.aliyun.com/mirror/
- 清华大学:https://mirrors.tuna.tsinghua.edu.cn/
- 中科大:http://mirrors.ustc.edu.cn/
- 北交大:https://mirror.bjtu.edu.cn/
- 中科院软件研究所:http://mirror.iscas.ac.cn/
- 上交大:https://ftp.sjtu.edu.cn/
1.3 具体操作:查装卸
(1)基础操作对比(centos vs ubuntu)
操作需求 | Centos(yum) | Ubuntu |
---|---|---|
查看软件包(如lrzsz) | yum list | grep lrzsz |
安装软件 | sudo yum install -y lrzsz | sudo apt install -y lrzsz |
卸载软件 | sudo yum remove -y lrzsz | sudo apt install -y lrzsz |
清理缓存 | sudo yum clean all | sudo apt clean |
(2)注意事项: |
- 安装/卸载需
sudo
权限(修改系统目录) - 同一时间只能执行一个
yum/apt
操作(防冲突)
二、编辑器vim:Linux下的“代码神器”
Vim 是 Linux 下功能最强大的文本编辑器之一,兼容 Vi 且支持语法高亮、多模式编辑,掌握它能极大提升代码编写效率。本节聚焦 Vim 核心模式与实用操作,帮你快速上手。
IDE例子:
2.1 核心认知:Vim和Vi的区别
vi
:Linux的原生编辑器,功能基础vim
:vi的升级版,支持语法高亮、可视化操作,兼容所有vi命令,可视化操作不仅可以在终端运行,也可以运行于 x window、mac os 、windows等
2.2 vim的三大核心模式:切换是关键
三大核心模式:命令模式(command mode)、插入模式(insert mode)和底行模式(last line mode)
模式名称 | 功能描述 | 进入方式 | 退出方式 |
---|---|---|---|
命令模式 | 控制屏幕光标移动,字符、字或行的删除,复制或进入insert mode/last line mode | 打开vim默认进入;其他模式按 Esc |
- |
插入模式 | 输入文本内容 | 命令模式下按i (光标前)/a (光标后)/o (新行) |
Esc |
底行模式 | 文件的保存/退出、查找、列行号等全局操作 |
命令模式下按shift+; (即: ) |
按Esc 或执行命令后自动返回 |
2.3 vim的实用操作:从入门到高效
(1)vim基础操作:
- 进入vim,在系统提示符输入
vim 文件名称
,即可进入vim全屏幕编辑画面,但是刚进入时是处于正常模式
,要切换到插入模式
才可以输入文字 正常模式
切换至插入模式
:直接输入==a/i/o==插入模式
切换至正常模式
:Esc正常模式
切换至底行模式
:shift+;- 退出vim模式并且保存文件:在正常模式下,按shift+; (即 : )进入底行模式后,输入下面的命令:
命令 | 功能 |
---|---|
w | 保存当前文件 |
wq | 存盘并退出vim |
q! | 不存盘,强制退出vim |
wq! | 存盘并强制退出vim |
(2)vim正常模式命令集:
1.插入模式:
- 正常模式下按i进入插入模式后是从光标当前位置开始输入文件
- 按 a 进入插入模式是从当前光标所在位置的下一个位置开始输入文字
- 按 o 进入插入模式是插入新的一行,从行首开始输入文字
2.移动光标:
- vim可以直接用键盘上的光标来上下左右移动,即小写英文字母的h、j、k、l,分别控制光标左、下、上、右
G:
移动到文章的最后$/^:
移动到光标所在行的行尾/行首w/e:
光标跳到下个字的开头/字尾b:
光标回到上个字的开头nl:
光标回到该行的第n个位置,如:5l,6lgg
:进入到文本开始shift+g
:进入到文本末端Ctrl+b/f
:屏幕往后/前移动一页ctrl+u/d
:屏幕往后/前移动半页
3.删除文字:
x
:每按一次,删除光标所在位置的一个字符nx
:即删除光标所在位置的“后面(包括自己在内)”n个字符(n代表数字)X
:大写的X,每按一次,删除光标所在位置的“前面”一个字符nX
:即删除光标所在位置的“前面”n个字符(n代表数字)dd
:删除光标所在行ndd
:从光标开始删除n(n代表数字)行
4.复制
yw
:将光标所在之处到字尾的字符复制到缓冲区nyw
:复制n个字到缓冲区yy
:复制光标所在行到缓冲区nyy
:拷贝n行到缓冲区p
:将缓冲区的字符贴到光标所在位置
5.替换:
r
:替换光标所在处的字符R
:替换光标所到之处的字符,直到按下ESC键为止
6.撤销上一次的操作:
u
:撤销(相当于Windows的CTRL+z)ctrl+r
:对 u的恢复,即撤销u
7.更改:
cw
:更改光标所在处的字到字尾处cnw
:更改n个字
8.跳至指定的行:
ctrl+g
:列出光标所在行的行号nG
:移动到光标至文章的第n行行首
(3)vim底行模式命令集:
在使用底行模式之前,先按ESC键确认已处于正常模式,再按shift+;
进入底行模式
命令 | 功能 |
---|---|
set nu | 列出行号 |
n(n代表一个数字) | 输入n后,再按回车键,就会跳转到文章的第n行 |
/或?+关键字 | 查找想要的关键字,按n键往后寻找 |
2.4简单配置:更好用
vim配置分为两类,推荐自定义,用起来更顺手(不影响系统全局)
- 进入用户主目录:
cd ~
- 编辑配置文件:
vim .vimrc
- 常用配置项如下(举例):
syntax on " 开启语法高亮
set nu " 显示行号
set shiftwidth=4 " 缩进4个空格
set tabstop=4 " Tab键对应4个空格
【注】还有很多配置,可以按照喜好配置
三、GCC/G++编辑器:从源代码到可执行文件
GCC(C编辑器)与G++(C++编辑器)是Linux下编译C/C++代码的核心工具,掌握其编译流程与参数,能更好的理解代码“如何变程序”
3.1编译四步曲:层层递进的过程
以C语言代码为例,GCC编译选项:gcc 选项 要编译的文件 选项 目标文件
从.c
源代码到可执行文件,需经历:预处理->编译->汇编->链接
四步,每一步都可通过GCC选项独立控制:
-E
:让gcc在预处理结束后停止编译过程-o
:是指目标文件.i
:文件为已经过预处理的C原始程序-S
:进行查看,该选项只进行编译而不进行汇编,生成汇编代码-c
:查看汇编代码是否已转化为二进制代码了
步骤 | 功能描述 | GCC选项 | 输出文件后缀 | 命令示例 |
---|---|---|---|---|
预处理 | 宏定义,文件包括,条件编译,去注释 | -E | .i | gcc -E hello.c -o hello.i |
编译 | 检查代码语法,将预处理文件转为汇编代码 | -S | .s | gcc -S hello.o -o hello.s |
汇编 | 将汇编代码转为机器码(二进制目标文件) | -c | .o | gcc -c hello.s -o hello.o |
链接 | 链接目标文件 | 无(默认) | 无(自定义) | gcc hello.o -o hello |
3.2 核心概念:静态链接VS动态链接
链接本质:关联代码与依赖库(如printf依赖于libc.so)
(1)静态链接:编译时将库代码全部嵌入可执行文件,生成文件大,所以运行时无需再依赖库(.a
), 在执行的时候运行速度快,编译命令:gcc hello.c -o hello -static(需提前安装静态库)
静态链接的缺点很明显:
- 浪费空间:每个可执行程序中对所有需要的目标文件都要有一份副本,若是多个程序对同一个目标文件都有依赖,导致同一个目标文件都在内存存在多个副本
- 更新比较困难:每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。
(2)动态链接:编译时仅记录库依赖,运行时家住在系统中的动态库(后缀.so
),生成文件小,节省内存,编译命令:gcc hello.o -o hello
(在执行中更常用动态链接,所以默认是动态连接的)
- 可通过
ldd 可执行文件名
查看依赖的动态库
【注 】:
- Linux下,动态库是XXX.so,静态库是XXX.a
- Windows下,动态库是XXX.dll,静态库是XXX.lib
3.3 常用GCC选项:调试与优化
选项 | 功能描述 | 应用场景 |
---|---|---|
-g | 生成调试信息(供GDB使用) | 调试阶段:gcc test.c -o test -g |
-wall | 显示所有警示信息(避免潜在信息) | 开发阶段:gcc test.c -o test -wall |
-O0/O1/O2/O3 | 编译优先级别(0无优化,3最高优化) | 发布阶段:gcc test.c -o test -O3 |
四、Makefile:自动化构建的“工程管家”
当项目有多个源文件时,手动执行gcc命令效率极低。Makefile定义了编译规则,只需一个make
命令即可完成自动化构建,是大型项目的必备工具。
make
是一条命令,Makefile
是一个文件,两个搭配使用,完成项目的自动化构建
4.1 核心逻辑:依赖关系与依赖方法
Makefile的核心是:目标文件->依赖文件->编译命令,即:
目标文件:依赖文件1 依赖文件2 ...
编译命令 (必须以Tab开头)
基本使用操作:
示例代码:myfile.c
#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
Makefile文件:
//目标:myfile,依赖:myfile.c
myfile:myfile.c
gcc -o myfile myfile.c //编译命令
//伪目标:clean(清理生成文件,总是被执行,即每make一次,文件的属性时间就更新一次)
.PHONY:clean
clean:
rm -f myfile //清理命令:删除可执行文件
推导过程:
myfile:myfile.o
gcc myfile.o -o myfile
myfile.o:myfile.s
gcc -c myfile.s -o myfile.o
myfile.s:myfile.i
gcc -S myfile.i -o myfile.s
myfile.i:myfile.c
gcc -E myfile.c -o myfile.i
.PHONY:clean
clean:
rm -f *.i *.s *.o myfile
4.2 进阶用法:变量与函数
通过变量和函数简化Makefile(适配多文件项目),示例如下:
BIN=myfile
CC=gcc
SRC=$(wildcard *.c) //使用wildcard函数,获取当前所有的.c文件
OBJ=$(SRC:.c=.o) //将SRC的所有同名.c替换成为.o形成目标文件列表
LFLAGS=-o
FLAGS=-c
RM=rm -f
$(BIN):$(OBJ)
@$(CC) $(LFLAGS) $@ $^ //$@代表文件名;$^代表依赖文件列表
@echo "linking... $^ to $@"
%.o:%.c //%.c展开当前目录的所有.c;%.o同时展开所有同名的.o
@$(CC) $(FLAGS) $< //%<:对展开的依赖.c文件,一个一个交给gcc
@echo "compling ... $< to $@" //@:不回显命令
.PHNOY:clean
clean:
$(RM) $(OBJ) $(BIN)
五、实践:编写第一个Linux程序–进度条
掌握了前面的工具,那么来实战编写一个动态进度条,理解“行缓冲区”“回车换行”等Linux终端特性
5.1 补充知识:回车(\r)与换行(\n)
换行
:光标移动到下一行开头回车
:光标移动到当前行开头(不换行)动态进度条的核心
:用\r覆盖当前行内容,实现“实时更新”效果
5.2 核心原理:行缓冲区刷新
printf输出默认会缓存,需手动刷新缓冲区(fflush(stdout))才能实时显示,对比示例:
#include<stdio.h>
int main()
{
// 示例1:无 \n 且不刷新,3秒后才显示
printf("hello");
sleep(3);
// 示例2:加 fflush 实时显示
printf("hello");
fflush(stdout);
sleep(3);
return 0;
}
5.3进度条代码实现(含Makefile)
(1)文件结构
progress/
├── process.c # 进度条逻辑
├── process.h # 函数声明
├── main.c # 主函数(模拟下载)
└── Makefile # 自动化构建
(2)核心代码(process.c)
#include "progress.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// 进度条长度(100个字符对应100%)
#define BAR_LENGTH 100
// 基础版进度条:模拟从0%到100%的过程
void progress_basic() {
// 存储进度条字符
char bar[BAR_LENGTH + 1] = {0};
// 旋转光标字符集(实现动画效果)
const char *spin = "|/-\\";
int spin_index = 0;
// 从0%循环到100%
for (int i = 0; i <= 100; i++) {
// 填充进度条
memset(bar, '=', i);
// 计算旋转光标位置
spin_index = i % 4;
// 输出进度条:
// [%-100s] 左对齐,占100个字符宽度
// %d%% 显示百分比
// %c 显示旋转光标
// \r 回到行首
printf("[%-100s][%3d%%][%c]\r", bar, i, spin[spin_index]);
// 手动刷新缓冲区
fflush(stdout);
// 延迟50ms,控制进度条速度
usleep(50000);
}
// 进度完成后换行
printf("\n");
}
// 进阶版进度条:支持自定义任务量和样式
void progress_advanced(int total, int current, char style) {
// 边界检查
if (current < 0) current = 0;
if (current > total) current = total;
// 计算进度百分比
int percent = (int)((float)current / total * 100);
// 构建进度条
char bar[BAR_LENGTH + 1] = {0};
int filled = (int)((float)current / total * BAR_LENGTH);
memset(bar, style, filled);
// 输出进度信息
printf("Progress: [%-100s][%3d%%] %d/%d\r", bar, percent, current, total);
fflush(stdout);
// 完成时换行
if (current == total) {
printf("\n");
}
}
(3)头文件(process.h)
#ifndef PROGRESS_H
#define PROGRESS_H
// 基础版:固定样式进度条
void progress_basic();
// 进阶版:可自定义参数的进度条
// 参数:
// total: 总任务量
// current: 当前完成量
// style: 进度条填充字符
void progress_advanced(int total, int current, char style);
#endif
(4)测试主程序(main.c)
#include "progress.h"
#include <unistd.h>
int main() {
// 测试基础版进度条
printf("基础版进度条演示:\n");
progress_basic();
printf("\n");
// 测试进阶版进度条(模拟文件下载)
printf("进阶版进度条演示(模拟文件下载):\n");
int file_size = 1024; // 模拟文件大小1024KB
for (int downloaded = 0; downloaded <= file_size; downloaded += 32) {
progress_advanced(file_size, downloaded, '#');
usleep(100000); // 延迟100ms
}
return 0;
}
(5)Makefile
# 编译器
CC = gcc
# 编译选项:显示警告,生成调试信息
CFLAGS = -std=c99 -Wall -g
# 目标可执行文件
TARGET = progress_bar
# 源文件
SRCS = progress.c main.c
# 目标文件
OBJS = $(SRCS:.c=.o)
# 默认目标:编译程序
all: $(TARGET)
# 链接目标文件生成可执行文件
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
# 编译源文件生成目标文件
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# 清理编译生成的文件
clean:
rm -f $(OBJS) $(TARGET)
# 伪目标:避免与同名文件冲突
.PHONY: all clean
效果展示: