博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
makefile
阅读量:4286 次
发布时间:2019-05-27

本文共 11960 字,大约阅读时间需要 39 分钟。

makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

    Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。makefile 文件是许多编译器--包括 Windows NT 下的编译器--维护编译信息的常用方法,只是在集成开发环境中,用户通过友好的界面修改 makefile 文件而已。

    在 UNIX 系统中,习惯使用 Makefile 作为 makefile 文件。如果要使用其他文件作为 makefile,则可利用类似下面的 make 命令选项指定 makefile 文件。

    
        一个文件,指示程序如何编译和链接程序。makefile文件的默认名称是名副其实的Makefile,但可以指定一个命令行选项的名称。
        

make程序有助于您在开发大型程序跟踪整个程序,其中部分已经改变,只有那些编译自上次编译的程序,它已经改变了部分。

    

    关于编译阶段

    

    编译一个小的C程序至少需要一个单一的文件.h文件(如适用)。虽然命令执行此任务只需CC file.c中,有3个步骤,以取得最终的可执行程序,如下所示:

    

    编译阶段:所有的C语言代码.c文件中被转换成一个低级语言汇编语言;决策.s文件。

    

    汇编阶段:前阶段所作的汇编语言代码,然后转换成目标代码的代码片段,该计算机直接理解。目标代码文件.o 结束。

 

为什么需要Makefile?    

对于本次教程中的讨论,假定有以下的源文件。

  • main.cpp
  • hello.cpp
  • factorial.cpp
  • functions.h

main.cpp 文件的内容

#include 
#include "functions.h"int main(){ print_hello(); cout << endl; cout << "The factorial of 5 is " << factorial(5) << endl; return 0;}

 

 hello.cpp 文件的内容

#include 
#include "functions.h"void print_hello(){ cout << "Hello World!";}

 

 factorial.cpp 文件的内容

#include "functions.h"int factorial(int n){    if(n!=1){	return(n * factorial(n-1));    }    else return 1;}

 

 functions.h 内容

void print_hello();int factorial(int n);

 

琐碎的方法来编译的文件,并获得一个可执行文件,通过运行以下命令:

CC  main.cpp hello.cpp factorial.cpp -o hello

这上面的命令将生成二进制的Hello。在我们的例子中,我们只有四个文件,我们知道的函数调用序列,因此它可能是可行的,上面写的命令的手,准备最后的二进制。但对于大的项目,我们将有源代码文件成千上万的文件,就很难保持二进制版本。

make命令允许您管理大型程序或程序组。当开始编写较大的程序,你会发现,重新编译较大的程序,需要更长的时间比重新编译的短节目。此外会发现通常只能在一小部分的程序(如单一功能正在调试),其余的程序不变。

在随后的章节中,我们将看到项目是如何准备一个makefile。

Makefile 宏

make程序允许您使用宏,这是类似的变量。 = 一对一个Makefile中定义的宏。例如:

MACROS=  -mePSROFF=  groff -TpsDITROFF= groff -TdviCFLAGS= -O -systype bsd43LIBS = "-lncurses -lm -lsdl"MYFACE = ":*)"
  • 特殊的宏

目标规则集发出任何命令之前,有一些特殊的预定义宏。

  • $@ 到的文件的名称。

  • $? 是改变的眷属的名字。

因此,举例来说,我们可以使用一个规则

hello: main.cpp hello.cpp factorial.cpp	$(CC) $(CFLAGS) $? $(LDFLAGS) -o $@alternatively:hello: main.cpp hello.cpp factorial.cpp        $(CC) $(CFLAGS) $@.cpp $(LDFLAGS) -o $@

在这个例子中$@代表 hello, $? 或$@.cpp将拾取所有更改的源文件。

有两个比较特殊的隐含规则中使用的宏。它们是

  • $< 导致该操作的相应的文件中的名称。

  • $* 前缀共享目标和相关文件。

常见的隐含规则的构造 .o(对象)文件,.cpp(源文件)。

.o.cpp:        $(CC) $(CFLAGS) -c $

注意:要获得更详细的关于Makefile规则,在另一部分。

  • 传统宏

有很多默认的宏(输入“make -p”打印出来的默认值)。大多数使用它们的规则是很明显的:

这些预定义变量,即。在隐含规则中使用的宏分为两大类:那些程序名(例如CC)和那些含有参数的程序(如CFLAGS)。

下面是一些比较常见的变量用作内置规则:makefile文件的程序名称的表。

