提高效率,解决一切问题:Linux 开发者的秘密武器
接上篇 ->【Linux篇】让开发事半功倍:Linux 开发工具的实战指南(上篇):本篇博客本文介绍了在 Linux 环境中,如何使用软件包管理器、Vim 编辑器、GCC 编译器以及动态与静态库的相关命令和操作。首先,通过软件包管理器(如APT)进行软件包的安装、卸载和更新,帮助简化软件管理过程。然后,详细讲解了 Vim 编辑器的三种模式和基本操作,提升编辑效率。接着,解释了 GCC 编译器的编译流程、常用选项和动态、静态链接的区别。最后,介绍了如何使用 ldd 命令查看可执行文件或库文件的依赖关系,帮助开发人员有效管理和调试系统库。请跟随小编的步伐,一起进入学习之旅。
一. 自动化构建 - make/makefile
1.1 make的背景与历史
- 起源:
make 最早由 Stuart Feldman 在1976年开发,目的是简化编译和链接过程。它最初是为了解决在大型项目中重复构建的问题,通过自动化构建流程来减少开发人员的工作量。
- 功能:
make 通过检查文件的时间戳(如源文件和目标文件),只重新构建那些需要更新的部分。这样就避免了不必要的重新编译,节省了大量时间,尤其是在大型项目中。
它使用 规则(rules) 来指定哪些文件需要被编译或构建,以及如何编译这些文件。一个典型的规则由以下几部分组成:
- 目标文件(target):最终输出的文件(比如一个可执行文件)。
- 依赖文件(dependencies):构建目标所依赖的源文件或其他中间文件。
- 命令(commands):构建目标所需要执行的操作,如编译命令。
Makefile:
Makefile 是 make 的配置文件,包含了一系列规则和命令。它基本上是告诉 make 如何构建或更新一个项目。Makefile 通常包括:
- 目标:需要生成的文件。
- 依赖项:目标所依赖的文件。
- 构建命令:生成目标所需要执行的命令。
1.2 make/makefile 基本使用
示例代码:
#include <stdio.h>
int main()
{
printf(“hello Makefile!\n”);
return 0;
}
Makefile文件:

