makefile基础
2015-10-17 16:26
357 查看
说明:本文章的所有内容基本都来自GNU Make 项目管理(第三版)这本书,大家想深入学习的话最好去看原书。
同目录下的名为makefile的文件内容如下
运行make命令,就会编译出一个名为hello的可执行文件
执行 ./hello 输出 hello world
target1 target2 …: prereq1 prereq2 …
command1
command2
.
.
.
target1等为工作目标,prereq1等为必要条件,command1等为要产生工作目标所要执行的命令。工作目标是一个必须生成的文件或进行的事情;必要条件是工作目标得以被成功创建之前,必须事先存在的那些文件;所要执行的命令则是必要条件成立时将会创建工作目标的那些shell命令。
注意:command前面为tab,不能用空格代替,否则会有语法错误
当make被要求处理某项规则时,它首先会找出必要条件和工作目标中所指定的文件。如果必要条件中存在关联到其他规则的文件,则make会先完成相应规则的更新动作,然后才会考虑到工作目标。如果必要条件中存在时间戳在工作目标的时间戳之后的文件(也就是必要条件的文件比目标文件新),则make会执行命令以便重新建立工作目标,否则make不会执行相应的命令。如果执行时有任何命令发生错误,则make会终止工作目标的建立并结束执行。
当我们不带参数调用make时,make会自动编译其所找到的第一个工作目标。如果要更新特定的工作目标时,可以在命令行上指定工作目标的名称。
make hello
我们可以用-n选项要求make显示它将为特定工作目标执行的命令,但不实际执行它们。
make -n
make中的注释符为#,另外可以用\来延续过长的文本行
通配符
当模式出现在工作目标或必要条件中时由make进行通配符扩展
当模式出现在命令中时是由shell执行此命令时进行扩展
几个例子
*.* 会被扩展成文件名中包含点号的所有文件
{a,b}.o 匹配 a.o和b.o
[ab].c 匹配 a.c或b.c
[^ab].c 匹配非a.c和b.c
? 匹配任何单一字符
假想工作目标
任何不代表文件的工作目标就叫做假想工作目标,假想工作目标会被标记为已更新,所以相应的命令永远不会被自动执行,除非你指明执行此命令,看下面的例子
clean:
rm -rf *.o
当你执行make时,clean后面的命令是不会被执行的,你可以用make clean命令来执行clean后面的命令。
另外make无法区分文件形式的工作目标与假想工作目标,如果当前目录中刚好出现与假想工作目标同名的文件,可能就会出错。为了解决此问题,GNU make提供了一个特殊的工作目标.PHONY,看下面的例子
.PHONY: clean
clean:
rm -rf *.o
这样即使当前工作目录存在名为clean的文件,make clean还是会执行对应于clean的命令。而且此命令还会让make知道,不应该像处理一般规则那样,从源文件来建立以工作目标为名的文件,从而优化make的一般搜索过程以提高性能。
假想工作目标其实也是可以指定必要条件的,看下面的例子
.PHONY: clean
clean: clean1
rm -rf test2.c
.PHONY: clean1
clean1:
rm -rf test1.c
这样当我们执行make clean时,会先执行rm -rf test1.c,再执行rm -rf test2.c。
标准的假想工作目标
|工作目标|功能|
|all|执行编译应用程序的所有工作|
|install|从已编译的二进制文件进行应用程序的安装|
|clean|将产生自源代码的二进制文件删除|
|distclean|删除编译过程中产生的任何文件(除了二进制文件,也包含configure所产生的makefile)|
|TAGS|建立可供编译器使用的标记表|
|info|从Texinfo源代码来创建GNU info文件|
|check|执行与应用程序相关的任何测试|
自动变量
自动变量是由make自动设定的,你可以直接使用它们
我们可以在后面加D来只返回值的目录部分,例如(@D)∗∗,也可以在后面加∗∗F∗∗来只返回值的文件部分,例如∗∗(@F)。
指定搜索路径
假如我们的mymakefile文件夹下有一个makefile文件和两个名字分别为include和src的文件夹,include文件夹下有一个名为mysort.h的文件,src文件夹下有两个名字分别为main.c和mysort.c的文件,它们的内容如下
此时运行make命令会提示
make: * No rule to make target
这是因为make默认在当前目录找寻工作目标以及必要条件,我们必须要告诉它源文件的目录,这可以用VPATH实现,来吧,让我们加上VPATH
咦,又出错了,错误信息如下
gcc -c src/mysort.c
src/mysort.c:1:20: fatal error: mysort.h: No such file or directory
#include “mysort.h”
^
compilation terminated.
make: * [mysort.o] Error 1
原来是找不到头文件了,别着急,让我们加上-I include选项
这时会生成当前目录生成main.o mysort.o mysort三个文件,我们可以用./mysort运行一下,会输出 1 2 3 4 5 6 7 8 9 10,我们已经学了假想工作目标了,让我们再添加点东西
然后删除刚才生成的文件,再运行make命令,接着运行make clean,这样我们就只保留了可运行文件mysort。
1.一个例子
hello.c文件内容如下#include<stdio.h> int main() { printf("hello world\n"); return 0; }
同目录下的名为makefile的文件内容如下
hello: hello.c gcc hello.c -o hello
运行make命令,就会编译出一个名为hello的可执行文件
执行 ./hello 输出 hello world
2.基本规则
规则的基本构成target1 target2 …: prereq1 prereq2 …
command1
command2
.
.
.
target1等为工作目标,prereq1等为必要条件,command1等为要产生工作目标所要执行的命令。工作目标是一个必须生成的文件或进行的事情;必要条件是工作目标得以被成功创建之前,必须事先存在的那些文件;所要执行的命令则是必要条件成立时将会创建工作目标的那些shell命令。
注意:command前面为tab,不能用空格代替,否则会有语法错误
当make被要求处理某项规则时,它首先会找出必要条件和工作目标中所指定的文件。如果必要条件中存在关联到其他规则的文件,则make会先完成相应规则的更新动作,然后才会考虑到工作目标。如果必要条件中存在时间戳在工作目标的时间戳之后的文件(也就是必要条件的文件比目标文件新),则make会执行命令以便重新建立工作目标,否则make不会执行相应的命令。如果执行时有任何命令发生错误,则make会终止工作目标的建立并结束执行。
当我们不带参数调用make时,make会自动编译其所找到的第一个工作目标。如果要更新特定的工作目标时,可以在命令行上指定工作目标的名称。
make hello
我们可以用-n选项要求make显示它将为特定工作目标执行的命令,但不实际执行它们。
make -n
make中的注释符为#,另外可以用\来延续过长的文本行
通配符
当模式出现在工作目标或必要条件中时由make进行通配符扩展
当模式出现在命令中时是由shell执行此命令时进行扩展
几个例子
*.* 会被扩展成文件名中包含点号的所有文件
{a,b}.o 匹配 a.o和b.o
[ab].c 匹配 a.c或b.c
[^ab].c 匹配非a.c和b.c
? 匹配任何单一字符
假想工作目标
任何不代表文件的工作目标就叫做假想工作目标,假想工作目标会被标记为已更新,所以相应的命令永远不会被自动执行,除非你指明执行此命令,看下面的例子
clean:
rm -rf *.o
当你执行make时,clean后面的命令是不会被执行的,你可以用make clean命令来执行clean后面的命令。
另外make无法区分文件形式的工作目标与假想工作目标,如果当前目录中刚好出现与假想工作目标同名的文件,可能就会出错。为了解决此问题,GNU make提供了一个特殊的工作目标.PHONY,看下面的例子
.PHONY: clean
clean:
rm -rf *.o
这样即使当前工作目录存在名为clean的文件,make clean还是会执行对应于clean的命令。而且此命令还会让make知道,不应该像处理一般规则那样,从源文件来建立以工作目标为名的文件,从而优化make的一般搜索过程以提高性能。
假想工作目标其实也是可以指定必要条件的,看下面的例子
.PHONY: clean
clean: clean1
rm -rf test2.c
.PHONY: clean1
clean1:
rm -rf test1.c
这样当我们执行make clean时,会先执行rm -rf test1.c,再执行rm -rf test2.c。
标准的假想工作目标
|工作目标|功能|
|all|执行编译应用程序的所有工作|
|install|从已编译的二进制文件进行应用程序的安装|
|clean|将产生自源代码的二进制文件删除|
|distclean|删除编译过程中产生的任何文件(除了二进制文件,也包含configure所产生的makefile)|
|TAGS|建立可供编译器使用的标记表|
|info|从Texinfo源代码来创建GNU info文件|
|check|执行与应用程序相关的任何测试|
自动变量
自动变量是由make自动设定的,你可以直接使用它们
变量 | 包含的内容 |
---|---|
$@ | 工作目标的文件名 |
$% | 档案文件成员(archive member)结构中的文件名元素 |
$< | 第一个必要条件的文件名 |
$? | 时间戳在工作目标时间戳之后的所有必要条件的文件名,以空格分隔 |
$^ | 所有必要条件的文件名,以空格分隔,已经删除了重复的文件名 |
$+ | 所有必要条件的文件名,以空格分隔,美有删除重复的文件名 |
$* | 工作目标的主文件名(即不含扩展名) |
指定搜索路径
假如我们的mymakefile文件夹下有一个makefile文件和两个名字分别为include和src的文件夹,include文件夹下有一个名为mysort.h的文件,src文件夹下有两个名字分别为main.c和mysort.c的文件,它们的内容如下
//mysort.h #ifndef MYSORT #define MYSORT #include<stdlib.h> #include<string.h> void sort( void * arr, int length, int elemlen, int (* compare)(void *,void *) ); int int_compare( void *a, void *b ); #endif
//mysort.c #include "mysort.h" void sort( void * arr, int length, int elemlen, int (* compare)(void *,void *) ){ void *temp = malloc(elemlen); int i = 0,j = 0; for(i=length-1;i>0;i--){ for(j=0;j<i;j++){ if(compare((char *)arr+j*elemlen,(char *)arr+(j+1)*elemlen)){ memcpy(temp,(char *)arr+j*elemlen,elemlen); memcpy((char *)arr+j*elemlen,(char *)arr+(j+1)*elemlen,elemlen); memcpy((char *)arr+(j+1)*elemlen,temp,elemlen); } } } free(temp); } int int_compare(void *a,void *b){ return *(int *)a > *(int *)b; }
//main.c #include<stdio.h> #include<stdlib.h> #include<string.h> #include "mysort.h" int main() { int arr[10] = {2,4,5,7,8,1,9,10,3,6}; sort(arr,10,sizeof(int),int_compare); int i = 0; for(i=0;i<10;i++){ printf("%d ",arr[i]); } printf("\n"); return 0; }
mysort: mysort.o main.o gcc $^ -o $@ mysort.o: mysort.c include/mysort.h gcc -c $< -o $@ main.o: main.c include/mysort.h gcc -c $< -o $@
此时运行make命令会提示
make: * No rule to make target
mysort.c', needed bymysort.o’. Stop.
这是因为make默认在当前目录找寻工作目标以及必要条件,我们必须要告诉它源文件的目录,这可以用VPATH实现,来吧,让我们加上VPATH
VPATH = src
mysort: mysort.o main.o gcc $^ -o $@ mysort.o: mysort.c include/mysort.h gcc -c $< -o $@ main.o: main.c include/mysort.h gcc -c $< -o $@
咦,又出错了,错误信息如下
gcc -c src/mysort.c
src/mysort.c:1:20: fatal error: mysort.h: No such file or directory
#include “mysort.h”
^
compilation terminated.
make: * [mysort.o] Error 1
原来是找不到头文件了,别着急,让我们加上-I include选项
VPATH = src mysort: mysort.o main.o gcc $^ -o $@ mysort.o: mysort.c include/mysort.h gcc -I include -c $< -o $@ main.o: main.c include/mysort.h gcc -I include -c $< -o $@
这时会生成当前目录生成main.o mysort.o mysort三个文件,我们可以用./mysort运行一下,会输出 1 2 3 4 5 6 7 8 9 10,我们已经学了假想工作目标了,让我们再添加点东西
VPATH = src mysort: mysort.o main.o gcc $^ -o $@ mysort.o: mysort.c include/mysort.h gcc -I include -c $< -o $@ main.o: main.c include/mysort.h gcc -I include -c $< -o $@
.PHONY: clean
clean:
rm -rf *.o
然后删除刚才生成的文件,再运行make命令,接着运行make clean,这样我们就只保留了可运行文件mysort。
相关文章推荐
- Linux/Unix环境下的Make和Makefile详解
- Python实现生成简单的Makefile文件代码示例
- (转)自动生成 Makefile 的全过程详解
- u-boot的Makefile分析
- 关于linux模块驱动简单的Makefile
- 编译单个驱动的Makefile文件。
- makefile完全教程
- Linux内核Makefile文件
- Linux内核的Makefile
- Makefile 文件的相关知识(2)
- 使用AutoMake轻松生成Makefile
- 学习写 Makefile
- makefile之环境变量MAKEFILES
- 一起写 Makefile
- u-boot的Makefile分析435557749
- MakeFile
- MakeFile详解
- Linux内核makefile解析
- linux 2.6内核makefile分析
- makefile经典实例