【Linux】Linux 基础开发工具(2):gcc 、Makefile 与进度条程序实现
目录
在 Linux 环境下进行 C/C++ 开发,掌握编译器工具、自动化构建工具以及基础程序编写能力是入门的关键。本文将从 gcc/g++ 编译器的编译流程、Makefile 的编写逻辑,到实现第一个 Linux 特色程序 —— 进度条,全方位拆解开发过程中的核心知识点。
一、gcc/g++ 编译器:代码到可执行文件的蜕变
gcc(GNU C Compiler)和 g++(GNU C++ Compiler)是 Linux 下最常用的 C/C++ 编译器,其核心工作是将源代码转化为可执行程序,整个过程分为预处理、编译、汇编、链接四个阶段。
1. 预处理:代码的 “初步加工”
预处理阶段主要完成宏替换、头文件展开、去注释、条件编译等操作,该阶段不会进行语法检查。
- 核心指令:
gcc -E 源文件 -o 预处理文件.i(C 语言)、g++ -E 源文件 -o 预处理文件.i(C++ 语言) - 示例:对
test.c进行预处理,生成test.i文件
预处理后,代码中的gcc -E test.c -o test.i#include头文件会被完整展开,#define宏会被直接替换,注释则会被全部清除。
2. 编译:生成汇编指令
编译阶段会对预处理后的代码进行语法、语义分析,在确认无语法错误后,将其转化为汇编语言代码。
- 核心指令:
gcc -S 预处理文件.i -o 汇编文件.s - 示例:将预处理后的
test.i转化为汇编文件test.s
此时生成的gcc -S test.i -o test.s.s文件为汇编代码,可直接被汇编器处理。
3. 汇编:转化为机器码
汇编阶段的任务是将汇编代码转化为机器可识别的二进制目标文件(.o文件),该文件为可重定位目标文件,无法直接执行。
- 核心指令:
gcc -c 汇编文件.s -o 目标文件.o - 示例:将
test.s转化为二进制目标文件test.ogcc -c test.s -o test.o
4. 链接:生成可执行程序
链接阶段是将多个目标文件以及系统库文件整合,生成最终的可执行程序。Linux 下链接分为静态链接和动态链接:
- 动态链接(默认):程序运行时才加载依赖的动态库(
.so文件),生成的可执行程序体积小,但运行时依赖系统动态库。 - 静态链接:编译时将依赖的静态库(
.a文件)代码直接拷贝到可执行程序中,程序可独立运行,但体积较大。 - 核心指令:
- 动态链接:
gcc 目标文件.o -o 可执行程序名 - 静态链接:
gcc 目标文件.o -o 可执行程序名 -static(需提前安装静态库,如 CentOS 下yum install glibc-static libstdc++-static -y)
- 动态链接:
- 示例:将
test.o链接为可执行程序testgcc test.o -o test
5. 调试模式编译
默认情况下 gcc/g++ 生成的是 release 模式程序,无法调试。若需使用 gdb 调试,需添加-g参数生成 debug 模式程序:
gcc test.c -o test -g
二、Makefile:自动化构建的 “利器”
当项目中存在多个源文件时,手动执行编译指令会变得繁琐且易出错。Makefile 通过定义依赖关系和编译规则,实现项目的自动化编译与清理,极大提升开发效率。
1. Makefile 核心原理
Makefile 的核心是 “依赖关系” 和 “依赖方法”:
- 依赖关系:目标文件依赖哪些源文件(如可执行程序依赖目标文件,目标文件依赖源文件)。
- 依赖方法:通过什么指令生成目标文件。
- 此外,可通过
.PHONY声明伪目标(如clean),伪目标的特性是 “总是会被执行”,不受文件时间戳影响。
2. 基础 Makefile 编写
以单文件项目test.c为例,编写 Makefile:
makefile
# 定义可执行程序名
test:test.o
gcc test.o -o test
# 目标文件依赖源文件
test.o:test.c
gcc -c test.c -o test.o
# 声明clean为伪目标
.PHONY:clean
# 清理编译产物
clean:
rm -f test.o test
执行make命令即可自动编译生成test程序,执行make clean可清理编译产物。
3. 进阶 Makefile:变量与通配符
对于多文件项目,可通过变量和通配符简化 Makefile 编写,提升通用性:
makefile
# 定义变量:编译器、源文件、目标文件、可执行程序名
CC=gcc
SRC=$(wildcard *.c) # 获取当前目录所有.c文件
OBJ=$(SRC:.c=.o) # 将所有.c文件替换为.o文件
BIN=app
# 生成可执行程序
$(BIN):$(OBJ)
$(CC) -o $@ $^ # $@代表目标文件名,$^代表所有依赖文件
# 生成目标文件
%.o:%.c
$(CC) -c $< -o $@ # $<代表依赖列表中的第一个文件
# 清理规则
.PHONY:clean
clean:
rm -f $(OBJ) $(BIN)
此 Makefile 可适配任意多.c文件的项目,无需逐个修改编译指令。
三、第一个 Linux 程序:实现动态进度条
进度条是 Linux 下典型的交互式程序,其核心是利用行缓冲区和光标控制实现动态刷新效果,下面分步实现两种版本的进度条。
1. 核心知识点铺垫
- 回车与换行:
\n是换行(光标移到下一行开头),\r是回车(光标回到当前行开头,不换行),进度条的动态刷新依赖\r。 - 行缓冲区:标准输出默认是行缓冲,只有遇到
\n或手动刷新(fflush(stdout))时,内容才会输出到终端。 - usleep 函数:用于控制进度条刷新速度(单位为微秒,1 秒 = 1000000 微秒)。
2. 版本 1:基础进度条
实现一个从 0% 到 100% 的基础进度条,包含进度条样式、百分比和动态旋转光标:
(1)头文件process.h
#pragma once
#include <stdio.h>
void process_v1();
(2)源文件process.c
#include "process.h"
#include <string.h>
#include <unistd.h>
#define NUM 101
#define STYLE '='
void process_v1() {
char buffer[NUM];
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区
const char *lable = "|/-\\"; // 旋转光标字符
int len = strlen(lable);
int cnt = 0;
while (cnt <= 100) {
// 输出进度条:左对齐100字符、百分比、旋转光标,回车刷新
printf("[%-100s][%d%%][%c]\r", buffer, cnt, lable[cnt % len]);
fflush(stdout); // 手动刷新缓冲区
buffer[cnt] = STYLE; // 填充进度条
cnt++;
usleep(50000); // 控制刷新速度
}
printf("\n"); // 进度完成后换行
}
(3)主程序main.c
#include "process.h"
int main() {
process_v1();
return 0;
}
(4)编写 Makefile
makefile
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
BIN=processbar
$(BIN):$(OBJ)
gcc -o $@ $^
%.o:%.c
gcc -c $< -o $@
.PHONY:clean
clean:
rm -f $(OBJ) $(BIN)
执行make生成processbar,运行后即可看到动态进度条效果。

