GNU Make / Makefile 学习资料
GNU Make学习总结(一)
GNU Make学习总结(二)
这篇学习总结,从一个简单的小例子开始,逐步加深,来讲解Makefile的用法。
最后用上面总结过的知识,给出了一个通用的C/C++ Makefile
文中提到《GNU 项目管理》一书,有280页。我觉得初学没必要看这么厚的书。豆瓣上对其评价也是不太实用。等以后有更深层次的需求时,再去看。
另外还有:
阮一峰-Make命令教程
这篇写的很简单,不过其中提到了一点很重要:每一行"命令"是独立的Shell。第二篇《使用Make构建网站》不需要看,是针对node.js的。
陈皓-跟我一起写Makefile
这本读起来很轻松,同时也比较全面。
徐海兵翻译-GNU make手册
官方文档通常是深入浅出的,非常推荐。就是比较罗嗦,也很厚,放最后看好了。
作者:Hexus
链接:https://www.jianshu.com/p/d63aff959d3d
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
今天学习了makefile的基本语法,特此总结一下。
主要的学习网站:https://www.jianshu.com/p/d63aff959d3d
原文:
GNU Make / Makefile 学习资料
GNU Make学习总结(一)
GNU Make学习总结(二)
这篇学习总结,从一个简单的小例子开始,逐步加深,来讲解Makefile的用法。
最后用上面总结过的知识,给出了一个通用的C/C++ Makefile
文中提到《GNU 项目管理》一书,有280页。我觉得初学没必要看这么厚的书。豆瓣上对其评价也是不太实用。等以后有更深层次的需求时,再去看。
另外还有:
阮一峰-Make命令教程
这篇写的很简单,不过其中提到了一点很重要:每一行"命令"是独立的Shell。第二篇《使用Make构建网站》不需要看,是针对node.js的。
陈皓-跟我一起写Makefile
这本读起来很轻松,同时也比较全面。
徐海兵翻译-GNU make手册
官方文档通常是深入浅出的,非常推荐。就是比较罗嗦,也很厚,放最后看好了。
作者:Hexus
链接:https://www.jianshu.com/p/d63aff959d3d
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
引用阮一峰的话:
代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。
Make是最常用的构建工具,诞生于1977年,主要用于C语言的项目。但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用Make构建。
入门
简介
Make是一种将源代码转换成可执行文件的自动化工具,通过Make语言,描述了源文件、中间文件、可执行文件之间的关系。与此同时,Make工具可以对编译过程进行优化,在重新编译时会根据时间戳来决定哪些文件需要重新生成,在编译大型工程时,这会省下不少时间(每次第一次编内核都是输完Make后先睡一觉再说...)。Make有多种变种,其中GNU Make使用相对广泛,在大多Linux/UNIX系统都对其提供支持。
Make一般将细节放在Makefile中,make命令会自动在当前文件夹下找到Makefile并执行,而Makefile的核心内容就是规则,它是Makefile的主要组成。每项规则可以由三部分组成:目标(target),必要条件(prerequisite),命令(command)。书写格式如下所示,目标和条件之间由冒号隔开,命令写在下一行,并以TAB开头,每条规则中可以有多个目标,多个条件以及多条命令。
target1 target2: prereq1 prereq2
command1
command2
tab开头请别忘记!!
自己写的案例:
1 #include "integrate.h"
2
3 float collect(float s,float t,int n,float (*p)(float x))
4 {
5 int i;
6 float f,h,x,y1,y2,area;
7 f=0.0;
8 h=(t-s)/n;
9 x=s;
10 y1=(*p)(x);
11
12 for(i=1;i<=n;i++)
13 {
14 x=x+h;
15 y2=(*p)(x);
16 area=(y1+y2)*h/2;
17 y1=y2;
18 f=f+area;
19 }
20 return (f);
21 }
22 float fun1(float x)
23 {
24 float fx;
25 fx=x*x-2.0*x+2.0;
26 return(fx);
27 }
28 float fun2(float x)
29 {
30 float fx;
31 fx=x*x*x+3.0*x*x-x+2.0;
32 return(fx);
33 }
34 float fun3 (float x)
35 {
36 float fx;
37 fx=x*sqrt(1+cos(2*x));
38 return(fx);
39 }
40 float fun4(float x)
41 {
42 float fx;
43 fx=1/(1.0+x*x);
44 return(fx);
45 }
46
47
48 #include <stdio.h>
49 #include <math.h>
50 #include "integrate.h"
51
52 int main()
53 {
54 int n,flag;
55 float a,b,v=0.0;
56
57 printf("Input the count range(from A to B)and the number of sections.
");
58 scanf("%f%f%d",&a,&b,&n);
59 printf("Enter your choice: '1' for fun1,'2' for fun2,'3' for fun3,'4' for fun4==>");
60 scanf("%d",&flag);
61
62 if(flag==1)
63 v=collect(a,b,n,fun1);
64 else if(flag==2)
65 v=collect(a,b,n,fun2);
66 else if(flag==3)
67 v=collect(a,b,n,fun3);
68 else
69 v=collect(a,b,n,fun4);
70 printf("v=%f
",v);
71 return 0;
72 }
73
74
75 //------------integrate.h------------
76 #ifndef _INTEGRATE_H_
77 #define _INTEGRATE_H_
78
79 #include <stdio.h>
80 #include <math.h>
81
82
83 float collect( float s, float t, int m, float (*p)(float x) );
84 float fun1(float x);
85 float fun2(float x);
86 float fun3(float x);
87 float fun4(float x);
88
89 #endif
首先;三个文件都在一个目录下
两个C文件,一个h文件。
最简单的makefile
main: main.o integrate.o
gcc integrate.o main.o -o main
main.o: main.c integrate.h
gcc -c main.c
integrate.o: integrate.c integrate.h
gcc -c integrate.c
#为了避免这种情况,可以明确声明clean是"伪目标",写法如下。声明clean是"伪目标"之后,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令。像.PHONY这样的内置目标名还有不少,
.PHONY: clean
clean:
rm *.o *.exe
点击make后,显示如下命令:
gcc -c main.c
gcc -c integrate.c
gcc integrate.o main.o -o main
这个比较简单。
复杂一点:
#这一章主要对生成规则进行了详细介绍,主要分为具体规则、模式规则、静态模式规则、隐含规则、后缀规则等等。在了解这些规则之前,首先了解一些其它的前提知识。
#变量及自动变量
#在Makefile中,使用x,$(xx)。关于变量的使用会在下一章详细介绍,这里主要说一下自动变量。自动变量一般用在命令中,会根据目标和条件自动替换成对应的内容。以下是几个常用的自动变量:
#$@ 目标文件名
#$% 档案文件成员,是指以a.o(b.o)这种形式作为目标时,括号中的内容
#$< 第一个必要条件文件名
#$? 时间戳在目标文件之后的所有必要条件文件名,空格隔开
#$^ 所有必要条件的文件名,空格隔开,这份列表删除了重复的文件名
#$+ 和$^一样,只是未删除重复的文件名
#$* 目标的主文件名(即不包括后缀)
#以上变量都有两个变体,加D表示文件的目录部分,加F表示文件的文件名部分,注意要加括号,如($F)等。
#我们可以使用自动变量来修改之前的Makefile,简化命令部分的书写
main: main.o integrate.o
gcc $^ -o $@
main.o: main.c integrate.h
gcc -c $<
integrate.o: integrate.c integrate.h
gcc -c $<
.PHONY: clean all
all:main
clean:
rm *.o *.exe
$<,$@是自动变量,解释看上面的说明,
all:main可以在命令行中,等同于make,即make all等同于make。
显示结果:
gcc -c main.c
gcc -c integrate.c
gcc main.o integrate.o -o main
版本三,更加难一点
CC=gcc
CFLAGS=-I.
DEPS = integrate.h
OBJ = integrate.o main.o
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c $< -o $@
main: $(OBJ)
$(CC) $(CFLAGS) $^ -o $@
.PHONY: clean
all:main
clean:
rm *.o *.exe
参考自:http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/
Makefile 4
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
OBJ = hellomake.o hellofunc.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
前四行是内置变量,应该不难理解。
模式规则
在gcc编译器中一般使用后缀表示文件类型,gcc会将x.c文件认为是C源文件,并翻译成对应的x.o,这种文件名的对应关系是模式规则的基础,使得Makefile对于目标x.o会自动去寻找对应的x.c文件,因此对于很多规则,我们都可以简化。
在一个规则中,如果主文件名中包含了%就表示这是一个模式规则。所谓模式规则,是指对符合这个模式的目标都采用这个规则,注意%和通配符的不同,在Makefile中是可以使用通配符的,*.c表示的是所有以c结尾的文件的集合,而%.c表示所有以c结尾的文件都匹配这条规则,一定要注意区分。
所有的内置规则都是模式规则,使用make -p可以看到这些内置规则,用其中生成%.o的这一条作为例子
%.o: %.c
#commands to execute (built-in): 这个是注释
$(COMPILE.c) $(OUTPUT_OPTION) $<
所有c文件结合h文件都要编译成相应的.o文件
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c $< -o $@
版本四:多文件夹管理编译
将h文件放在include下,将.c文件放在src下,Makefile文件与两个文件同级,如下所示:
|-- integrate
-- include
|-- integrate.h
-- src
|-- integrate.c
|-- main.c
Makefile
#这时候再在InputSpeed目录下执行make就会报找不到文件的错误,解决的方法之一是通过VPATH = src include将源文件加入到Make的搜索路径中,但这样并不是最好的方法,因为不同的文件夹下可能有同名的文件,VPATH只会返回第一个找到的文件,并不一定是我们想要的文件,我们可以使用vpath pattern directory的形式来指定在哪个目录下搜索哪个文件,具体用法可以看下面给出的Makefile,其中%类似于通配符,告诉Make在src下找.c文件,在include下找.h文件。现在make已经可以找到所有的文件了,但还不行,因为gcc命令找不到函数的原型,我们通过-I命令把头文件的位置告诉GCC。修改后的Makefile文件如下所示
#VAPTH src include
vpath %.c src
vpath %.h include
CFLAGS = -I include
main: main.o integrate.o
gcc $^ -o $@
main.o: main.c integrate.h
gcc $(CFLAGS) -c $< -o $@
integrate.o: integrate.c integrate.h
gcc $(CFLAGS) -c $< -o $@
.PHONY: clean all
all:main
clean:
rm *.o *.exe
版本五:隐含规则
就是make自带的内置规则,不是模式规则就是后缀规则。在我们没有为规则编写命令时,make会自动去内置规则中找是否有对应的规则,上面模式规则中举的例子就是一个隐含规则,利用该隐含规则,我们可以进一步简化我们的Makefile,
vpath %.c src
vpath %.h include
CFLAGS = -I include
CC=gcc
main: main.o integrate.o
main.o: integrate.h
integrate.o: integrate.h
.PHONY: clean all
all:main
clean:
rm *.o *.exe
隐含规则的出现,使我们的Makefile一句命令都没有用就完成了编译,也简洁了很多,实在是十分强大。这个makefile格式真是比较厉害的。
gcc -I include -c -o main.o src/main.c
gcc -I include -c -o integrate.o src/integrate.c
gcc main.o integrate.o -o main