makefileshell命令_LinuxMake的使⽤以及命令安装详解
  对于GNU Make或许很多Windows开发的程序员并不是很了解,因为Windows中的很多集成开发环境(I
DE)都帮我们做了这件事。但是作为⼀个专业从事Linux嵌⼊式开发的程序员就必须要了解GNU Make,会不会使⽤GNU Make从⼀定⾓度上反应了⼀个⼈是否具备⼤型⼯程能⼒。本⽂主要围绕Make命令展开,介绍Linux下Make的使⽤以及Makefile的语法和使⽤Make进⾏源码安装。
  ⼀、什么是GNU Make
  GNU Make是⼀个控制从程序的源⽂件中⽣成程序的可执⾏⽂件和其他⾮源⽂件的⼯具。
  Make可以从⼀个名为Makefile的⽂件中获得如何构建程序的知识,该⽂件列出了每个⾮源⽂件以及如何从其他⽂件计算它。当你编写⼀个程序时,你应该为它编写⼀个Makefile⽂件,这样就可以使⽤Make来编译和安装这个程序。
  ⼆、如何获取Make
  三、为什么需要Make
  任何⼀种技能或知识都是源之于某种社会需求,那为什么要⽤Make呢?当项⽬源⽂件很少的时候,我们也许还可以⼿动使⽤gcc命令来进⾏编译,但是当项⽬发展到⼀个庞⼤的规模时,再⼿动敲gcc命令去编译就变得不可能的事情。所以呢,在这样的历史背景下,就出现了⼀位⼤⽜(斯图亚特·费尔德曼),在1977年贝尔实验室制作了这样⼀个软件,它的名字就叫做Make。所以实际开发中,我们在编
译⼤型项⽬的时候往往会使⽤Make进⾏编译,为此我们还需要了解Make软件所依赖的Makefile规则⽂件。
  四、Makefile
  Makefile ⽂件需要按照某种语法进⾏编写,⽂件中需要说明如何编译各个源⽂件并连接⽣成可执⾏⽂件,并要求定义源⽂件之间的依赖关系。Makefile的语法还是略微有些复杂,因篇幅有限,本⽂只能简述Makefile的编写原则。
  (1)Makefile的组成部分
  Makefile包含五个东西:显⽰规则,隐式规则,变量定义,⽂件指⽰,注释。
  <1>显式规则,显式规则说明了,如何⽣成⼀个或多的的⽬标⽂件。这是由Makefile的书写者明显指出,要⽣成的⽂件,⽂件的依赖⽂件,⽣成的命令。
  <2>隐式规则,由于我们的make有⾃动推导的功能,所以隐晦的规则可以让我们⽐较粗糙地简略地书写Makefile,这是由make所⽀持的。
  <3>变量的定义,在Makefile中我们要定义⼀系列的变量,变量⼀般都是字符串,这个有点你C语⾔中的宏,当Makefile被执⾏时,其中的变量都会被扩展到相应的引⽤位置上。
  <4>⽂件指⽰,其包括了三个部分,⼀个是在⼀个Makefile中引⽤另⼀个Makefile,就像C语⾔中的include⼀样;另⼀个是指根据某些情况指定Makefile中的有效部分,就像C语⾔中的预编译#if⼀样;还有就是定义⼀个多⾏的命令。有关这⼀部分的内容,我会在后续的部分中讲述。
  <5>注释,Makefile中只有⾏注释,和UNIX的Shell脚本⼀样,其注释是⽤“#”字符,这个就像C/C++中的“//”⼀样。如果你要在你的Makefile中使⽤“#”字符,可以⽤反斜框进⾏转义,如:“/#”。
  (2) Makefile的规则
  我们先来粗略地看⼀看Makefile的规则。
  : prerequisites ...
  command
  ...
  ...
  -------------------------------------------------------------------------------
  target也就是⼀个⽬标⽂件,可以是Object File,也可以是执⾏⽂件。还可以是⼀个标签(Label),对于标签这种特性,在后续的“伪⽬标”章节中会有叙述。
  prerequisites就是,要⽣成那个target所需要的⽂件或是⽬标。
  command也就是make需要执⾏的命令。(⼀定要以Tab键作为开头)
  这是⼀个⽂件的依赖关系,也就是说,target这⼀个或多个的⽬标⽂件依赖于prerequisites中的⽂件,其⽣成规则定义在command 中。说⽩⼀点就是说,prerequisites中如果有⼀个以上的⽂件⽐target⽂件要新的话,command所定义的命令就会被执⾏。这就是Makefile的规则。也就是Makefile中最核⼼的内容。
  (3)Makefile之模式规则
  模式规则其实也是普通规则,但它使⽤了如%这样的通配符。如下⾯的例⼦:
  此规则描述了⼀个.o⽂件如何由对应的.c⽂件创建。规则的命令⾏中使⽤了⾃动化变量“$<”和“$@”,其中⾃动化变量“$<”代表规则的依赖,“$@”代表规则的⽬标。此规则在执⾏时,命令⾏中的⾃动化变量将根据实际的⽬标和依赖⽂件取对应值。
  其含义是,字指出了从所有的.c⽂件⽣成相应的.o⽂件的规则。如果要⽣成的⽬标是”a.o b.o”,那么 %.c”就是”a.c b.c”。
  在模式规则中,⽬标的定义需要有“%”字符。“%”定义对⽂件名的匹配,表⽰任意长度的⾮空字符串。在依赖⽬标中同样可以使
