您的位置:首页 > 其它

makefile基础

2015-10-17 16:26 357 查看
说明:本文章的所有内容基本都来自GNU Make 项目管理(第三版)这本书,大家想深入学习的话最好去看原书。

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)结构中的文件名元素
$<第一个必要条件的文件名
$?时间戳在工作目标时间戳之后的所有必要条件的文件名,以空格分隔
$^所有必要条件的文件名,以空格分隔,已经删除了重复的文件名
$+所有必要条件的文件名,以空格分隔,美有删除重复的文件名
$*工作目标的主文件名(即不含扩展名)
我们可以在后面加D来只返回值的目录部分,例如(@D)∗∗,也可以在后面加∗∗F∗∗来只返回值的文件部分,例如∗∗(@F)

指定搜索路径

假如我们的mymakefile文件夹下有一个makefile文件和两个名字分别为includesrc的文件夹,include文件夹下有一个名为mysort.h的文件,src文件夹下有两个名字分别为main.cmysort.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 by
mysort.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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  makefile