mytest:mytest.c
gcc -o mytest mytest.c
.PHONY:clean
clean:
rm -f mytest
核心思想:
- 依赖关系:mytest的形成依赖于mytest.c
- 依赖方法: gcc -o mytest mytestc ,就是上述的依赖关系
- 项目清理:make会自下而上扫描,形成一个目标文件,除非下面的目标文件与第一个目标文件有关联,上述clean的目标文件,设置为伪目标,用.PHONY修饰,它的特性总是被执行。简单点说就是可以重复执行,反之没有被修饰会报错: make: ‘mytest’ is up to date.
问题1:为什么make后不能再编译
make
gcc test.c -o mytest
wch_1@hcss-ecs-2ce4:~/114/code/lesson2$ ll
total 28
-rw-rw-r-- 1 wch_1 wch_1 73 Mar 27 21:02 Makefile
-rwxrwxr-x 1 wch_1 wch_1 16696 Mar 27 21:02 mytest
-rw-rw-r-- 1 wch_1 wch_1 237 Mar 27 20:50 test.c
wch_1@hcss-ecs-2ce4:~/114/code/lesson2$ make
make: ‘mytest’ is up to date.
- 编译器如何知道源文件需不需要重新编译
通过文件的属性创建与更改时间,发现不同就编译,反之不编译。
主要是为了提高编译效率!!!
结论:.PHONY:让make忽略源⽂件和可执⾏⽬标⽂件的M时间对⽐
1.2.1 推导过程
在底行模式下,输入make命令后,make大致工作流程如下:
- 读取 Makefile
make 读取当前目录中的 Makefile(或指定的其他文件)。解析 Makefile 中的规则和命令。
- 检查目标文件
如果没有指定目标,默认执行 Makefile 中的第一个目标,通常是 all。
如果指定了目标,如 make ,make 会寻找与该目标匹配的规则。
- 依赖关系解析
对每个目标文件,make 会检查其依赖项。
比较目标文件的时间戳与依赖项的时间戳,确定是否需要重新构建。
如果目标文件的时间戳较旧,表示目标需要更新。
如果目标文件是最新的,且其依赖文件没有变化,make 会跳过该目标。
- 执行构建命令
如果目标需要更新,make 会执行规则中的命令。命令通常是编译或链接操作。
每个命令在单独的 shell 环境中执行。
- 递归构建
make 会递归检查目标的依赖项。如果某个依赖需要更新,make 会继续处理其依赖项并执行相应命令。
例如,若目标依赖 .o 文件,则 make 会先编译这些 .o 文件,再链接生成最终目标。
- 构建完成
当所有目标文件和依赖项都构建完成时,最终目标文件(如可执行文件)会生成。
- 清理操作
若 Makefile 中定义了 clean 目标,执行 make clean 可以删除所有生成的中间文件(如 .o 文件和可执行文件)以便重新构建。
1.3 适度扩展语法
BIN=proc.exe # 定义变量
CC=gcc
#SRC=KaTeX parse error: Expected 'EOF', got '#' at position 16: (shell ls *.c) #̲ 采⽤shell命令⾏⽅式,获…(wildcard *.c) # 或者使⽤ wildcard 函数,获取当前所有.c⽂件名
OBJ=$(SRC:.c=.o) # 将SRC的所有同名.c 替换 成为.o 形成⽬标⽂件列表
LFLAGS=-o # 链接选项
FLAGS=-c # 编译选项
RM=rm -f # 引⼊命令
( B I N ) : (BIN): (BIN):(OBJ)
@$(CC) $(LFLAGS) $@ $^ # $@:代表⽬标⽂件名。 $^: 代表依赖⽂件列表
@echo "linking … $^ to @ " 名 . o @ @" %.o:%.c # %.c 展开当前⽬录下所有的.c。 %.o: 同时展开同 名.o @ @"名.o@(CC) $(FLAGS) $< # %<: 对展开的依赖.c⽂件,⼀个⼀个的交给gcc。
@echo “compling … $< to $@” # @:不回显命令
.PHONY:clean
clean:
$(RM) $(OBJ) $(BIN) # $(RM): 替换,⽤变量内容替换它
.PHONY:test
test:
@echo $(SRC)
@echo $(OBJ)
二. 回车与换行概念
实现本程序,需要额外大致了解一下下面的概念
2.1 回车与换行
回车 (\r):
- 回车将光标移动到当前行的开头。
- 它不会换到下一行,只是将光标移到当前行的最左侧。
换行 (\n):
- 换行将光标移动到下一行的开头。
- 它通常用来在文本中创建新的行。
示例:
- 回车的效果:
Hello, world!\rGoodbye
输出结果:
Goodbye, world!
在这个例子中,Hello, world! 被回车符号(\r)覆盖,光标回到行首,显示了 Goodbye。
- 换行的效果:
Hello, world!\nGoodbye
输出结果:
Hello, world!
Goodbye
这里,\n 创建了一个新的行,Goodbye 出现在下一行。
- 回车与换行组合的效果(Windows):
Hello, world!\r\nGoodbye
输出结果:
Goodbye
world!
这会把光标移到行首并换行,Goodbye 会出现在新的一行。
总结:
回车 (\r):光标移到当前行的开头。
换行 (\n):光标移到下一行的开头。
2.2 行缓冲区
2.2.1 什么是行缓冲区
行缓冲区(Line Buffering)是指在处理输入/输出时,数据以一行一行的方式进行缓冲。当缓冲区中积累了完整的一行数据时,才会将数据从缓冲区中处理或输出。
- 具体定义:
行缓冲区的工作方式是,每当输入或输出到达换行符(如 \n)时,系统才会将该行数据传递给程序或设备。这种方式通常在处理文本输入输出时比较常见,尤其是与交互式输入输出操作(如命令行输入)相关。
行缓冲区的特点:
1 -> 输入缓冲区:当用户输入一行时,数据会先存储在缓冲区中,直到用户按下回车键(表示换行符 \n),系统才会将该行输入传递给程序进行处理。
2 -> 输出缓冲区:程序将数据写入缓冲区,直到遇到换行符(或缓冲区满)时,数据才会从缓冲区写到屏幕或文件。
行缓冲区的特点:
1 ->输入缓冲区:当用户输入一行时,数据会先存储在缓冲区中,直到用户按下回车键(表示换行符 \n),系统才会将该行输入传递给程序进行处理。
2 -> 输出缓冲区:程序将数据写入缓冲区,直到遇到换行符(或缓冲区满)时,数据才会从缓冲区写到屏幕或文件。
行缓冲区的优势:
<1> 提高效率:行缓冲区通常能减少每个字符的输入/输出操作次数,从而提高效率。程序可以一次性读取或写入整行数据。
<2>交互性:对交互式程序来说,行缓冲区能更好地处理逐行输入输出,使用户体验更加流畅。
行缓冲区的缺点:
延迟:如果程序需要更快的输入输出反应,行缓冲可能导致延迟,特别是在没有换行符时。
其他类型的缓冲:
字符缓冲(Character Buffering):每次输入一个字符就立即传递。
全缓冲(Full Buffering):只有缓冲区满时,才进行数据的读取或输出。
2.3 实现倒计时程序
#include <stdio.h>
#include <unistd.h>
int main()
{
int i = 10;
while(i >= 0)
{
printf("%-2d\r", i); // \n
fflush(stdout);
i--;
sleep(1);
}
printf("\n");
return 0;
}
三. 总结
本文介绍了 Linux 开发中的一些关键概念和工具,重点关注自动化构建、回车与换行概念以及行缓冲区。首先,make 工具帮助简化编译和链接过程,使用 Makefile 定义构建规则,避免不必要的重新编译,从而提高开发效率。回车与换行分别控制光标在当前行与下一行的位置。行缓冲区则通过在输入输出达到换行符时才传递数据,优化了效率并提升了交互性。通过理解这些工具和概念,开发者可以在 Linux 环境中更高效地进行开发和调试。
路虽远,行则将至;事虽难,做则必成
亲爱的读者们,下一篇文章再会!!! \color{Red}亲爱的读者们,下一篇文章再会!!! 亲爱的读者们,下一篇文章再会!!!