GCC编译
在Linux系统中,对于单个或者少量文件项目我们经常使用GCC编译,GCC 编译代码主要有两种方式:一次编译和分步编译。
GCC常用编译选项
-E | 仅预处理,不编译 | gcc -E main.c -o main.i |
-S | 编译到汇编语言,不汇编 | gcc -S main.c -o main.s |
-c | 编译和汇编,不链接 | gcc -c main.c -o main.o |
-o | 指定输出文件名称 | gcc main.c -o program |
-Wall | 开启常见编译警告 | gcc -Wall main.c |
-g | 生成调试信息(用于 GDB) | gcc -g main.c -o debug |
-O2 | 开启二级优化(提高性能) | gcc -O2 main.c |
-I 路径 | 指定头文件搜索路径 | gcc -I ./include main.c |
-l 库名 | 链接指定库文件 | gcc main.c -lm |
-L 路径 | 指定库文件搜索路径 | gcc main.c -L ./lib -lmylib |
1.一次编译
基本命令
gcc [选项] 源文件.c -o 可执行文件
# 编译单个 C 文件
gcc main.c -o program
# 编译多个 C 文件
gcc main.c utils.c math.c -o program
# 添加编译选项(如优化、调试信息)
gcc -Wall -O2 -g main.c utils.c -o program
使用过程:
2.分步编译
1.预处理:处理 #include、#define 等指令,生成 .i 文件
gcc -E main.c -o main.i
2.编译:将 .i 文件转换为汇编代码 .s
gcc -S main.i -o main.s
3.汇编:将汇编代码 .s 转换为目标文件 .o
gcc -c main.s -o main.o
4.链接:将多个 .o 文件和库文件合并为可执行文件
gcc main.o utils.o -o program
使用过程:
make工具和makefile文件
介绍
为什么要使用makefile:
自动化编译:避免手动输入复杂的编译命令尤其是对于大型项目有超多.c文件。
增量编译:只重新编译修改过的文件,提高效率。
跨平台兼容:在不同系统上保持一致的编译规则。
make 工具
简介:工程管理器,顾名思义,就是管理较多文件
功能:根据文件依赖关系自动编译程序,避免重复编译未修改的文件。
核心逻辑:
检查目标文件是否存在。
检查依赖文件是否比目标文件新。
若依赖更新或目标不存在,则执行命令重新生成目标。
安装make
sudo apt install make
Makefile 文件
Makefile是一个定义了关于项目编译和链接等规则的文件,它在Linux系统下的C/C++项目编译中起到了自动化编译的作用。Makefile文件中包含了编译器和链接器的参数选项,并且描述了所有源文件之间的关系,如源代码文件需要的特定的包含文件,可执行文件要求包含的目标文件模块及库等。创建程序(make程序)首先读取makefile文件,然后激活编译器、汇编器、资源编译器和链接器以便产生最后的输出,通常是可执行文件。
编写makefile
Makefile 基本原理
1. 文件依赖关系
Makefile 的核心是定义文件间的依赖关系,并基于文件修改时间决定哪些部分需要重新编译:
目标:通常是要生成的文件(如可执行文件、库文件)或操作名称(如 clean)。
依赖:生成目标所需的文件或其他目标。
规则:定义如何从依赖生成目标的命令。
2. 工作流程
当执行 make 命令时:
读取 Makefile:默认读取当前目录下的 Makefile 或 makefile 文件。
确定目标:如果未指定目标,默认使用第一个目标(通常是 all)。
检查依赖:递归检查目标的所有依赖是否需要更新。
如果依赖文件不存在或已过期(修改时间比目标新),则执行对应的命令重新生成。
如果依赖是其他目标,会先处理该目标。
执行命令:仅当依赖更新或目标不存在时执行命令。
基本规则
目标: 依赖1 依赖2 ...
<Tab>命令1
<Tab>命令2
app: main.o utils.o
gcc main.o utils.o -o app
使用过程:
1.一次编译
2.分步编译
删除文件
此时我们要删除.i .s .o和add文件,我们可以用rm指令一个一个删除,我们也可以在makefile里再加一个目标文件
此时在shell命令行执行make clean指令
即可删除对应文件
但是如果当前目录下的文件里有名字为clean的文件则不能使用
此时我们需要使用PHONY目标
PHONY的作用:
1.避免和同名文件冲突
2.改善性能
变量的创建和使用
创建变量的目的:
1.提升代码可维护性
借助变量能够避免在 Makefile 里重复书写相同的内容。要是后续需要对某个值进行修改,仅需改动变量的定义之处即可。
2.实现代码复用
可以把常用的值或者命令定义成变量,在多个地方重复使用。
3.便于条件编译
通过变量可以灵活控制编译过程,比如针对不同的环境或者目标进行编译。
1.预定义变量
Makefile 内置了一些系统变量:
CC:默认的 C 编译器(通常是cc)
CXX:默认的 C++ 编译器(通常是g++)
RM:默认的删除命令,只能删除文件不能删除目录(通常是rm -f)
CFLAGS C 编译器的选项(如-Wall -O2)
CXXFLAGS C++ 编译器的选项
CPPFLAGS C/C++ 预处理器的选项(如-I/include)
FFLAGS Fortran 编译器的选项
LDFLAGS 链接器的选项(如-L/lib)
LIBS 链接时需要的库(如-lm -lpthread)
ARFLAGS 创建静态库时的选项(如rcs)
此时我们可用cc编译器来生成add和add.o文件,用RM来删除文件
用变量代替参数-c
2.自定义变量
自己定义的变量
此时cc不是cc编译器,还是gcc编译器
3.自动变量
几个常见的自动变量
$* 不包含扩展名的目标文件名称
$+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包
含重复的依赖文件
$< 第一个依赖文件的名称
$? 所有时间戳比目标文件晚的的依赖文件,并以空格分开
$@ 目标文件的完整名称
$^ 所有不重复的目标依赖文件,以空格分开
$% 如果目标是归档成员,则该变量表示目标的归档成员名称
此时我们创建三个文件
我们怎么把这三个.c文件编译生成一个可执行文件呢
如果不用自动变量的话:
使用自动变量:
至此可以应付一些简单的项目了,makefile高级使用的笔记内容后面再补充吧~