AR Archive-maintaining program; default `ar'.
AS Program for compiling assembly files; default `as'.
CC Program for compiling C programs; default `cc'.
CO Program for checking out files from RCS; default `co'.
CXX Program for compiling C++ programs; default `g++'.
CPP Program for running the C preprocessor, with results to standard output; default `$(CC) -E'.
FC Program for compiling or preprocessing Fortran and Ratfor programs; default `f77'.
GET Program for extracting a file from SCCS; default `get'.
LEX Program to use to turn Lex grammars into source code; default `lex'.
YACC Program to use to turn Yacc grammars into source code; default `yacc'.
LINT Program to use to run lint on source code; default `lint'.
M2C Program to use to compile Modula-2 source code; default `m2c'.
PC Program for compiling Pascal programs; default `pc'.
MAKEINFO Program to convert a Texinfo source file into an Info file; default `makeinfo'.
TEX Program to make TeX dvi files from TeX source; default `tex'.
TEXI2DVI Program to make TeX dvi files from Texinfo source; default `texi2dvi'.
WEAVE Program to translate Web into TeX; default `weave'.
CWEAVE Program to translate C Web into TeX; default `cweave'.
TANGLE Program to translate Web into Pascal; default `tangle'.
CTANGLE Program to translate C Web into C; default `ctangle'.
RM Command to remove a file; default `rm -f'.

这里是一个变量,其值是上述程序的额外的参数表。所有这些的默认值是空字符串,除非另有说明。

ARFLAGS Flags to give the archive-maintaining program; default `rv'.
ASFLAGS Extra flags to give to the assembler (when explicitly invoked on a `.s' or `.S' file).
CFLAGS Extra flags to give to the C compiler.
CXXFLAGS Extra flags to give to the C compiler.
COFLAGS Extra flags to give to the RCS co program.
CPPFLAGS Extra flags to give to the C preprocessor and programs that use it (the C and Fortran compilers).
FFLAGS Extra flags to give to the Fortran compiler.
GFLAGS Extra flags to give to the SCCS get program.
LDFLAGS Extra flags to give to compilers when they are supposed to invoke the linker, `ld'.
LFLAGS Extra flags to give to Lex.
YFLAGS Extra flags to give to Yacc.
PFLAGS Extra flags to give to the Pascal compiler.
RFLAGS Extra flags to give to the Fortran compiler for Ratfor programs.
LINTFLAGS Extra flags to give to lint.

注:您可以取消`-R'或` --no-builtin-variables“选项隐含规则使用的所有变量。

如,也可以在命令行中定义的宏

make CPP = /home/courses/cop4530/spring02

Makefile 定义依赖性

这是很常见的,最终的二进制文件将依赖于各种源代码和源代码的头文件。依存关系是重要的,因为他们告诉对任何目标的源。请看下面的例子

hello: main.o factorial.o hello.o	$(CC) main.o factorial.o hello.o -o hello

在这里,我们告诉hello 依赖main.o,factorial.o和hello.o,所以每当有任何变化,这些目标文件将采取行动。

同时我们会告诉如何准备 .o文件,所以我们必须定义这些依赖也如下

main.o: main.cpp functions.h	$(CC) -c main.cppfactorial.o: factorial.cpp functions.h	$(CC) -c factorial.cpphello.o: hello.cpp functions.h	$(CC) -c hello.cpp

Makefile 定义规则

一个Makefile目标规则的一般语法

target [target...] : [dependent ....]    [ command ...]

方括号中的项是可选的,省略号是指一个或多个。注意标签,每个命令前需要。

下面给出一个简单的例子,定义了一个规则使您的目标从 hello 其他三个文件。

 

hello: main.o factorial.o hello.o	$(CC) main.o factorial.o hello.o -o hello

注:在这个例子中,你必须放弃规则,使所有对象从源文件的文件

语义是相当简单的。当"make target"发现目标规则适用,如有眷属的新目标,使执行的命令一次一个(后宏替换)。如果有任何依赖进行,即先发生(让您拥有一个递归)。

如果有任何命令返回一个失败状态,MAKE将终止。这就是为什么看到规则,如:

clean:        -rm *.o *~ core paper

 

Make忽略一个破折号开头的命令行返回的状态。例如。如果没有核心文件,谁在乎呢?

Make 会 echo 宏字符串替换的命令后,告诉发生了什么事,因为它发生。有时可能想要把它们关掉。例如:

install:        @echo You must be root to install

大家所期望的Makefile的 某些目标。应该总是先浏览,但它的合理预期的目标(或只是做),安装,清洁,会发现。

  • make all - 编译一切,让你可以在本地测试,之前安装的东西。

  • make install - 应安装在正确的地方的东西。但看出来的东西都安装在正确的地方为系统。

  • make clean - 应该清理的东西。摆脱的可执行文件,任何临时文件,目标文件等。

 


Makefile的隐含规则

该命令应该在所有情况下,我们建立一个可执行x的的源代码x.cpp的作为一个隐含的规则,这可以说:

.cpp:        $(CC) $(CFLAGS) $@.cpp $(LDFLAGS) -o $@

这种隐含的规则说,如何make c,  x.c- 运行x.c 调用输出x。规则是隐式的,因为没有特定的目标提到。它可用于在所有的情况下。

另一种常见的隐含规则的构造 .o(对象)文件和 .cpp (源文件)。 

.o.cpp:        $(CC) $(CFLAGS) -c $

Makefile 自定义后缀规则

就其本身而言,make已经知道,为了创建一个 .o文件,就必须使用 cc-c 相应的c文件。 建成MAKE这些规则,可以利用这一点来缩短Makefile。如果仅仅只是表示 .h 文件的 Makefile依赖线,依赖于目前的目标是,MAKE会知道,相应的文件已规定。你甚至不需要编译器包括命令。

这减少了我们的Makefile更多,如下所示:

OBJECTS = main.o hello.o factorial.ohello: $(OBJECTS)        cc $(OBJECTS) -o hellohellp.o: functions.hmain.o: functions.h factorial.o: functions.h

 

Make 使用一个特殊的目标,故名 .SUFFIXES允许你定义自己的后缀。例如,依赖线:

.SUFFIXES: .foo .bar

告诉make ,将使用这些特殊的后缀,以使自己的规则。

 

如何让 make 已经知道如何从 .c 文件生成 .o文件。类似的可以定义规则以下列方式:

.foo.bar:        tr '[A-Z][a-z]' '[N-Z][A-M][n-z][a-m]' < $< > $@.c.o:        $(CC) $(CFLAGS) -c $<

 

第一条规则允许你创建一个 .bar 文件从 .foo文件。 (不要担心它做什么,它基本上打乱文件)第二条规则 .c文件创建一个 .o 文件中使用的默认规则。

Makefile 指令

有好几种指令以不同的形式。让程序可能不支持所有指令。因此,请检查make是否支持指令,我们这里解释。 GNU make支持这些指令

条件指令

条件的指令

  • ifeq 指令开始的条件,指定的条件。它包含两个参数,用逗号分隔,并用括号括起。两个参数进行变量替换,然后对它们进行比较。该行的makefile继IFEQ的服从如果两个参数的匹配,否则会被忽略。

  • ifneq 指令开始的条件,指定的条件。它包含两个参数,用逗号分隔,并用括号括起。两个参数进行变量替换,然后对它们进行比较。makefile ifneq 遵守如果两个参数不匹配,否则会被忽略。

  • ifdef 指令开始的条件,指定的条件。它包含单参数。如果给定的参数为真,则条件为真。

  • ifndef 指令开始的条件,指定的条件。它包含单参数。如果给定的是假的,那么条件为真。

  • else 指令会导致以下行如果前面的条件未能被遵守。在上面的例子中,这意味着第二个选择连接命令时使用的第一种选择是不使用。它是可选的,在有条件有一个else。

  • endif 指令结束条件。每一个条件必须与endif结束。 


条件式指令的语法

一个简单的条件,没有其他的语法如下:

conditional-directivetext-if-trueendif

文本如果真可以是任何行文字,被视为makefile文件的一部分,如果条件为真。如果条件是假的,没有文字来代替。

一个复杂的语法条件如下:

conditional-directivetext-if-trueelsetext-if-falseendif

如果条件为真时,文本,如果真正的使用,否则,如果假文本来代替。的文本,如果错误的数量可以是任意的文本行。

有条件的指令的语法是相同的,无论是简单或复杂的条件。有四种不同的测试不同条件下的指令。这里是一个表:

ifeq (arg1, arg2)ifeq 'arg1' 'arg2'ifeq "arg1" "arg2"ifeq "arg1" 'arg2'ifeq 'arg1' "arg2"

上述条件相反的指令如下

ifneq (arg1, arg2)ifneq 'arg1' 'arg2'ifneq "arg1" "arg2"ifneq "arg1" 'arg2'ifneq 'arg1' "arg2"

条件式指令示例

libs_for_gcc = -lgnunormal_libs =foo: $(objects)ifeq ($(CC),gcc)        $(CC) -o foo $(objects) $(libs_for_gcc)else        $(CC) -o foo $(objects) $(normal_libs)endif

 


include 指令

include指令告诉make暂停读取当前makefile文件和读取一个或多个其它的makefile,然后再继续。该指令是一行在makefile中,看起来像这样:

include filenames...

文件名可以包含shell文件名模式。允许额外的空格开头的行被忽略,但不允许一个标签。例如,如果有三个`.mk',`.mk' files, `a.mk', `b.mk', and `c.mk', and $(bar) 扩展到bash中,然后下面的表达式。

include foo *.mk $(bar)is equivalent toinclude foo a.mk b.mk c.mk bish bash

当MAKE处理包括指令,它包含的makefile暂停读取,并从各列出文件中依次读取。当这个过程完成,使读取指令出现在其中的makefile的恢复。


override 指令

如果一个变量已经设置的命令参数,在makefile中被忽略的普通任务。如果要设置makefile的变量,即使它被设置的命令参数,可以使用一个override指令,这是一行看起来像这样:

override variable = valueoroverride variable := value

Makefile include

makefile include 指令

include指令告诉make暂停读取当前makefile文件和读取一个或多个其它的makefile,然后再继续。该指令是一行在makefile中,看起来像这样:

include filenames...

文件名可以包含shell文件名模式。允许额外的空格开头的行被忽略,但不允许一个标签。例如,如果有三个`.mk',`.mk' files, `a.mk', `b.mk', and `c.mk', and $(bar) 扩展到bash中,然后下面的表达式。

include foo *.mk $(bar)is equivalent toinclude foo a.mk b.mk c.mk bish bash

当MAKE处理包括指令,它包含的makefile暂停读取,并从各列出文件中依次读取。当这个过程完成,使读取指令出现在其中的makefile的恢复。

Makefile 文件重新编译

make 程序是一个智能的实用程序和工作根据在源文件中的变化。如果有四个文件main.cpp,hello.cpp,factorial.cpp和functions.h。这里所有reamining文件是依赖functions.h,main.cpp的是依赖于hello.cpp,factorical.cpp。因此,如果做任何改变functions.h然后将重新编译所有源文件来生成新的对象文件。但是,如果做任何改变main.cpp,因为这是不依赖任何其他的过滤,那么在这种情况下,只有main.cpp文件将被重新编译和hellp.cpp factorial.cpp将无法重新编译。

虽然编译一个文件时,MAKE检查目标文件和比较时间表带,如果源文件有更新的时间戳比目标文件,然后将生成新的对象文件,假设源文件已被改变。


避免重新编译

有可能是项目包括成千上万的文件。有时候可能已经改变了一个源文件,但不想重新编译所有依赖于它的文件。例如,假设添加宏到一个头文件或声明,许多其他文件依赖。假设在头文件中的任何变化需要重新编译所有相关文件,但要知道,他们并不需要重新编译,你宁可不要浪费时间等待他们的编译。

如果预期改变头文件的问题之前,可以使用`-t'标志位。这个标志告诉make命令不运行的规则,而是来标记目标,迄今为止,通过改变它的最后修改日期。遵循以下步骤:

  1. 使用命令'make'来重新编译真的需要重新编译源文件。

  2. 在头文件中进行更改。

  3. 使用命令`-t'来纪念所有的目标文件为最新。下一次运行make,在头文件中的变化不会引起任何重新编译。

如果已经改变了头文件的时候,有一些文件就需要重新编译,做到这一点已经太晚了。相反,可以使用`-o文件“的标志,这标志着一个指定的文件作为”old“。这意味着该文件本身不会被重制并没有别的其交代将被重制。遵循以下步骤:

  1. 重新编译源文件,需要编制独立的特定头文件的原因,`make -o headerfile'。如果涉及几个头文件,使用一个单独的`-o'选项,每个头文件。

  2. 轻触所有目标文件使用`make -t'.

Makefile 其他功能

make 递归使用

递归使用的手段使用,make在makefile作为命令。这种技术是非常有用的,当你想要的makefile各种子系统组成一个更大的系统。例如,假设你有一个子目录,子目录都有其自己的makefile,并且您希望所在目录的makefile中运行make子目录。可以做到这一点如以下:

subsystem:        cd subdir && $(MAKE)or, equivalently 	subsystem:        $(MAKE) -C subdir

 

可以编写递归复制这个例子只是通过make命令,但有很多事情,了解他们是如何和为什么工作的,以及如何子涉及到顶层make。


通信变量到子make

顶层make变量的值可以被传递到子通过环境,通过显式请求。这些变数定义子作为默认值,但不会覆盖子的makefile使用makefile中所指定的,除非使用`-e'开关

向下传递,或导出,一个变量,变量和其值的环境中运行每个命令添加。子make反过来,make使用环境变量值来初始化它的表格

特殊变量SHELL和MAKEFLAGS总是导出(除非取消导出)。 MAKEFILES导出,如果把它设置到任何东西。

如果想导出特定变量的一个子制造,使用导出指令,像这样:

export variable ...

如果想阻止一个变量被导出的,使用撤消导出的指令,像这样:

unexport variable ...

MAKEFILES 变量

MAKEFILES如果环境变量的定义,make额外的makefile 名称列表(由空格分隔)之前被读取别人认为其值。这很像include指令:不同的目录中查找这些文件。

makefile的主要用途是MAKE递归调用之间的通信


头文件包含在不同的目录

如果已经把你的头文件在不同的目录,在不同的目录中运行make,那么它需要告诉头文件的路径。这是可以做到的makefile中使用-I选项。假设该functions.h文件可在/home/yiibai/header头和其他文件/home/yiibai/src/然后进行文件将被写入如下。 

INCLUDES = -I "/home/yiibai/header"CC = gccLIBS =  -lmCFLAGS = -g -WallOBJ =  main.o factorial.o hello.ohello: ${OBJ}   ${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}.cpp.o:   ${CC} ${CFLAGS} ${INCLUDES} -c $<

 


追加更多的文本变量

通常,它用于添加更多的文字,已定义的变量的值。make 这行包含'+ =',像这样:

objects += another.o

这需要值的变量对象,并添加文字`another.o'(前面由一个单一的空间)。因此:

objects = main.o hello.o factorial.oobjects += another.o

设置`文件main.o hello.o factorial.o another.o'的对象。

使用'+ ='是类似于:

objects = main.o hello.o factorial.oobjects := $(objects) another.o

 


Makefile中的续行

如果不喜欢太大的行,在Makefile中,然后你可以打破线使用反斜杠“\”,如下图所示

OBJ =  main.o factorial.o \	hello.ois equivalent toOBJ =  main.o factorial.o hello.o

 


从命令提示符下运行的Makefile

如果已经准备好请示的Makefile的名称为“Makefile”文件,然后简单地写在命令提示符下,它将运行Makefile文件。但是,如果有任何其他的名字的Makefile,然后使用以下命令

make -f your-makefile-name

makefile 例子

这是一个例子编译hello程序Makefile。此程序包含三个文件main.cpp,factorial.cpp,hello.cpp。

# Define required macros hereSHELL = /bin/shOBJS =  main.o factorial.o hello.oCFLAG = -Wall -gCC = gccINCLUDE =LIBS = -lmhello:${OBJ}	${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}clean:	-rm -f *.o core *.core.cpp.o:	${CC} ${CFLAGS} ${INCLUDES} -c $<

现在可以建立hello 程序使用“make”打招呼。如果发出命令“make clean”,则它会删除所有的对象可在当前目录中的文件和核心文件。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载地址:http://qzpgi.baihongyu.com/

你可能感兴趣的文章
git回到指定版本命令
查看>>
C#计算两个时间年份月份差
查看>>
Cordova 扫码插件整理-cordova-plugin-qrscanner
查看>>
cordova-plugin-splashscreen设置启动页面和图标
查看>>
cordova-plugin-battery-status监听电池状态
查看>>
cordova-plugin-globalization本地化
查看>>
cordova-plugin-contacts联系人操作
查看>>
cordova-plugin-camera相机插件使用
查看>>
cordova-plugin-media音频播放和录制
查看>>
Visual Studio 2017使用Emmet风格编写Html--ZenCoding
查看>>
iis提示“另一个程序正在使用此文件,进程无法访问。(异常来自HRESULT:0x80070020) ”解决办法
查看>>
Visual Studio Code v1.21发布
查看>>
C# Newtonsoft.Json JObject移除属性,在序列化时忽略
查看>>
Git移除版本控制操作
查看>>
分块编码(Transfer-Encoding: chunked)(转)
查看>>
Http缓存机制(转)
查看>>
C# 本地时间格式,UTC时间格式,GMT时间格式处理
查看>>
Windows系统搭建GitServer--Bonobo Git Server
查看>>
Bootstrap3 datetimepicker控件之smalot的使用
查看>>
小程序Canvas隐藏问题处理
查看>>