c /c++ 工程写法 linux makefile多文件编译 原理
其实很多时候逛github,看源码都会见到makefile 。makefile可以当一个工程管理器。在这里说一下,Makefile和makefile都是一样的,输入make命令后linux都会自动在当前目录找这两个makefile 。
不过,当makefile和Makefile在相同目录时,make会执行小写的makefile 所以很多源码都用Makefile 都比较谦虚啊
makefile是很有用的东西。尤其是在你组织一个比较大点的工程时,不可能一行一行地去编译,而且,工程中有的源码文件改动之后,makefile的好处就体现了。这个后说。
这里举个例子,整理一下我用到的。
我们现在home目录下创建这几个文件
写多了c一般都有这么个工程习惯。.h文件存放变量、函数的声明,宏定义,.c文件写具体的实现,最后main #include .h文件就可以。
然后我们vim * -p 用vim打开所有文件
这里有个小窍门
:ls
能显示每一个文件的编号 然后:bn 就能跳到 第n和文件
:n 是下一个文件 :N是上一个文件 ctrl + 6是切换
t1.h 我们简简单单声明一个函数
这个ifndef 和endif 是为了防止循环调用
t1.c我们简简单单写上这些,就是函数的具体实现
t2.h 和t2.c 就是改个皮 把代码里的t1换成t2
main.c 写上这些:
然后 我们编译运行一下 ok 成功了:
哦,对了。给不知道的说一下,gcc 只有一个.c 的时候 没指定输出文件 默认是输出a.out
我们现在开始理清关系
这个a.out 是怎么实现的? 它是依赖于三个文件: main.o t1.o t2.o (.o就是汇编后的目标文件)
main.o 依赖于 main.c
t1.o 依赖于t1.c
t2.o 依赖于t2.c
这就是makefile 的关系
接下来我们vim makefile
开始写makefile
我们先有一个总目标:myt : main.o t1.o t2.o
那我们写:
myt : main.o t1.o t2.o
gcc main.o t1.o t2.o -o myt
注意gcc前要tab的。格式很严
这段话意思是myt 依赖于main.o t1.o t2.o 命令是gcc xxx什么什么的
可是我们没有main.o
就接着写:我们的新目标就是main.o,而main.o依赖于main.c这个文件 所以大家应该懂了
main.o : main.c
gcc main.c -c -Wall -g -o main.o
-c是编译 -Wall是包含警告
然后同理
t1.o : t1.c
gcc t1.c -c -Wall -g -o t1.o
t2.o : t2.c
gcc t2.c -c -Wall -g -o t2.o
写完了makefile:
还有要注意,.h文件从来不参与我们的编译 我们从来都是include进去的
命令行输入make
就会执行所有的内容
他实质上是 先去执行所有的.o 再去生成myt文件
首先gcc main.c 为 main.o
然后gcc t1.c t1.o
gcc t2.c t2.o
gcc main.o t1.o t2.o myt
就是这个顺序
我们的makefile make 有很多的依赖与被依赖的关系
执行make 确定文件是否再重新生成取决于是否被修改过 就是 时间戳
如果myt 时间 和这几个.o 一比 比较旧 就会重新生成myt
这些依赖关系就像树一样 树的叶子结点动了 牵一发动全身 那些依赖他的 被依赖的 都得改啊
但是make只会重新编译最新被修改的 不信可以修改一下
所以make这个工程管理器可以很方便的不用动以前编译过的且未修改过的
对了makefile也可以加一个
clean:
rm *.o myt -r-f 做一个清理
我们输入make clean就能清理了
当然这样写个makefile很麻烦 要自己区分依赖关系
makefile 有很多简写的方法 可以变量替换 shell里边$符号不是取变量么 而且gcc还有一个宏变量就是CC
大写的CC就是gcc RM就是rm -f
这样用CC写很有用 我们如果要写cpp
我们nakefile里令CC =g++
我们就用g++编译了
还有个很好用的叫做CFLAGS变量
CFLAGS +=-c -Wall -g
这个意思是我也不知道你以前是什么编译选项 我反正用CFLAGS变量加上这些选项
还有$^ 代表上一句依赖关系中被依赖的文件
而目标文件比如myt 是可以复用的
myt : main.o t1.o t2.o
gcc main.o t1.o t2.o -o myt
可写为
OBJS = main.o t1.o t2.o
myt : $(OBJS )
$(CC) $^ -o $@
@_@ 什么天文
最终makefile天文可以写成:
CC = gcc(可以不要)
CFLAGS += -c -Wall -g
OBJS = main.o t1.o t2.o
myt : $(OBJS )
$(CC) $^ -o $@
main.o :main.c
$(CC) $^ $(CFLAGS) -o $@
t1.o :t1.c
$(CC) $^ $(CFLAGS) -o $@
t2.o :t2.c
$(CC) $^ $(CFLAGS) -o $@
clean:
rm *.o myt -r-f
这就是最终版的makfile吗?天真,这才是:
CC = gcc(可以不要)
CFLAGS += -c -Wall -g
OBJS = main.o t1.o t2.o
myt : $(OBJS )
$(CC) $^ -o $@
%.o :%.c
$(CC) $^ $(CFLAGS) -o $@
clean:
rm *.o myt -r-f
好了 现在看github那些makefile就不会被恶心到了@_@