Makefile教程(绝对经典,所有问题看这一篇足够了)

您所在的位置:网站首页 default放前面 Makefile教程(绝对经典,所有问题看这一篇足够了)

Makefile教程(绝对经典,所有问题看这一篇足够了)

2024-01-23 18:47| 来源: 网络整理| 查看: 265

该篇文章为转载,是对原作者系列文章的总汇加上标注。

支持原创,请移步陈浩大神博客:

http://blog.csdn.net/haoel/article/details/2886

makefile很重要      什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

      现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。

    在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。

0.1 关于程序的编译和链接

   在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。               编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。        链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。

      总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的ObjectFile.              好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。

1 Makefile 介绍

      make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。

      首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:

                      1.如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。

            2.如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。

            3.如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

      只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。

1.1 Makefile的规则

   在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。

          target... : prerequisites ...

          command

          ...

          ...         -------------------------------------------------------------------------------

       target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

       prerequisites就是,要生成那个target所需要的文件或是目标。

       command也就是make需要执行的命令。(任意的Shell命令)

       这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

       说到底,Makefile的东西就是这样一点,好像我的这篇文档也该结束了。呵呵。还不尽然,这是Makefile的主线和核心,但要写好一个Makefile还不够,我会以后面一点一点地结合我的工作经验给你慢慢到来。内容还多着呢。:)

      【注】:在看别人写的Makefile文件时,你可能会碰到以下三个变量:$@,$^,$    为符合模式< pattern>的文件指定搜索目录。

2.        vpath < pattern>                              清除符合模式< pattern>的文件的搜索目录。

3.        vpath                                                 清除所有已被设置好了的文件搜索目录。

vapth使用方法中的< pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件。< pattern>指定了要搜索的文件集,而< directories>则指定了的文件集的搜索的目录。例如:

   vpath %.h ../headers

该语句表示,要求make在“../headers”目录下搜索所有以“.h”结尾的文件。(如果某文件在当前目录没有找到的话)

我们可以连续地使用vpath语句,以指定不同搜索策略。如果连续的vpath语句中出现了相同的< pattern>,或是被重复了的< pattern>,那么,make会按照vpath语句的先后顺序来执行搜索。如:

   vpath %.c foo

   vpath %   blish

   vpath %.c bar

其表示“.c”结尾的文件,先在“foo”目录,然后是“blish”,最后是“bar”目录。

   vpath %.c foo:bar

   vpath %   blish

而上面的语句则表示“.c”结尾的文件,先在“foo”目录,然后是“bar”目录,最后才是“blish”目录。

3.5 伪目标

最早先的一个例子中,我们提到过一个“clean”的目标,这是一个“伪目标”,

   clean:

           rm *.o temp

正像我们前面例子中的“clean”一样,即然我们生成了许多文件编译文件,我们也应该提供一个清除它们的“目标”以备完整地重编译而用。 (以“make clean”来使用该目标)

因为,我们并不生成“clean”这个文件。“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。

当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。

   .PHONY : clean

只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。于是整个过程可以这样写:

    .PHONY: clean

   clean:

           rm *.o temp

伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:

   all : prog1 prog2 prog3

   .PHONY : all

 

   prog1 : prog1.o utils.o

           cc -o prog1 prog1.o utils.o

 

   prog2 : prog2.o

           cc -o prog2 prog2.o

 

   prog3 : prog3.o sort.o utils.o

           cc -o prog3 prog3.o sort.o utils.o

我们知道,Makefile中的第一个目标会被作为其默认目标。我们声明了一个“all”的伪目标,其依赖于其它三个目标。由于伪目标的特性是,总是被执行的,所以其依赖的那三个目标就总是不如“all”这个目标新。所以,其它三个目标的规则总是会被决议。也就达到了我们一口气生成多个目标的目的。“.PHONY : all”声明了“all”这个目标为“伪目标”。

随便提一句,从上面的例子我们可以看出,目标也可以成为依赖。所以,伪目标同样也可成为依赖。看下面的例子:

   .PHONY: cleanall cleanobj cleandiff

 

   cleanall : cleanobj cleandiff

           rm program

 

   cleanobj :

           rm *.o

 

   cleandiff :

           rm *.diff

