⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gmake.txt

📁 gnu make 的使用说明
💻 TXT
📖 第 1 页 / 共 4 页
字号:
  以下例子从相应的".c"文件编译"foo.o"和"bar.o": 
  objects = foo.o bar.o 
  $(objects): %.o: %.c 
  $(CC) -c $(CFLAGS) $< -o $@ 
  每个目标必须匹配目标模式,对于不匹配的目标会给出警告。如果列表中只有部分文件匹配模式,可以使用filter 函数移去不匹配的文件名: 
  files = foo.elc bar.o lose.o 
  $(filter %.o,$(files)): %.o: %.c 
  $(CC) -c $(CFLAGS) $< -o $@ 
  $(filter %.elc,$(files)): %.elc: %.el 
  emacs -f batch-byte-compile $< 
  例子中"$(filter %.o,$(files))" 结果是"bar.o lose.o"; "$(filter %.elc,$(files))" 的结果是"foo.elc"。 
  以下例子说明"$*"的使用: 
  bigoutput littleoutput : %output : text.g 
  generate text.g -$* > $@ 
  命令 "generate"执行时,"$*"扩展为词干"big"或"little"。 

3.11.2 静态模式规则和隐式规则 

  静态模式规则和隐式规则在作为模式规则是具有很多共同点,都有目标模式和构造依赖文件名的模式,不同之处在于make 决定何时应用规则的方法。隐式规则可应用于匹配其模式的任何目标,但只限于没有指定命令的目标,如果有多条可应用的隐式规则,只有一条被使用,取决于规则的顺序。反之,静态模式规则适用于规则中明确目标列表,不适用于其它目标且总是适用于指定的每个目标。如果有两条冲突的规则,且都有命令,这是一个错误。 

  静态模式规则比隐式规则优越之处如下: 
  ★可为一些不能按句法分类,但可以显式列出的文件重载隐式规则 
  ★不能判定目录中的精确内容,一些无关的文件可能导致make 适用错误的隐式规则;最终结果可能依赖于隐式规则的次序。适用静态模式规则时,这种不确定性是不存在的:规则适用于明确指定的目标。 

3.12 双冒号规则 
  双冒号规则(Double-colon rules)的目标后是"::"而不是":",当一个目标出现在多条规则中时,其处理和普通规则的处理不同。当一个目标出现在多条规则中时,所有规则必须是相同类型的:都是普通的或者都是双冒号的。如果是双冒号,规则之间相互独立;如果目标需要更新,则规则的命令被执行;结果可能是没有执行,或者执行了其中一些,或者所有的规则都执行了。 

   同一目标的双冒号规则事实是完全孤立的,每条规则被被单独处理,就象不同目标的规则一样;规则按照在makefile 中出现的次序被处理,此类规则真正有意义的是那些于命令执行次序无关的。 

   这种规则有时比较晦涩不是特别有用;它提供了一种机制:通过不同依赖文件的更新来对目标进行不同的处理,这种情形很罕见。每个这种规则应当提供命令,如果没有,适用的隐式规则将使用。 

3.13 自动生成依赖关系 
  在makefile 中,许多规则都是一些目标文件依赖于一些头文件。例如:"main.c"通过"#include"使用"defs.h",这样规则: 
  main.o: defs.h 
  告诉make 在"defs.h"变化时更新"main.o"。在程序比较大时,需要写许多这样的规则;而且当每次增删"#include"时,必须小心的更新makefile。许多现代的编译器可以帮你写这些规则,通常这是通过编译器的"-M"选项,例如命令: 
  cc -M main.c 
  输出以下内容: 
  main.o : main.c defs.h 
  这样就不必写这些规则,有编译器代劳了。 
  注意这样的依赖关系中提及"main.o",不会被隐式规则认为是中间文件,这意味这make 在使用过它之后不会将其删除。使用老的"make"程序时,习惯做法是使用"make depend"命令利用编译器的功能产生依赖关系,该命令会产生一个"depend"文件包含所有自动产生的依赖关系,然后在makefile 中使用"include"将其读入。 

  使用GNU 的make 时,重新生成makefile 的功能使得这种做法变得过时:从不需要显式请求更新依赖关系,因为它总是重新生成任何过时的makefile。 
  自动依赖关系生成推荐的做法是对每个源文件做一个makefile。对每个源文件"NAME.c",有一个makefile "NAME.d",其中列出了目标文件"NAME.o"依赖的所有文件,这样在源文件更新时,需要扫描来产生新的依赖关系。例子是一个从"NAME.c"产生依赖关系文件"NAME.d"的模式规则: 
  %.d: %.c 
  $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< | sed '\''s/\($*\)\.o[ :]*/\1 $@/g'\'' > $@' 

  -e 选项是当$(CC)命令失败时(exit 状态非0),shell 立刻退出。通常shell 的返回值是管道中最后一条命令(sed)的返回值,这样make 不会注意到编译器出错。 
  使用GNU 的C 编译器时(gcc),可以用"-MM"选项来代替"-M"选项,这样省略系统头文件的依赖关系。"sed"命令的目的是将main.o : main.c defs.h转换为main.o main.d : main.c defs.h 

  这样使得每个".d"文件依赖于".o"文件相应源文件和头文件,make 则可以在原文间或头文件变化时更新依赖关系文件。 

  如果定义了生成".d"文件的规则,可以使用"include"指令来读入所有的文件: 
  sources = foo.c bar.c 
  include $(sources:.c=.d) 
  例中使用替换变量来将源文件列表" foo.c bar.c"转换为依赖关系文件的列表。因为".d"文件和其它文件一样,不需要更多工作,make 会在需要时重新生成它们。 

