目录
一、GCC编译
1.直接编译
2.分步编译
预处理:
编译:
汇编:
链接:
3.多文件编译
4.G++
二、Make
1.概述
2.使用步骤
3.makefile创建规则
3.1一个基本规则
3.2两个常用函数
4.示例文件
三、GDB
示例:
基本指令:
一、GCC编译
我们都知道想要实现一个程序首先需要写好代码让其能运行起来,那么写出来的.c文件是如何被编译出来的呢?
1.直接编译
首先将程序直接编译为可执行文件可以通过Linux中的GCC编译器。
GCC(是一套广泛使用的编译器工具集,由 GNU 项目开发和维护。它支持多种编程语言,包括 C、C++、Objective-C、Fortran、Go 和其他语言。GCC 提供了编译、链接和优化等功能,可以将源代码转换为可执行文件或库。
gcc name.c:已经写好.c文件想生成执行文件,可直接用指令实现,会生成一个name.out文件,
输入指令"./name.out" 文件就会执行
2.分步编译
那么GCC是如何实现这个原理的呢?
预处理:
C 编译器对各种预处理命令进行处理,包括头文件包含、宏定义的扩展、条件编译的选择等;
gcc -E name.c -o name.i:对c程序文件进行预处理得到.i预处理文件
编译:
将预处理得到的源代码文件进行语法词法分析,“翻译转换”得到机器语言的汇编文件;
gcc -S name.i:通过编译得到.s 汇编文件 (如果是c文件,会进行预处理+编译)
汇编:
将汇编代码翻译成了机器码,但是还不可以运行;
gcc -c name.s:通过汇编得到 hello.o 机器码文件 (如果是c文件,会进行预处理+编译+汇编)
链接:
处理可重定位文件,把各种符号引用转换成为可执行文件中的合适信息,通常是虚拟地址;
gcc name.o -o name:通过链接得到 a.out 可执行文件 (如果是c文件,进行完整编译步骤)
3.多文件编译
首先可以创建两个文件,一个是a.c文件
#include<stdio.h>
int main()
{
printf("hello,world!\n");
test();
return 0;
}
再创建一个文件用来存储外部函数
#include<stdio.h>
void test()
{
printf("test\n");
}
如果文件有更新,那么两个文件都需要重新编译
4.G++
g++:这是 GCC 中的 C++ 编译器。它将 C++ 源代码文件(通常以 .cpp 或 .cc 扩展名)作为输入,并生成可执行文件。与 gcc 相比,g++ 在编译 C++ 代码时会自动链接 C++ 的标准库。可以理解为一个是对C语言的编译,一个是对C++的编译
二、Make
1.概述
make 是一个命令工具,它解释Makefile 中的指令。在Makefile 文件中述了整个工程所有文件的编译顺序、编译规则。
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若千个目录中,Makefile
定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚本一样,也可以执行操作系统的命令
如果是单独文件编译可以直接用make name就可以生成执行文件。
2.使用步骤
- 创建Makefile:在项目根目录下创建一个名为Makefile的文本文件。Makefile中包含了构建项目所需的规则和命令。
- 定义规则:Makefile中的规则由目标文件、依赖文件和构建命令组成。目标文件是需要构建的文件,依赖文件是构建目标文件所需的文件,构建命令是用于生成目标文件的命令。
- 编写构建命令:在Makefile中为每个规则编写构建命令。构建命令可以是任意可执行的命令或脚本,用于生成目标文件。
- 运行Make:在终端或命令提示符中,进入到项目根目录,并执行make命令。Make工具会读取Makefile,并根据规则和依赖关系自动构建项目。
3.makefile创建规则
3.1一个基本规则
目标:依赖条件(可以设置多个依赖条件)
命令
target: dependencies
command1
command2
...
3.2两个常用函数
$(wildcard pattern):
这个函数用于匹配指定模式的文件,并返回符合模式的文件名列表。模式可以包含通配符,如*和?。该函数将返回一个字符串,其中包含匹配的文件名列表,每个文件名之间用空格分隔。例:
src = $(wildcard *.c)
在这个示例中,$(wildcard *.c)会返回当前目录中所有以.c为扩展名的文件,将其赋值给变量src。
$(patsubst 参数1,参数2,参数3):
这个函数用于在给定的文本中,将符合指定模式的部分替换为指定的内容。模式可以包含通配符,如%,用于匹配任意字符。例:
objects := $(patsubst %.c, %.o, $(src))
在这个示例中,假设src变量包含一些.c文件的文件名列表。使用$(patsubst %.c, %.o, $(src))将替换文件名的扩展名,将.c替换为.o,并将结果赋值给变量objects。
3.3三个自动变量
$@
:
在规则的命令中,表示规则中的目标。例:
target: dependency
gcc -o $@ $<
在这个示例中,$@将被替换为目标文件的名称。
$^
:
在规则的命令中,表示所有依赖条件。例:
target: dependency1 dependency2
gcc -o $@ $^
在这个示例中,$^将被替换为所有依赖文件的列表,即dependency1 dependency2。
$<
: 在规则的命令中,表示第一个依赖条件。例:
target: dependency
gcc -o $@ $<
在这个示例中,$<
将被替换为第一个依赖文件的名称。
4.示例文件
# 编译器设置
CC := gcc
CFLAGS := -Wall -Wextra -g
# 目标文件
TARGET := program
# 源文件列表
SRCS := main.c utils.c
# 生成目标
$(TARGET): $(SRCS)
$(CC) $(CFLAGS) -o $@ $^
# 清理生成的文件
clean:
rm -f $(TARGET)
.PHONY: clean
- CC:定义编译器的变量,这里使用gcc作为默认的编译器。
- CFLAGS:定义编译选项的变量,这里设置了一些常用的编译选项,如-Wall和-Wextra用于开启更多的警告信息,-g用于生成调试信息。
- TARGET:定义目标文件的变量,这里设置为program。
- SRCS:定义源文件的变量,这里列出了main.c和utils.c。
- $(TARGET): $(SRCS):这是一个生成目标的规则,指定了$(SRCS)作为依赖文件,当依赖文件发生变化时,执行后续的命令将源文件编译链接成目标文件。
- $(CC) $(CFLAGS) -o $@ $^:这是生成目标的命令,$(CC)和$(CFLAGS)分别代表编译器和编译选项,$@代表目标文件名,$^代表所有的依赖文件。
- clean::这是一个清理目标文件的规则,指定了clean作为伪目标。
- rm -f $(TARGET):这是清理目标文件的命令,使用rm -f命令删除目标文件。
- .PHONY: clean:这个声明用于指示clean是一个伪目标,而不是一个实际的文件。
关于Makefile需要多加练习,对于多文件编译是很有用的。Linux环境下的程序员如果不会使用GNU make来构建和管理自己的工程,应该不能算是个合格的专业程序员,至少不能称得上是 Unix 程序员。
三、GDB
示例:
使用gcc编译时加上g选项可以得到调试表
#include<stdio.h>
void my_print(int i)
{
printf("打印第%d次\n",i);
}
int main(){
int i = 0;
while(i < 10) {
i++;
my_print(i);
}
return 0;
}
例如:
- gcc -g main.c
- gdb ./a.out
基本指令:
- list/l或list[数字]: 列出源码。加数字,在指定行号位置附近显示
- break/b 或 break [number]: b 20 在20行位置设置断点
- d/delete:断点编号 删除断点
- run/r: 运行程序
- start: 运行程序(到主函数停止)
- n/next:下一条指令 (会越过函数)
- s/step:下一条指令 (会进入函数)
- p/print[变量名]:查看变量的值
- continue/c:继续执行断点后续指令
- finish:结束当前函数调用
- q/quit:退出 gdb 当前调试
上面只是GDB的基本用法,如果想更深入的学习需要自己查阅一下资料。