“makeclean”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。我们可以输入“makecleanall”和“make cleanobj”和“makecleandiff”命令来达到清除不同种类文件的目的

3.6 多目标

Makefile的规则中的目标可以不止一个,其支持多目标,有可能我们的多个目标同时依赖于一个文件,并且其生成的命令大体类似。于是我们就能把其合并起来。当然,多个目标的生成规则的执行命令是同一个,这可能会可我们带来麻烦,不过好在我们的可以使用一个自动化变量“$@”(关于自动化变量,将在后面讲述),这个变量表示着目前规则中所有的目标的集合,这样说可能很抽象,还是看一个例子吧。

   bigoutput littleoutput : text.g

           generate text.g -$(subst output,,$@) > $@

   上述规则等价于:

 

   bigoutput : text.g

           generate text.g -big > bigoutput

   littleoutput : text.g

           generate text.g -little > littleoutput

其中,-$(subst output,,$@)中的“$”表示执行一个Makefile的函数,函数名为subst,后面的为参数。关于函数,将在后面讲述。这里的这个函数是截取字符串的意思,“$@”表示目标的集合,就像一个数组,“$@”依次取出目标,并执于命令。

3.7 静态模式

静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。我们还是先来看一下语法:

: :

   

...

targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。

target-parrtern是指明了targets的模式,也就是的目标集模式。

prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。

这样描述这三个东西,可能还是没有说清楚,还是举个例子来说明一下吧。如果我们的定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们的定义成“%.c”,意思是对所形成的目标集进行二次定义,其计算方法是,取模式中的“%”(也就是去掉了[.o]这个结尾),并为其加上[.c]这个结尾,形成的新集合。

所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“\”进行转义,来标明真实的“%”字符。

看一个例子:

   objects = foo.o bar.o

 

   all: $(objects)

 

   $(objects): %.o: %.c

           $(CC) -c $(CFLAGS) $< -o $@

 

上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foobar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.cbar.c”。而命令中的“$ $@; \

            rm -f $@.

这个规则的意思是,所有的[.d]文件依赖于[.c]文件,“rm-f $@”的意思是删除所有的目标,也就是[.d]文件,第二行的意思是,为每个依赖文件“$的多,那么,中的多出来的单词将保持原样。如果的单词个数要比 多,那么,多出来的单词将被复制到中。 返回:返回连接过后的字符串。 示例:$(join aaa bbb , 111 222 333)返回值是“aaa111 bbb222 333”。 四、foreach 函数 foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的 foreach函数几乎是仿照于Unix标准Shell(/bin /sh)中的for语句,或是C-Shell(/bin /csh)中的foreach语句而构建的。它的语法是: $(foreach ,, ) 这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。 所以,最好是一个变量名,可以是一个表达式,而中一般会使用 这个参数来依次枚举中的单词。举个例子: names := a b c d files := $(foreach n,$(names),$(n).o) 上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(f iles)的值是“a.o b.o c.o d.o”。 注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。 五、if 函数 if函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是: $(if , ) 或是 $(if ,, ) 可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则 会被计算。 而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。 所以,和只会有一个被计算。 六、call函数 call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是: $(call ,,,...) 当 make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是 call函数的返回值。例如: reverse = $(1) $(2) foo = $(call reverse,a,b) 那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如: reverse = $(2) $(1) foo = $(call reverse,a,b) 此时的foo的值就是“b a”。 七、origin函数origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是: $(origin ) 注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函 数的返回值: “undefined” 如果从来没有定义过,origin函数返回这个值“undefined”。 “default” 如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。 “environment” 如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。 “file” 如果这个变量被定义在Makefile中。 “command line” 如果这个变量是被命令行定义的。 “override” 如果是被override指示符重新定义的。 “automatic” 如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。 这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一 个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是 ,在我们的Makefile中,我们可以这样写: ifdef bletch ifeq "$(origin bletch)" "environment" bletch = barf, gag, etc. endif endif 当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗 暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。 八、shell函数 shell 函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数 返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如: contents := $(shell cat foo) files := $(shell echo *.c) 注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。 九、控制make的函数 make提供了一些函数来控制make的运行。通常,你需要检测一些运行Makefile时的运行时信息,并且根据这些信息来决定,你是让make继续执行,还是停止。 $(error ) 产生一个致命的错误,是错误信息。注意,error函数不会在一被使用就会产生错误信息,所以如果你把其定义在某个变量中,并在后续的脚本中使用这个变量,那么也 是可以的。例如: 示例一: ifdef ERROR_001 $(error error is $(ERROR_001)) endif 示例二: ERR = $(error found an error!) .PHONY: err err: ; $(ERR) 示例一会在变量ERROR_001定义了后执行时产生error调用,而示例二则在目录err被执行时才发生error调用。 $(warning ) 这个函数很像error函数,只是它并不会让make退出,只是输出一段警告信息,而make继续执行。