4 编写命令 
  规则的命令是由一一执行的shell 命令组成。除了以分号隔开写在依赖关系后的命令,每个命令行必须以tab 字符开始空行和注释行可以出现在命令行中,处理时被忽略(注意:以tab 字符开始的空行不是"空"行,是一条空命令)。可以在命令中使用任何程序,但这些程序是由$(SHELL)来执行的。 

4.1 回显 
  通常make 打印出要执行的命令,称之为回显,这和亲自敲命令的现象是一样的。当行之前有"@"字符时,命令不再回显,字符"@"在传递给shell 前丢弃。 
  典型的用法是只对打印命令有效,比如"echo"命令: 
  @echo About to make distribution files 
  当make 使用"-n"或"-just-print"选项时,显示要发生的一切,但不执行命令。只有在这种情况下,即使命令以"@"开始,命令行仍然显示出来。这个选项对查看make 实际要执行的动作很有用。 
  ‘-s"或"-silent"选项阻止make 所有回显,就象所有命令以"@"开始一样;一条没有依赖关系的".SILENT"规则有相同的作用,但是"@"更加灵活。 

4.2 执行 
  在需要执行命令更新目标时,make 为每一行创建一个子shell 来执行。这意味着诸如为进程设置局部变量的shell 命令"cd"(改变进程的当前目录)不会影响以后的命令。如果需要"cd"影响下一个命令,将它们放在一行上用分号隔开, 
  这样make 认为是一条命令传递给shell 程序(注意:这需要shell 支持): 
  foo : bar/lose 
  cd bar; gobble lose > ../foo 
  另一个形式使用续行符: 
  foo : bar/lose 
  cd bar; \ 
  gobble lose > ../foo 

  shell 程序的名字是通过"SHELL"变量来取得的。 
  "SHELL"变量不是通过环境来设置的(即需要在makefile 中设置),因为"SHELL"环境是个人选择的,如果不同人的选择会影响makefile 的功能的话,这样很糟糕。 

4.3 并行执行 
  GNU make 可以一次执行几条命令。通常make一次执行一条命令,等待其返回,再执行下一条。使用"-j"或"-jobs"可以同时执行多条命令。如果"-j"后跟一个正数,表示一次可以执行的命令条数;如果"-j"之后没有参数,则不限制可执行的命令数。缺省的数量是一。 

  一个讨厌的问题是如果同时执行多条命令,它们的输出会混在一起;另一个问题是两个进程不能从同一个设备获得输入。 

4.4 错误 
  每条shell 命令返回时,make 会检查其返回状态。如果命令执行成功,则下一条命令被执行,最后一条命令执行完后,规则执行结束。 
如果有错误(返回非0 状态),make 放弃当前规则,也可能是所有规则。 
  有时候命令执行错误并不是问题,比如使用"mkdir"命令确保目录存在:如果目录一存在,则"mkdir"会报告错误,但仍希望make 继续。要忽略命令的错误,在命令之前使用"-"字符,"-"字符在传递给shell 之前被丢弃: 
   clean: 
   -rm -f *.o 
  如果使用"-i"或"-ignore-errors"选项,make 会忽略所有命令产生的错误;一条没有依赖关系的".IGNORE"规则有相同的作用,但"-"更灵活。在忽略错误时,make 将错误也认为是成功,只是通知你命令的退出状态和错误被忽略。如果make 并未告知忽略错误,在错误发生时,表明该目标不能成功。更新,直接或间接依赖于此的目标当然也不能成功;这些目标的命令不会被执行,因为其先决条件不满足。 

  通常make 会立即以非0 状态退出。然而,如果给定"-k"或"-keep-going"选项,make 在退出前会处理其它的依赖关系,进行必要的更新。例如,在编译一个目标文件遇到错误,"make -k"会继续编译其它的目标文件。通常认为你的目的是更新指定的目标,当make 知道这是不可能时,会立即报告失败;"-k"选项指示真正目的是测试更新程序的更多可能性:在编译之前找出更多不相关的问题。 
   
  如果命令失败了,假设它更新的目标文件,这个文件是不完整的不能使用-至少不是完全更新的。但文件的最后修改时间表明已经是最新的,下一次make 运行时,不会再更新这个文件。这种情况和命令被kill 相同;则通常情况下在命令失败时将目标删除是正确的;当".DELETE_ON_ERROR"是目标时make 帮你做这件事。虽然你总是希望make 这么做,但这不是过去的习惯;所以必须显式要求make 这样做(其它的make 自动这样做)。 