⽤“%”,只是依赖⽬标中“%”的取值,取决于其⽬标。
  注意:模式规则中“%”的展开和变量与函数的展开是有区别的,“%”的展开发⽣在变量和函数的展开之后。变量和函数的展开发⽣在make载⼊Makefile时,⽽“%”的展开则发⽣在运⾏时。
  <1> ⾃动化变量
  ⾃动化变量只应出现在规则的命令中。
变量
含义
$@
表⽰规则中的所有⽬标⽂件的集合。在模式规则中如果有多个⽬标,“$@”就是匹配于⽬标中模式定义的集合
$%
仅当⽬标是函数库⽂件时,表⽰规则中的⽬标成员名,如果⽬标不是函数库⽂件(UNIX下是.a,Windows是.lib),其值为空。
依赖⽬标中的第⼀个⽬标名字,如果依赖⽬标是以模式(即”%“)定义的,则”$<”是符合模式的⼀系列的⽂件集$?
所有⽐⽬标新的依赖⽬标的集合,以空格分隔
$^
所有依赖⽬标的集合,以空格分隔。如如果在依赖⽬标中有多个重复的,则⾃动去除重复的依赖⽬标,只保留⼀份$+
同”$^”,也是所有依赖⽬标的集合,只是它不去除重复的依赖⽬标。
$*
⽬标模式中“%”及其之前的部分
$(@D)
“$@”的⽬录部分(不以斜杠作为结尾),如果”$@”中没有包含斜杠,其值为“.”(当前⽬录)
$(@F)
“$@”的⽂件部分,相当于函数”$(notdir $@)”
$(*D)
同”$(@D)”,取⽂件的⽬录部分
$(*F)
同”$(@F)”,取⽂件部分,但不取后缀名
$(%D)
函数包⽂件成员的⽬录部分
$(%F)
函数包⽂件成员的⽂件名部分
$(
依赖⽬标中的第⼀个⽬标的⽬录部分
$(
依赖⽬标中的第⼀个⽬标的⽂件名部分
$(^D)
所有依赖⽬标⽂件中⽬录部分(⽆相同的)
$(^F)
所有依赖⽬标⽂件中⽂件名部分(⽆相同的)
$(+D)
所有依赖⽬标⽂件中的⽬录部分(可以有相同的)
$(+F)
所有依赖⽬标⽂件中的⽂件名部分(可以有相同的)
所有被更新⽂件的⽬录部分
$(?F)
所有被更新⽂件的⽂件名部分
  <2>$VAR和$$VAR的区别:
  makefile⽂件中的规则绝⼤部分都是使⽤shell命令来实现的,这⾥就涉及到了变量的使⽤,包括makefile中的变量和shell命令范畴内的变量。在makefile的规则命令⾏中使⽤$var就是在命令中引⽤makefile的变量,这⾥仅仅是读取makefile的变量然后扩展开,将其值作为参数传给了⼀个shell命令;⽽$$var是在访问⼀个shell命令内定义的变量,⽽⾮makefile的变量。如果某规则有n个shell命令⾏构成,⽽相互之间没有⽤';'和''连接起来的话,就是相互之间没有关联的shell命令,相互之间也不能变量共享。
  (4)Makefile之伪⽬标
linux命令及shell编写  使⽤其原因⼀:避免和同名⽂件冲突
  在现实中难免存在所定义的⽬标与所存在的⽬标是同名的,采⽤Makefile如何处理这种情况呢?Makefile中的假⽬标(phony target)可以解决这个问题。
  假⽬标可以使⽤.PHONY关键字进⾏声明,对于假⽬标,可以想象,因为不依赖于某⽂件,make该⽬标的时候,其所在规则的命令都会被执⾏。
  如果编写⼀个规则,并不产⽣⽬标⽂件,则其命令在每次make 该⽬标时都执⾏。
  例如:
  clean:
  rm *.o temp
  因为"rm"命令并不产⽣"clean"⽂件,则每次执⾏"make clean"的时候,该命令都会执⾏。如果⽬录中出现了"clean"⽂件,则规则失效了:没有依赖⽂件,⽂件"clean"始终是最新的,命令永远不会执⾏;为避免这个问题,可使⽤".PHONY"指明该⽬标。如:
  .PHONY : clean
  这样执⾏"make clean"会⽆视"clean"⽂件存在与否。
  已知phony ⽬标并⾮是由其它⽂件⽣成的实际⽂件,make 会跳过隐含规则搜索。这就是声明phony ⽬标会改善性能的原因,即使你并不担⼼实际⽂件存在与否。
  完整的例⼦如下:
  .PHONY : clean
  clean :
  rm *.o temp
  使⽤其原因⼆:提⾼执⾏make的效率
  当⼀个⽬标被声明为伪⽬标后,make在执⾏此规则时不会试图去查隐含规则来创建这个⽬标。这样也提⾼了make的执⾏效率,同时我们也不⽤担⼼由于⽬标和⽂件名重名⽽使我们的期望失败。
  (5)Makefile的赋值
  [=]和[:=]符号的区别。
  =
  可以先使⽤后定义,这就导致makefile在全部展开后才能决定变量的值。
  有可能出现循环递归,⽆法暂开的问题。
  必须先定义然后再使⽤,在当前的位置就可以决定变量的值。
  ?=
  相当于选择疑问句,如果前⾯的变量没被赋值,那就做赋值操作
  +=
  相当于递加操作
  (6)Makefile之执⾏过程
  1. 依次读取变量“MAKEFILES”定义的makefile⽂件列表
  2. 读取⼯作⽬录下的makefile⽂件(根据命名的查顺序“GNUmakefile”,“makefile”,“Makefile”,⾸先到那个就读取那个)
  3. 依次读取⼯作⽬录makefile⽂件中使⽤指⽰符“include”包含的⽂件
  4. 查重建所有已读取的makefile⽂件的规则(如果存在⼀个⽬标是当前读取的某⼀个makefile⽂件,则执⾏此规则重建此makefile⽂件,完成以后从第⼀步开始重新执⾏)
  5. 初始化变量值并展开那些需要⽴即展开的变量和函数并根据预设条件确定执⾏分⽀
  6. 根据“终极⽬标”以及其他⽬标的依赖关系建⽴依赖关系链表
  7. 执⾏除“终极⽬标”以外的所有的⽬标的规则(规则中如果依赖⽂件中任⼀个⽂件的时间戳⽐⽬标⽂件新,则使⽤规则所定义的命令重建⽬标⽂件)
  8. 执⾏“终极⽬标”所在的规则
  五、使⽤Make进⾏源码安装
  (1)正常的编译安装/卸载:
  源码的安装⼀般由3个步骤组成:配置(configure)、编译(make)、安装(make install)。
  configure⽂件是⼀个可执⾏的脚本⽂件,它有很多选项,在待安装的源码⽬录下使⽤命令./configure –help可以输出详细的选项列表。
  其中--prefix选项是配置安装⽬录,如果不配置该选项,安装后可执⾏⽂件默认放在/usr /local/bin,库⽂件默认放
在/usr/local/lib,配置⽂件默认放在/usr/local/etc,其它的资源⽂件放在/usr /local/share,⽐较凌乱。
  如果配置了--prefix,如:
  $ ./configure --prefix=/usr/local/test
  安装后的所有资源⽂件都会被放在/usr/local/test⽬录中,不会分散到其他⽬录。
  使⽤--prefix选项的另⼀个好处是⽅便卸载软件或移植软件;当某个安装的软件不再需要时,只须简单的删除该安装⽬录,就可以把软件卸载得⼲⼲净净;⽽移植软件只需拷贝整个⽬录到另外⼀个机器即可(相同的操作系统下)。
  当然要卸载程序,也可以在原来的make⽬录下⽤⼀次make uninstall,但前提是Makefile⽂件有uninstall命令(nodejs的源码包⾥有uninstall命令,测试版本v0.10.35)。
  (2)卸载:
  如果没有配置--prefix选项,源码包也没有提供make uninstall,则可以通过以下⽅式可以完整卸载:
  ⼀个临时⽬录重新安装⼀遍,如:
  $ ./configure --prefix=/tmp/to_remove && make install

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。