make 的运行—————— 一般来说,最简单的就是直接在命令行下输入make命令,make命令会找当前目录的makefile来执行,一切都是自动的。但也有时你也许只想让 make重编译某些文件,而不是整个工程,而又有的时候你有几套编译规则,你想在不同的时候使用不同的编译规则,等等。本章节就是讲述如何使用make命令的。 一、make的退出码 make命令执行后有三个退出码:

0 —— 表示成功执行。

1 —— 如果make运行时出现任何错误,其返回1。

2 —— 如果你使用了make的“-q”选项,并且make使得一些目标不需要更新,那么返回2。

Make的相关参数我们会在后续章节中讲述。

二、指定Makefile 前面我们说过,GNU make找寻默认的Makefile的规则是在当前目录下依次找三个文件——“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就 开始读取这个文件并执行。 当前,我们也可以给make命令指定一个特殊名字的Makefile。要达到这个功能,我们要使用make的“-f”或是“--file”参数(“-- makefile”参数也行)。例如,我们有个mak efile的名字是“hchen.mk”,那么,我们可以这样来让make来执行这个文件: make –f hchen.mk 如果在make的命令行是,你不只一次地使用了“-f”参数,那么,所有指定的makefile将会被连在一起传递给make执行。 三、指定目标 一般来说,make的最终目标是makefile中的第一个目标,而其它目标一般是由这个目标连带出来的。这是make的默认行为。当然,一般来说,你的 makefile中的第一个目标是由许多个目标组成,你可以指示make,让其完成你所指定的目标。要达到这一目的很简单,需在make命令后直接跟目标的名字就可以完成(如前面提到的“make clean”形式)任何在makefile中的目标都可以被指定成终极目标,但是除了以“- ”打头,或是包含了“=”的目标,因为有这些字符的目标,会被解析成命令行参数或是变量。甚至没有被我们明确写出来的目标也可以成为make的终极目标,也就是说,只要make可以找到其隐含规则推导规则,那么这个隐含目标同样可以被指定成终极目标。 有一个make的环境变量叫“MAKECMDGOALS”,这个变量中会存放你所指定的终极目标的列表,如果在命令行上,你没有指定目标,那么,这个变量是空值。这个变量可以让你使用在一些比较特殊的情形下。比如下面的例子: sources = foo.c bar.c ifneq ( $(MAKECMDGOALS),clean) include $(sources:.c=.d) endif 基于上面的这个例子,只要我们输入的命令不是“make clean”,那么makefile会自动包含“foo.d”和“bar.d”这两个makefile。 使用指定终极目标的方法可以很方便地让我们编译我们的程序,例如下面这个例子: .PHONY: all all: prog1 prog2 prog3 prog4 从这个例子中,我们可以看到,这个makefile中有四个需要编译的程序——“prog1”, “prog2”, “prog3”和 “prog4”,我们可以使用“make all”命令来编译所有的目标 (如果把all置成第一个目标,那么只需执行“make”),我们也可以使用“make prog2”来单独编译目标“prog2”。 即然make可以指定所有makefile中的目标,那么也包括“伪目标”,于是我们可以根据这种性质来让我们的makefile根据指定的不同的目标来完成不同的事。在Unix世界中,软件 发布时,特别是GNU这种开源软件的发布时,其 makefile都包含了编译、安装、打包等功能。我们可以参照这种规则来书写我们的makefile中的目标。