4.5 中断make 
  如果make 执行命令时遇到错误,可能会删除命令更新的目标文件: make 检查文件的修改时间是否变化。删除目标的目的是确保make 下次执行时重新生成它。 
  为什么这样做?假设在编译器运行时按了"Ctrl-c",此时编译器写生成目标文件"foo.o"。"Ctrl-c" kill 了编译器,留下一个不完整的文件,但它的修改时间比源文件"foo.c"新;此时make 也受到"Ctrl-c"信号删除这个不完整的文件, 
  如果make 不这样做,下次make 运行时认为"foo.o"不需要更新,会在链接时出现奇怪的错误。 
  可以使用".PRECIOUS"规则来防止目标文件被删除。在make 更新目标时,会检测其是否为".PRECIOUS"的依赖,决定在命令出错或中断时是否删除该目标。如果你希望目标的更新是原子操作,或是用来记录修改时间,或必须一直存在防止其它类型的错误,这些理由使得你必须这样做。 

4.6 递归使用 
  递归使用make 就是在makefile 中使用make 命令。这种技术在你将一个大系统分解为几个子系统,为每个自系统提供一个makefile 时有用处。比如有一个子目录"subdir"中有自己的makefile,希望make 在自己目录中运行,可以这样做: 
  subsystem: 
  cd subdir; $(MAKE) 
  或者 
  subsystem: 
  $(MAKE) -C subdir 
  可以照抄这个例子来递归使用make 

4.6.1‘MAKE"变量 
  递归的make 必须使用"MAKE"变量,不是显式的make 命令: 
  subsystem: 
  cd subdir; $(MAKE) 
  该变量的值是被调用的make的名字。在命令中使用"MAKE"有特殊的功能:它改变了"-t" ("--touch"), "-n" ("--just-print")和"-q" ("--question")选项的含义。使用上例来考虑"make -t"命令("-t"选项将目标标记为最新但不运行命令),"-t"选项的功能,该命令将创建一个"subsystem"文件,实际希望的操作是运行"cd subdir; make -t";但这回执行命令,与"-t"的原意不符。 
   
  这个特殊功能做了期望的工作。当命令行包含变量"MAKE"时,选项"-t","-n"和"-q"并不适用。不管这些导致不会执行命令的标志,包含"MAKE"变量的命令始终会执行。正常的"MAKEFLAGS"机制将这些标志传递到子make, 
   
  这样打印命令的请求被传播到子系统中。 

4.6.2 传递变量到子make 
  上级(top-level)make 中的变量可以显式通过环境传递到子make中。在子make中,这些变量被缺省定义,但不会重载子makefile 中的定义除非使用"-e"选项向下传递,或输出变量,make 在运行命令时将其加入到环境变量中;子make 可以使用环境变量来初始化变量表。 除非显式要求,make 只输出初始环境中或命令行设置的变量而且变量名只由字母,数字和下划线组成。一些shell 不能处理有其它字符的环境变量。特殊变量"SHELL","MAKEFLAGS"总是输出,如果"MAKEFILE"变量有值,也会输出。Make 自动通过"MAKEFLAGS"来输出命令行定义的变量。 

   如果想要输出特定变量,使用"export"指令: 
   export VARIABLE ... 
   如果要阻止输出一个变量,使用"unexport"指令: 
   unexport VARIABLE ... 
   为方便起见,可以在定义变量时输出它: 
   export VARIABLE = value 
   和 
   VARIABLE = value 
   export VARIABLE 
   作用相同。 
  如果要输出所有的变量,使用"export"指令本身就可以了。 
  变量"MAKELEVEL"在一级一级传递时会改变,这个变量的值是表示嵌套层数的字符串,顶级"make"是,变量的值为"0";子make 的值为"1";子子make 的值为"2",依此类推。 
  "MAKELEVEL"的用途是在条件指令中测试它,这样写出在递归运行时和直接运行时表现不同的makefile。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -