Linux学习(二):makefile
gcc
gcc 是用来编译代码的编译器 编译完后有一些常见的输出文件: .a 静态库(文档) .c 需要预处理的C语言源代码 .h C语言源代码的头文件 .i 经过预处理后的C语言源代码 .o 目标文件(经过汇编产生) .s 经过编译后产生的汇编语言代码
gcc编译过程:
首先对.c和.h文件进行预处理操作,生成.i文件,然后将其编译产生汇编语言代码.s,再对.s文件进行处理,生成目标文件.o,.o文件就是计算机能看懂,且可以执行的机器语言。
先创建文件写一个简单代码
#include <stdio.h>
int main()
{
printf("HelloWorld");
}
预处理
预处理指令:
gcc -E helloWorld.c -o helloWorld.i
执行后多出一个.i文件 再通过ls -l指令查看文件详细内容,可以看到文件的大小,在经过预处理后由59B变为16335B,翻了好几倍 变大的原因:我们之前引用了头文件stdio.h,在执行预处理后,等同于将.h中的所有内容拷贝到了该文件,所以文件大小变大。
通过less helloWorld.i 可以查看该文件详细内容:
产生汇编
这里主要使用 -s 命令,可以看见下图能直接对.c 和 .i 文件进行操作,这是因为-s中已经集成了预处理操作
生成目标文件
同理,-o同样集成了预处理和转为汇编的操作,因此可以直接对.c文件进行操作: 我们再看文件的详细信息: 这里可以看到.o 文件要小于.s和.i文件,这是因为.o文件只是一个可执行文件,但是它不具备可执行的能力,.o文件是将汇编文件转为的机器码,也就是二进制文件。
执行文件
gcc可以直接读懂二进制.o文件,所以可以直接使用这种指令生成可执行文件:gcc helloWorld.o -o myHello
再看看myHello 的文件大小,再次变大,前面我们提到.o文件是可执行文件,但是不具备可执行能力。为了让它具备可执行能力,gcc需要在.o文件原来的基础上再添加一些配置,让它具备可执行文件。
题外话
可以看到,我们可以直接编译.c 生成可执行文件,那么,我们之前学的那些生成.i,.s,.o的过程有什么用呢。虽然现在的指令都集成好了,可以直接用,但是我们还是需要对这些过程做一些了解,因为c语言不同于java,Java是解释型语言,而c则是编译型语言,例如程序有时候出错可能不是错在.c文件,而是在其他文件中出了一些问题,所以这些基本性的内容仍然需要做一些了解。
此外,这种方法只试用于头文件为官方库的情况,如果用到了其他的库则这种一步会出错,遇到这种情况的做法到后面再说。
Makefile
概念:在我们使用gcc进行编译时,如果有很多个.c文件,那么我们就需要一条一条的输入指令,这样做太过麻烦,所以Makefile就应运而生。Makefile本质上就是一种脚本,帮我们简化了许多重复性的操作。
多文件编译
首先准备好多个.c文件和.h文件,这里准备的是加减除三个函数,用c语言简单写一下就可以。 然后myProject.c中写的是主函数:
#include <stdio.h>
#include "myadd.h"
#include "mysub.h"
#include "mymul.h"
void main()
{
int n1 = 5;
int n2 = 20;
int n3 = 3;
printf("%d\n", myAdd(n1, n2));
printf("%d\n", mySub(n2, n3));
printf("%d\n", myMul(n1, n2));
}
那么,怎样将几个文件编译起来呢,具体操作如下所示: 很显然,这样做的操作比较麻烦。需要执行很多指令,我们可以用makefile来进行操作。
makefile 规则
target:depend command
target:目标,可以是一个中间文件,也可以是最终的执行文件 depend:依赖,指要生成目标文件所需要的文件或目标 command:make需要执行的命令
比如在这个指令中:
gcc -c mymul.c -o mymul.o
mymul.c为依赖,mymul.o为目标
makefile 执行顺序: 默认执行第一条,在执行第一条时,先找所有的依赖文件,如果没有,继续往下找有没有脚本能生成这个依赖文件,如果有就会先执行下面生成依赖的语句,当需要的依赖齐全后再执行那个语句。 事例:
test:prog.o code.o
gcc -o test prog.o code.o
prog.o:prog.c
gcc -c prog.c -o prog.o
code.o:code.c
gcc -c code.c -o code.o
clean:
rm -f *.o
没有第一条命令中需要的prog.o 和 code.o文件时,就先往下执行,通过编译.c 文件得到了prog.o和code.o文件,然后再执行第一条命令,就可以生成需要的test文件。
简单的makefile实例
写一个makefile文档:
myProject: myProject.o myadd.o mysub.o mymul.o
gcc *.o -o myProject
myProject.o: myProject.c
gcc -c myProject.c -o myProject.o
myadd.o:myadd.c
gcc -c myadd.c -o myadd.o
mysub.o:mysub.c
gcc -c mysub.c -o mysub.o
mymul.o:mymul.c
gcc -c mymul.c -o mymul.o
clean:
rm -f *.o
如图所示,写好makefile文件后,直接输入make就可以执行已经写好的指令,十分方便 全部编译好后,如果想要清除掉没用的文件,如.o文件,可以使用在makefile中写好的文件make clean。
makefile变量和通配符
变量理解为字符串
OBJ = a b c —— 表示OBJ就是a b c 这三个,不能改变了
OBJ := a b c —— 表示OBJ是a b c 但可以用+=再去追加
OBJ += a b c —— 表示OBJ变量添加了d这一个变量
变量引用:
$(变量名)
通配符:
% —— 表示任意一个
* —— 表示所有
?—— 表示匹配一个未知的东西
所以,原来的代码就可以进化成这样了:
OBJ:=myadd.o mysub.o mymul.o
OBJ+=myProject.o
myProject:$(OBJ)
gcc $(OBJ) -o myProject
*.o:*.c
gcc -c *.c -o *.o
clean:
rm -f *.o myProject
可见代码更加简洁,且后续修改也更加方便,但是还可以更加简洁。
$@ —— 表示目标文件 $^ —— 表示依赖文件
代码再次进化:
target=myProject
OBJ:=myadd.o mysub.o mymul.o
OBJ+=myProject.o
CC:=gcc
CFLAGS:=-c
$(target):$(OBJ)
$(CC) $^ -o $@
*.o:*.c
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -f *.o $(target)
这样后续修改直接改变量就可以了,非常方便
今天的文章Linux学习(二):makefile分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/17910.html