gcc 编译器
gcc(是一个编译器, 是GNU组织主要的编译工具)
gcc 是一个跨平台(跨软件平台 和 硬件平台)的编译器。
跨平台,代码可以通过不同的编译器编译到适合不同平台运行的程序。
在windows下开发了一款软件,只需要使用linux支持的编译器对代码进行编译,这个软件就可以在linux下运行。这个过程叫做交叉编译。
编译命令
gcc 编译在不指定生成的可执行文件的名字时,默认的名字是 a.out
-o 指定生成文件的名称
gcc hello.c -o hello 编译hello.c文件,生成可执行文件的名字叫hello,可执行文件的名字自己起名
或者 gcc -o hello hello.c
./ 运行程序
./hello 运行名字叫做hello的程序
编译hello.c 生成执行文件为hello
gcc hello.c -o hello
总共经历四步
预处理 编译 汇编 链接
预处理
只做预处理
gcc -E hello.c -o hello.i
#include <stdio.h> 将头文件 复制粘贴到include的位置
#define 使用宏值去替换宏名
编译
gcc -S hello.c -o hello.s
将c文件变成汇编文件,此时还没有生成机器码
编译到汇编的步骤,虽然不是二进制,但是语法和二进制一样
汇编
gcc -c hello.c
编译后自动生成hello.o文件
将c文件变成机器码文件(二进制文件)
此时生成的文件已经无法查看
但是不能运行,因为缺少一些必要的内容
链接
gcc -o hello.out hello.c
将代码中调用的函数,以及一些运行程序必要的内容组合在一起,形成可执行程序
链接之后的文件 要比.o的文件要大
总结
gcc 编译多个文件
在一个文件夹 且相互调用函数的可以一起编译
gcc main.c add.c fun.c
make (工程管理工具)
我们的一个项目中代码源文件是很多的,编译需要耗时,很耗时。我们需要工程管理工具提高我们的编译效率。
大原则就是已经编译过的文件如果没有修改就不再编译。
当前项目管理工具有很多,make只是其中一种,是linux下最常用的一种。
make : 工程管理工具。 make 命令。 编译项目
makefile : 是配置文件。 是 make 命令唯一读入的配置文件。 makefile文件里记载了我们需要编译的文件。
makefile 的名字是固定的。
Makefile或者写成makefile都可以。
当使用make命令时,make工具会找到makefile文件,根据文件中的描述对项目源文件进行编译。
文件编写规则
编译规则
目标名称:编译最终生成的产物。hello.out
依赖文件:编译目标需要的文件。
hello.out是目标,main.c add.c del.c是编译这个目标的依赖文件。依赖文件不一定是.c文件。
还可能是.o文件
gcc -o main main.c add.c del.c
编译规则:编译的指令。
单文件编译
准备文件 hello.c
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
创建makefile 名字必须是 makefile Makefile
vi makefile
hello.out:hello.c //hello.out 是目标文件 hello.c是产生目标文件的依赖文件
gcc hello.c -o hello.out //执行的命令
保存退出
执行,显示结果
make 执行命令
再次输入 make
提示 源代码没有修改,不会编译
添加清除和重新编译的功能
hello.out:hello.c
gcc hello.c -o hello.out
clean:
rm hello.out //删除
rebuild:clean hello.out //先删除 然后编译
使用 make clean 和 make rebuild 可以清空或重新编译
多文件处理
hello.out:main.o del.o add.o
gcc -o hello.out add.o main.o del.o
main.o:main.c
gcc -c main.c //全部编译成了.o文件 再编译成目标文件
当main.c 更改了 再编译时 只有main.o
重新生成了
add.o:add.c
gcc -c add.c
del.o:del.c
gcc -c del.c
简洁写法
makefile 文件和源文件在一起
所有的.c文件都生成对应的.o文件
gcc *.c -c 是编译当前路径下的所有的.c文件 所以我们应该给项目单独创建一个文件夹
hello.out:main.o add.o del.o
gcc -o hello.out add.o del.o main.o
.o:.c //将文件夹中所有.c文件生成.o文件
gcc -c *.c
clean:
rm *.o hello.out //删除所有的.o文件
rebbuild:clean hello.out
添加变量
预设变量
$@: 完整的目标名称
$^ : 依赖文件
$< : 每个.o文件的依赖文件
hello.out :main.o add.o del.o
gcc -o $@ $^ //$@ 完整的目标名称 $^ 依赖文件
.o:.c
gcc -o $< //$< 每个.o文件的依赖文件
clean:
rm *.o hello.out
rebuild: clean hello.out
将目标等参数用变量代替
EXEC=hello.out
OBJS=main.o add.o del.o
CC=gcc
$(EXEC):$(OBJS)
$(CC) -o $@ $^
.o:.c
$(CC) -c $<
clean:
rm $(OBJS) $(EXEC)
rebuild:clean $(EXEC)
总结
make工具提高编译效率,原理是编译过的文件如果没有进行修改就不再编译。
makefile是make工具的配置文件,文件里面定义编译规则。
make工具的使用命令是 make make clean make rebuild
能大概看懂,简单修改,知道是干啥的。
一小部分,入门。
gbd(调试器GUN debuger)
调试器有很多种,不一定是gdb。
什么是调试器?帮助我们找到代码中的逻辑问题,编译通过了,但是不好使。
它能够找到我们代码中存在的逻辑问题吗?不是调试器找问题,而是我们自己找问题,调试器在找问题的过程中仅仅是辅助功能。
找逻辑问题的思路:
1 预判问题可能出现在哪里?
2 在可能出现问题的地方,查看关键变量的值是否符合预期。
gdb非常好,只是没有可视化界面的gdb使用太复杂了。
gdb使用
编译时:gcc -g demo.c -o demo.out // 加入了调试功能
进入调试:gdb demo.out
gdb 模式中的一些命令:
l : 列出代码(默认10行)(小写L)
break n : 设置断点 breakpoint 断点就是预测可能出现问题的地方,调试器会让程序在断点停止,断点停止的哪一 行代码是没执行的
r : run 运行程序
n : next 单步运行 从断点处开始只执行一行代码。
p : print 打印各类变量等信息。
c : continue 继续运行
q : quit 退出 gdb 模式
info break: 查看断点信息
delete 断点号: 删除断点g
调试的核心目的就是让程序停止在我怀疑有问题的地方,然后查看该处的变量的值。
步骤:
1. 编写demo.c 程序
2. 编译时 加入调试功能
gcc -g demo.c -o demo.out
3. 使用gdb运行该目标文件
gdb demo.out
4. 输入r 让程序运行起来
5. 输入r 程序全部执行完毕
6.break 9 在程序的第9行 设置了一个断点
7.info b 显示断点的个数
8. q 退出程序
delete 1 删除了编号为1的断点
p i 打印当前i的值
n 从断点处执行一行
c 执行到下一个断点的位置
clear n 删除n行的断点
l 列出代码(默认10行)