概要
Makefile学习记录。
列出从简单到复杂的4个Makefile模型:version 1~4.
首先是编译要用到的4个文件:
main.c:
#include"hello.h"
#include<stdio.h>
int main()
{
printhello();
printf("This is main:\r\n");
printf("the factorial of 5 is: %d\r\n",factorial(5));
return 0;
}
hello.c:
#include<stdio.h>
#include"hello.h"
void printhello(void)
{
printf("hello world!\r\n");
}
factorial.c:
#include<stdio.h>
#include"hello.h"
int factorial(int num)
{
if(num == 1)
return 1;`在这里插入代码片`
else
return num * factorial(num-1);
}
hello.h:
void printhello(void);
int factorial(int num);
Makefile version 1:
这是最简单的方式:
1.hello 是要生成的目标文件,后面3个文件是编译链接所需要的;
2.第二行前面一定要缩进一个tab键的空格;
3.gcc表示编译方式,-o表示指定输出文件名称 yzh,后面三个文件是需要依赖的文件;
hello: main.c hello.c factorial.c
gcc -o yzh main.c hello.c factorial.c
执行make 指令即可产生yzh文件,如下
Makefile version 2:
这是进化版V2,区别:
1.用指定符号CXX、TARGET、OBJ替换了一些变量,后续只需要调用这些指定符号即可实现相应功能;
2.每个.c文件都产生各自的.o文件,哪个.c文件有更新,则编译相应的.c文件,从而节省编译时间和资源,这也是最大的好处;
CXX = gcc #指定编译器 gcc
TARGET = yzh #编译目标 yzh
OBJ = main.o hello.o factorial.o #OBJ表示这几个文件
$(TARGET) : $(OBJ) #比较TARGET和OBJ的修改时间,
$(CXX) -o $(TARGET) $(OBJ) #如果OBJ时间更新,则执行本行
#相当于执行了 gcc -o yzh main.o hello.o factorial.o
#main.o的来源
main.o: main.c
$(CXX) -c main.c #只编译生成.o文件,不链接
#hello.o的来源
hello.o: hello.c
$(CXX) -c hello.c
#factorial.o的来源
factorial.o: factorial.c
$(CXX) -c factorial.c
执行make 指令,效果如下:
Makefile version 3:
与上一版的区别:
1.增加了一个编译选项 CXXFLAGS;
2. 用 $@ 替换了 $(TARGET),用 $^ 替换了 $(OBJ),注意 $^ 代表的是所有的依赖条件
3.(最大的好处)用语句"%.o: %.c"编译产生了所有.o文件,在大型系统中就显得很简洁了;
4.增加了clean命令;
CXX = gcc #指定编译器 gcc
TARGET = yzh #编译目标 yzh
OBJ = main.o hello.o factorial.o #OBJ表示这几个文件
CXXFLAGS = -c -Wall #编译选项,把所有的警告都显示出来
$(TARGET) : $(OBJ)
$(CXX) -o $@ $^ #$@指的是目标,即$(TARGET), $^指所有的依赖条件,这里指$(OBJ)
%.o: %.c
$(CXX) $(CXXFLAGS) $< -o $@ # $@ 指目标,即 %.o, $< 指依赖条件的第一个,这里只有一个,即%.c
#.PHONY这个文件永远不会存在,故如果执行 make clean,就一定会执行到这里
#如果不加.PHONY,且外部有clean这个文件,再执行make clean,就会执行不到这里
.PHONY: clean
clean:
rm -f *.o $(TARGET)
效果如下:
Makefile version 4:
与上一版的区别:
用"OBJ = $(patsubst %.c, %.o, $(SRC)) "语句做到了自适应.c文件的增加或者减少,不需要修改makefile文件,具体见代码;
CXX = gcc #指定编译器 gcc
TARGET = yzh #编译目标 yzh
SRC = $(wildcard *.c) #把所有.c文件都放到SRC中
OBJ = $(patsubst %.c, %.o, $(SRC)) #把所有SRC中的文件都换成.o文件,这样即使后面增加或者减少了.c文件,
## makefile文件也不需要动,做到了自适应
CXXFLAGS = -c -Wall #编译选项,把所有的警告都显示出来
$(TARGET) : $(OBJ)
$(CXX) -o $@ $^ #$@指的是目标,即$(TARGET),$^指所有的依赖条件,这里指$(OBJ)
%.o: %.c
$(CXX) $(CXXFLAGS) $< -o $@ #$@指目标,即%.o,$<指依赖条件的第一个,这里只有一个,即%.c
#.PHONY这个文件永远不会存在,故如果执行 make clean,就一定会执行到这里
#如果不加.PHONY,且外部有clean这个文件,再执行make clean,就会执行不到这里
.PHONY: clean
clean:
rm -f *.o $(TARGET)
执行效果:
小结
makefile功能的学习需要由简到繁,不然真的看不懂,嘻嘻~~
写文章真累,不过也算是对在网络上学习到这么多知识的一点回馈吧。
另外我是在bilibili的 于仕琪 的教学视频上学习到的这些内容,搜makefile自然就出来他的视频了,点击量最高的就是他了,很棒的。