“all”              这个伪目标是所有目标的目标,其功能一般是编译所有的目标。

“clean”       这个伪目标功能是删除所有被make创建的文件。

“install”       这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。

“print”         这个伪目标的功能是例出改变过的源文件。

“tar”             这个伪目标功能是把源程序打包备份。也就是一个tar文件。

“dist”           这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。

“TAGS”        这个伪目标功能是更新所有的目标,以备完整地重编译使用。

“check”和“test”    这两个伪目标一般用来测试makefile的流程。

       当然一个项目的makefile中也不一定要书写这样的目标,这些东西都是GNU的东西,但是我想,GNU搞出这些东西一定有其可取之处(等你的UNIX下的程序文件一多时你就会发现这些功能很有用了),这里只不过是说明了,如果你要书写这种功能,最好使用这种名字命名你的目标,这样规范一些,规范的好处就是——不用解释,大家都明白。而且如果你的makefile中有这些功能,一是很实用,二是可以显得你的makefile很专业(不是那种初学者的作品)。

四、检查规则 有时候,我们不想让我们的makefile中的规则执行起来,我们只想检查一下我们的命令,或是执行的序列。于是我们可以使用make命令的下述参数: “-n” “--just-print” “--dry-run” “--recon” 不执行参数,这些参数只是打印命令,不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行,这些参数对于我们调试makefile很有用处。 “-t” “--touch” 这个参数的意思就是把目标文件的时间更新,但不更改目标文件。也就是说,make假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。 “-q” “--question” 这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。 “-W ” “--what-if=” “--assume-new=” “--new-file=” 这个参数需要指定一个文件。一般是是源文件(或依赖文件),Make会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和“-n”参数一同使用,来查看这个依赖文件 所发生的规则命令。 另外一个很有意思的用法是结合“-p”和“-v”来输出makefile被执行时的信息(这个将在后面讲述)。 五、make的参数 下面列举了所有GNU make 3.80版的参数定义。其它版本和产商的make大同小异,不过其它产商的make的具体参数还是请参考各自的产品文档。 “-b” “-m” 这两个参数的作用是忽略和其它版本make的兼容性。 “-B” “--always-make” 认为所有的目标都需要更新(重编译)。 “-C ” “--directory=” 指定读取makefile的目录。如果有多个“-C”参数,make的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。如:“make –C ~hchen/test –C prog” 等价于“make –C ~hchen/test/prog”。 “—debug[=]” 输出make的调试信息。它有几种不同的级别可供选择,如果没有参数,那就是输出最简单的调试信息。下面是的取值:

a —— 也就是all,输出所有的调试信息。(会非常的多)

b —— 也就是basic,只输出简单的调试信息。即输出不需要重编译的目标。

v —— 也就是verbose,在b选项的级别之上。输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等。

i —— 也就是implicit,输出所以的隐含规则。

j —— 也就是jobs,输出执行规则中命令的详细信息,如命令的PID、返回码等。

m —— 也就是makefile,输出make读取makefile,更新makefile,执行makefile的信息。

“-d”相当于“--debug=a”。“-e”“--environment-overrides”指明环境变量的值覆盖makefile中定义的变量的值。“-f=”“--file=”“--makefile=”指定需要执行的makefile。“-h”“--help”显示帮助信息。“-i”“--ignore-errors”在执行时忽略所有的错误。“-I ”“--include-dir=”指定一个被包含makefile的搜索目标。可以使用多个“-I”参数来指定多个目录。“-j []”“--jobs[=]”指同时运行命令的个数。如果没有这个参数,make运行命令时能运行多少就运行多少。如果有一个以上的“-j”参数,那么仅最后一个“-j”才是有效的。(注意这个参数在MS-DOS中是无用的)“-k”“--keep-going”出错也不停止运行。如果生成一个目标失败了,那么依赖于其上的目标就不会被执行了。“-l ”“--load-average[=



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3