3. 版本 2:适配业务场景的进度条
版本 1 为固定进度,版本 2 实现可适配下载、传输等业务场景的进度条,根据 “总任务量” 和 “已完成量” 动态更新进度:
(1)扩展头文件process.h
#pragma once
#include <stdio.h>
void process_v1();
void FlushProcess(double total, double current);
(2)扩展源文件process.c
#include "process.h"
#include <string.h>
#include <unistd.h>
#define NUM 101
#define STYLE '='
void process_v1() {
// 版本1代码,此处省略
}
void FlushProcess(double total, double current) {
char buffer[NUM];
memset(buffer, 0, sizeof(buffer));
const char *lable = "|/-\\";
int len = strlen(lable);
static int cnt = 0; // 静态变量保存光标状态
// 根据已完成量计算进度百分比
int num = (int)(current * 100 / total);
for (int i = 0; i < num; i++) {
buffer[i] = STYLE;
}
double rate = current / total;
cnt %= len;
printf("[%-100s][%.1f%%][%c]\r", buffer, rate * 100, lable[cnt]);
cnt++;
fflush(stdout);
}
(3)编写业务主程序main.c
#include "process.h"
#include <unistd.h>
double total = 1024.0; // 总任务量(示例为1024MB)
double speed = 1.0; // 每次完成量
void DownLoad() {
double current = 0;
while (current <= total) {
FlushProcess(total, current);
usleep(3000); // 模拟下载耗时
current += speed;
}
printf("\ndownload %.2lfMB Done\n", total);
}
int main() {
// 模拟多次下载
for (int i = 0; i < 3; i++) {
DownLoad();
}
return 0;
}
运行程序后,可看到模拟下载的动态进度条,每次下载完成后会提示下载成功。

四、总结
本文从 gcc/g++ 的编译流程出发,讲解了从源代码到可执行程序的完整转化过程;通过 Makefile 实现了项目的自动化构建;最后基于 Linux 终端特性,完成了基础版和业务适配版的进度条程序。这些知识点是 Linux C/C++ 开发的基础,掌握后可应对大部分小型项目的开发与构建需求。后续可进一步学习 gdb 调试、git 版本控制等技能,完善 Linux 开发技术栈。

更多推荐
所有评论(0)