<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="https://www.gentoo-zh.org/extern.php?action=feed&amp;tid=501&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Gentoo中文社区 / Makefile 使用总结]]></title>
		<link>https://www.gentoo-zh.org/viewtopic.php?id=501</link>
		<description><![CDATA[Makefile 使用总结 最近发表的帖子。]]></description>
		<lastBuildDate>Mon, 07 Nov 2022 04:55:52 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Makefile 使用总结]]></title>
			<link>https://www.gentoo-zh.org/viewtopic.php?pid=537#p537</link>
			<description><![CDATA[<p>Makefile 主要的 5个部分 (显示规则, 隐晦规则, 变量定义, 文件指示, 注释)</p><p>Makefile基本格式如下:</p><p>target ... : prerequisites ...&#160; &#160;<br />&#160; command&#160; &#160; <br />&#160; &#160;...&#160; &#160; <br />&#160; &#160;...</p><p>其中,</p><p>&#160; &#160; target&#160; &#160; &#160; &#160; - 目标文件, 可以是 Object File, 也可以是可执行文件<br />&#160; &#160; prerequisites - 生成 target 所需要的文件或者目标<br />&#160; &#160; command&#160; &#160; &#160; &#160;- make需要执行的命令 (任意的shell命令), Makefile中的命令必须以 [tab] 开头</p><p> </p><p>&#160; &#160; 显示规则 :: 说明如何生成一个或多个目标文件(包括 生成的文件, 文件的依赖文件, 生成的命令)<br />&#160; &#160; 隐晦规则 :: make的自动推导功能所执行的规则<br />&#160; &#160; 变量定义 :: Makefile中定义的变量<br />&#160; &#160; 文件指示 :: Makefile中引用其他Makefile; 指定Makefile中有效部分; 定义一个多行命令<br />&#160; &#160; 注释&#160; &#160; &#160;:: Makefile只有行注释 &quot;#&quot;, 如果要使用或者输出&quot;#&quot;字符, 需要进行转义, &quot;\#&quot;</p><p> <br />1.2 GNU make 的工作方式</p><p>&#160; &#160; 读入主Makefile (主Makefile中可以引用其他Makefile)<br />&#160; &#160; 读入被include的其他Makefile<br />&#160; &#160; 初始化文件中的变量<br />&#160; &#160; 推导隐晦规则, 并分析所有规则<br />&#160; &#160; 为所有的目标文件创建依赖关系链<br />&#160; &#160; 根据依赖关系, 决定哪些目标要重新生成<br />&#160; &#160; 执行生成命令</p><p> <br />2. Makefile 初级语法<br />2.1 Makefile 规则<br />2.1.1 规则语法</p><p>规则主要有2部分: 依赖关系 和 生成目标的方法.</p><p>语法有以下2种:</p><p>target ... : prerequisites ...&#160; &#160; &#160;<br />&#160; &#160;command <br />&#160; &#160; ...</p><p>或者</p><p>target ... : prerequisites ; command<br /> command<br /> ...</p><p>*注* command太长, 可以用 &quot;\&quot; 作为换行符</p><p> <br />2.1.2 规则中的通配符</p><p>&#160; &#160; *&#160; &#160; &#160;:: 表示任意一个或多个字符<br />&#160; &#160; ?&#160; &#160; &#160;:: 表示任意一个字符<br />&#160; &#160; [...] :: ex. [abcd] 表示a,b,c,d中任意一个字符, [^abcd]表示除a,b,c,d以外的字符, [0-9]表示 0~9中任意一个数字<br />&#160; &#160; ~&#160; &#160; &#160;:: 表示用户的home目录</p><p> <br />2.1.3 路径搜索</p><p>当一个Makefile中涉及到大量源文件时(这些源文件和Makefile极有可能不在同一个目录中),</p><p>这时, 最好将源文件的路径明确在Makefile中, 便于编译时查找. Makefile中有个特殊的变量 VPATH 就是完成这个功能的.</p><p>指定了 VPATH 之后, 如果当前目录中没有找到相应文件或依赖的文件, Makefile 回到 VPATH 指定的路径中再去查找..</p><p>VPATH 使用方法:</p><p>&#160; &#160; vpath &lt;directories&gt;&#160; &#160; &#160; &#160; &#160; &#160; :: 当前目录中找不到文件时, 就从&lt;directories&gt;中搜索<br />&#160; &#160; vpath &lt;pattern&gt; &lt;directories&gt;&#160; :: 符合&lt;pattern&gt;格式的文件, 就从&lt;directories&gt;中搜索<br />&#160; &#160; vpath &lt;pattern&gt;&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; :: 清除符合&lt;pattern&gt;格式的文件搜索路径<br />&#160; &#160; vpath&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; :: 清除所有已经设置好的文件路径</p><p># 示例1 - 当前目录中找不到文件时, 按顺序从 src目录 ../parent-dir目录中查找文件<br />VPATH src:../parent-dir&#160; </p><p># 示例2 - .h结尾的文件都从 ./header 目录中查找<br />VPATH %.h ./header</p><p># 示例3 - 清除示例2中设置的规则<br />VPATH %.h</p><p># 示例4 - 清除所有VPATH的设置<br />VPATH</p><p>2.2 Makefile 中的变量<br />2.2.1 变量定义 ( = or := )</p><p>OBJS = programA.o programB.o <br />OBJS-ADD = $(OBJS) programC.o <br /># 或者 <br />OBJS := programA.o programB.o <br />OBJS-ADD := $(OBJS) programC.o</p><p>其中 = 和 := 的区别在于, := 只能使用前面定义好的变量, = 可以使用后面定义的变量</p><p>测试 =</p><p># Makefile内容<br />OBJS2 = $(OBJS1) programC.o<br />OBJS1 = programA.o programB.o</p><p>all:<br />&#160; &#160; @echo $(OBJS2)</p><p># bash中执行 make, 可以看出虽然 OBJS1 是在 OBJS2 之后定义的, 但在 OBJS2中可以提前使用<br />$ make<br />programA.o programB.o programC.o</p><br /><p>测试 :=</p><p># Makefile内容<br />OBJS2 := $(OBJS1) programC.o<br />OBJS1 := programA.o programB.o</p><p>all:<br />&#160; &#160; @echo $(OBJS2)</p><p># bash中执行 make, 可以看出 OBJS2 中的 $(OBJS1) 为空<br />$ make<br />programC.o<br />2.2.2 变量替换<br /># Makefile内容<br />SRCS := programA.c programB.c programC.c<br />OBJS := $(SRCS:%.c=%.o)</p><p>all:<br />&#160; &#160; @echo &quot;SRCS: &quot; $(SRCS)<br />&#160; &#160; @echo &quot;OBJS: &quot; $(OBJS)</p><p># bash中运行make<br />$ make<br />SRCS:&#160; programA.c programB.c programC.c<br />OBJS:&#160; programA.o programB.o programC.o</p><p>2.2.3 变量追加值 +=<br /># Makefile内容<br />SRCS := programA.c programB.c programC.c<br />SRCS += programD.c</p><p>all:<br />&#160; &#160; @echo &quot;SRCS: &quot; $(SRCS)</p><p># bash中运行make<br />$ make<br />SRCS:&#160; programA.c programB.c programC.c programD.c</p><p>2.2.4 变量覆盖 override</p><p>作用是使 Makefile中定义的变量能够覆盖 make 命令参数中指定的变量</p><p>语法:</p><p>&#160; &#160; override &lt;variable&gt; = &lt;value&gt;<br />&#160; &#160; override &lt;variable&gt; := &lt;value&gt;<br />&#160; &#160; override &lt;variable&gt; += &lt;value&gt;</p><p> </p><p>下面通过一个例子体会 override 的作用：<br /># Makefile内容 (没有用override)<br />SRCS := programA.c programB.c programC.c</p><p>all:<br />&#160; &#160; @echo &quot;SRCS: &quot; $(SRCS)</p><p># bash中运行make<br />$ make SRCS=nothing<br />SRCS:&#160; nothing</p><p>#################################################</p><p># Makefile内容 (用override)<br />override SRCS := programA.c programB.c programC.c</p><p>all:<br />&#160; &#160; @echo &quot;SRCS: &quot; $(SRCS)</p><p># bash中运行make<br />$ make SRCS=nothing<br />SRCS:&#160; programA.c programB.c programC.c</p><p>2.2.5 目标变量</p><p>作用是使变量的作用域仅限于这个目标(target), 而不像之前例子中定义的变量, 对整个Makefile都有效.</p><p>语法:</p><p>&#160; &#160; &lt;target ...&gt; :: &lt;variable-assignment&gt;<br />&#160; &#160; &lt;target ...&gt; :: override &lt;variable-assignment&gt; (override作用参见 变量覆盖的介绍)</p><p>示例:<br /># Makefile 内容<br />SRCS := programA.c programB.c programC.c</p><p>target1: TARGET1-SRCS := programD.c<br />target1:<br />&#160; &#160; @echo &quot;SRCS: &quot; $(SRCS)<br />&#160; &#160; @echo &quot;SRCS: &quot; $(TARGET1-SRCS)</p><p>target2:<br />&#160; &#160; @echo &quot;SRCS: &quot; $(SRCS)<br />&#160; &#160; @echo &quot;SRCS: &quot; $(TARGET1-SRCS)</p><p># bash中执行make<br />$ make target1<br />SRCS:&#160; programA.c programB.c programC.c<br />SRCS:&#160; programD.c</p><p>$ make target2&#160; &#160; &#160;&lt;-- target2中显示不了 $(TARGET1-SRCS)<br />SRCS:&#160; programA.c programB.c programC.c<br />SRCS:</p><p>2.3 Makefile 命令前缀</p><p>Makefile 中书写shell命令时可以加2种前缀 @ 和 -, 或者不用前缀.</p><p>3种格式的shell命令区别如下:</p><p>&#160; &#160; 不用前缀 :: 输出执行的命令以及命令执行的结果, 出错的话停止执行<br />&#160; &#160; 前缀 @&#160; &#160;:: 只输出命令执行的结果, 出错的话停止执行<br />&#160; &#160; 前缀 -&#160; &#160;:: 命令执行有错的话, 忽略错误, 继续执行</p><p> </p><p>示例:<br /># Makefile 内容 (不用前缀)<br />all:<br />&#160; &#160; echo &quot;没有前缀&quot;<br />&#160; &#160; cat this_file_not_exist<br />&#160; &#160; echo &quot;错误之后的命令&quot;&#160; &#160; &#160; &#160;&lt;-- 这条命令不会被执行</p><p># bash中执行 make<br />$ make<br />echo &quot;没有前缀&quot;&#160; &#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 命令本身显示出来<br />没有前缀&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &lt;-- 命令执行结果显示出来<br />cat this_file_not_exist<br />cat: this_file_not_exist: No such file or directory<br />make: *** [all] Error 1</p><p>###########################################################</p><p># Makefile 内容 (前缀 @)<br />all:<br />&#160; &#160; @echo &quot;没有前缀&quot;<br />&#160; &#160; @cat this_file_not_exist<br />&#160; &#160; @echo &quot;错误之后的命令&quot;&#160; &#160; &#160; &#160;&lt;-- 这条命令不会被执行</p><p># bash中执行 make<br />$ make<br />没有前缀&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 只有命令执行的结果, 不显示命令本身<br />cat: this_file_not_exist: No such file or directory<br />make: *** [all] Error 1</p><p>###########################################################</p><p># Makefile 内容 (前缀 -)<br />all:<br />&#160; &#160; -echo &quot;没有前缀&quot;<br />&#160; &#160; -cat this_file_not_exist<br />&#160; &#160; -echo &quot;错误之后的命令&quot;&#160; &#160; &#160; &#160;&lt;-- 这条命令会被执行</p><p># bash中执行 make<br />$ make<br />echo &quot;没有前缀&quot;&#160; &#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 命令本身显示出来<br />没有前缀&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &lt;-- 命令执行结果显示出来<br />cat this_file_not_exist<br />cat: this_file_not_exist: No such file or directory<br />make: [all] Error 1 (ignored)<br />echo &quot;错误之后的命令&quot;&#160; &#160; &#160; &#160;&lt;-- 出错之后的命令也会显示<br />错误之后的命令&#160; &#160; &#160; &#160; &#160; &#160; &#160; &lt;-- 出错之后的命令也会执行</p><p> <br />2.4 伪目标</p><p>伪目标并不是一个&quot;目标(target)&quot;, 不像真正的目标那样会生成一个目标文件.</p><p>典型的伪目标是 Makefile 中用来清理编译过程中中间文件的 clean 伪目标, 一般格式如下:</p><p>.PHONY: clean&#160; &#160;&lt;-- 这句没有也行, 但是最好加上 <br />clean:<br /> -rm -f *.o</p><p> <br />2.5 引用其他的 Makefile</p><p>语法: include &lt;filename&gt;&#160; (filename 可以包含通配符和路径)</p><p>示例:</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo &quot;主 Makefile begin&quot;<br />&#160; &#160; @make other-all<br />&#160; &#160; @echo &quot;主 Makefile end&quot;</p><p>include ./other/Makefile</p><p># ./other/Makefile 内容<br />other-all:<br />&#160; &#160; @echo &quot;other makefile begin&quot;<br />&#160; &#160; @echo &quot;other makefile end&quot;</p><p># bash中执行 make<br />$ ll<br />total 20K<br />-rw-r--r-- 1 wangyubin wangyubin&#160; 125 Sep 23 16:13 Makefile<br />-rw-r--r-- 1 wangyubin wangyubin&#160; 11K Sep 23 16:15 makefile.org&#160; &#160;&lt;-- 这个文件不用管<br />drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 23 16:11 other<br />$ ll other/<br />total 4.0K<br />-rw-r--r-- 1 wangyubin wangyubin 71 Sep 23 16:11 Makefile</p><p>$ make<br />主 Makefile begin<br />make[1]: Entering directory `/path/to/test/makefile&#039;<br />other makefile begin<br />other makefile end<br />make[1]: Leaving directory `/path/to/test/makefile&#039;<br />主 Makefile end<br />2.6 查看C文件的依赖关系</p><p>写 Makefile 的时候, 需要确定每个目标的依赖关系.</p><p>GNU提供一个机制可以查看C代码文件依赖那些文件, 这样我们在写 Makefile 目标的时候就不用打开C源码来看其依赖那些文件了.</p><p>比如, 下面命令显示内核源码中 virt/kvm/kvm_main.c 中的依赖关系</p><p>$ cd virt/kvm/ <br />$ gcc -MM kvm_main.c&#160; <br />kvm_main.o: kvm_main.c iodev.h coalesced_mmio.h async_pf.h &lt;--这句就可以加到Makefile中作为编译kvm_main.o的依赖关系</p><p> <br />2.7 make 退出码</p><p>Makefile的退出码有以下3种：</p><p>&#160; &#160; 0 :: 表示成功执行<br />&#160; &#160; 1 :: 表示make命令出现了错误<br />&#160; &#160; 2 :: 使用了 &quot;-q&quot; 选项, 并且make使得一些目标不需要更新</p><p> <br />2.8 指定 Makefile， 指定特定目标</p><p>默认执行 make 命令时, GNU make在当前目录下依次搜索下面3个文件 &quot;GNUmakefile&quot;, &quot;makefile&quot;, &quot;Makefile&quot;,</p><p>找到对应文件之后, 就开始执行此文件中的第一个目标(target). 如果找不到这3个文件就报错.</p><p>非默认情况下, 可以在 make 命令中指定特定的 Makefile 和特定的 目标.</p><p>示例：</p><p># Makefile文件名改为 MyMake, 内容<br />target1:<br />&#160; &#160; @echo &quot;target [1]&#160; begin&quot;<br />&#160; &#160; @echo &quot;target [1]&#160; end&quot;</p><p>target2:<br />&#160; &#160; @echo &quot;target [2]&#160; begin&quot;<br />&#160; &#160; @echo &quot;target [2]&#160; end&quot;</p><p># bash 中执行 make<br />$ ls<br />Makefile<br />$ mv Makefile MyMake<br />$ ls<br />MyMake<br />$ make&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 找不到默认的 Makefile<br />make: *** No targets specified and no makefile found.&#160; Stop.<br />$ make -f MyMake&#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 指定特定的Makefile<br />target [1]&#160; begin<br />target [1]&#160; end<br />$ make -f MyMake target2&#160; &#160;&lt;-- 指定特定的目标(target)<br />target [2]&#160; begin<br />target [2]&#160; end<br />2.9 make 参数介绍</p><p>make 的参数有很多, 可以通过 make -h 去查看, 下面只介绍几个我认为比较有用的.</p><p>参数<br />&#160; &#160; </p><p>含义<br />--debug[=&lt;options&gt;] &#160; &#160; 输出make的调试信息, options 可以是 a, b, v<br />-j --jobs &#160; &#160; 同时运行的命令的个数, 也就是多线程执行 Makefile<br />-r --no-builtin-rules &#160; &#160; 禁止使用任何隐含规则<br />-R --no-builtin-variabes &#160; &#160; 禁止使用任何作用于变量上的隐含规则<br />-B --always-make &#160; &#160; 假设所有目标都有更新, 即强制重编译</p><p> <br />2.10 Makefile 隐含规则</p><p>这里只列一个和编译C相关的.</p><p>编译C时，&lt;n&gt;.o 的目标会自动推导为 &lt;n&gt;.c</p><p># Makefile 中<br />main : main.o<br />&#160; &#160; gcc -o main main.o</p><p>#会自动变为:<br />main : main.o<br />&#160; &#160; gcc -o main main.o</p><p>main.o: main.c&#160; &#160; &lt;-- main.o 这个目标是隐含生成的<br />&#160; &#160; gcc -c main.c<br />2.11 隐含规则中的 命令变量 和 命令参数变量<br />2.11.1 命令变量, 书写Makefile可以直接写 shell时用这些变量.</p><p>下面只列出一些C相关的</p><p>变量名<br />&#160; &#160; </p><p>含义<br />RM &#160; &#160; rm -f<br />AR &#160; &#160; ar<br />CC &#160; &#160; cc<br />CXX &#160; &#160; g++</p><p>示例:</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(RM)<br />&#160; &#160; @echo $(AR)<br />&#160; &#160; @echo $(CC)<br />&#160; &#160; @echo $(CXX)</p><p># bash 中执行make, 显示各个变量的值<br />$ make<br />rm -f<br />ar<br />cc<br />g++<br />2.11.2 命令参数变量</p><p>变量名<br />&#160; &#160; </p><p>含义<br />ARFLAGS &#160; &#160; AR命令的参数<br />CFLAGS &#160; &#160; C语言编译器的参数<br />CXXFLAGS &#160; &#160; C++语言编译器的参数</p><p> </p><p>示例: 下面以 CFLAGS 为例演示</p><p># test.c 内容<br />#include &lt;stdio.h&gt;</p><p>int main(int argc, char *argv[])<br />{<br />&#160; &#160; printf (&quot;Hello Makefile\n&quot;);<br />&#160; &#160; return 0;<br />}</p><p># Makefile 内容<br />test: test.o<br />&#160; &#160; $(CC) -o test test.o</p><p># bash 中用 make 来测试<br />$ ll<br />total 24K<br />-rw-r--r-- 1 wangyubin wangyubin&#160; 69 Sep 23 17:31 Makefile<br />-rw-r--r-- 1 wangyubin wangyubin 14K Sep 23 19:51 makefile.org&#160; &#160;&lt;-- 请忽略这个文件<br />-rw-r--r-- 1 wangyubin wangyubin 392 Sep 23 17:31 test.c</p><p>$ make<br />cc&#160; &#160; -c -o test.o test.c<br />cc -o test test.o&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 这个是自动推导的</p><p>$ rm -f test test.o</p><p>$ make CFLAGS=-Wall&#160; &#160; &#160; &#160; &#160; &#160; &#160;&lt;-- 命令中加的编译器参数自动追加入下面的编译中了<br />cc -Wall&#160; &#160;-c -o test.o test.c<br />cc -o test test.o<br />2.12 自动变量</p><p>Makefile 中很多时候通过自动变量来简化书写, 各个自动变量的含义如下:</p><p>自动变量<br />&#160; &#160; </p><p>含义<br />$@ &#160; &#160; 目标集合<br />$% &#160; &#160; 当目标是函数库文件时, 表示其中的目标文件名<br />$&lt; &#160; &#160; 第一个依赖目标. 如果依赖目标是多个, 逐个表示依赖目标<br />$? &#160; &#160; 比目标新的依赖目标的集合<br />$^ &#160; &#160; 所有依赖目标的集合, 会去除重复的依赖目标<br />$+ &#160; &#160; 所有依赖目标的集合, 不会去除重复的依赖目标<br />$* &#160; &#160; 这个是GNU make特有的, 其它的make不一定支持</p><p> <br />3. Makefile 高级语法<br />3.1 嵌套Makefile</p><p>在 Makefile 初级语法中已经提到过引用其它 Makefile的方法. 这里有另一种写法, 并且可以向引用的其它 Makefile 传递参数.</p><p>示例: (不传递参数, 只是调用子文件夹 other 中的Makefile)</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo &quot;主 Makefile begin&quot;<br />&#160; &#160; @cd ./other &amp;&amp; make<br />&#160; &#160; @echo &quot;主 Makefile end&quot;</p><br /><p># ./other/Makefile 内容<br />other-all:<br />&#160; &#160; @echo &quot;other makefile begin&quot;<br />&#160; &#160; @echo &quot;other makefile end&quot;</p><p># bash中执行 make<br />$ ll<br />total 28K<br />-rw-r--r-- 1 wangyubin wangyubin&#160; 104 Sep 23 20:43 Makefile<br />-rw-r--r-- 1 wangyubin wangyubin&#160; 17K Sep 23 20:44 makefile.org&#160; &#160;&lt;-- 这个文件不用管<br />drwxr-xr-x 2 wangyubin wangyubin 4.0K Sep 23 20:42 other<br />$ ll other/<br />total 4.0K<br />-rw-r--r-- 1 wangyubin wangyubin 71 Sep 23 16:11 Makefile</p><p>$ make<br />主 Makefile begin<br />make[1]: Entering directory `/path/to/test/makefile/other&#039;<br />other makefile begin<br />other makefile end<br />make[1]: Leaving directory `/path/to/test/makefile/other&#039;<br />主 Makefile end</p><p>示例: (用export传递参数)</p><p># Makefile 内容<br />export VALUE1 := export.c&#160; &#160; &lt;-- 用了 export, 此变量能够传递到 ./other/Makefile 中<br />VALUE2 := no-export.c&#160; &#160; &#160; &#160; &lt;-- 此变量不能传递到 ./other/Makefile 中</p><p>all:<br />&#160; &#160; @echo &quot;主 Makefile begin&quot;<br />&#160; &#160; @cd ./other &amp;&amp; make<br />&#160; &#160; @echo &quot;主 Makefile end&quot;</p><br /><p># ./other/Makefile 内容<br />other-all:<br />&#160; &#160; @echo &quot;other makefile begin&quot;<br />&#160; &#160; @echo &quot;VALUE1: &quot; $(VALUE1)<br />&#160; &#160; @echo &quot;VALUE2: &quot; $(VALUE2)<br />&#160; &#160; @echo &quot;other makefile end&quot;</p><p># bash中执行 make<br />$ make<br />主 Makefile begin<br />make[1]: Entering directory `/path/to/test/makefile/other&#039;<br />other makefile begin<br />VALUE1:&#160; export.c&#160; &#160; &#160; &#160; &lt;-- VALUE1 传递成功<br />VALUE2:&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &lt;-- VALUE2 传递失败<br />other makefile end<br />make[1]: Leaving directory `/path/to/test/makefile/other&#039;<br />主 Makefile end</p><p>补充* export 语法格式如下:</p><p>&#160; &#160; export variable = value<br />&#160; &#160; export variable := value<br />&#160; &#160; export variable += value</p><p> <br />3.2 定义命令包</p><p>命令包有点像是个函数, 将连续的相同的命令合成一条, 减少 Makefile 中的代码量, 便于以后维护.</p><p>语法:</p><p>define &lt;command-name&gt; <br />command<br />...<br />endef</p><p> </p><p>示例:</p><p># Makefile 内容<br />define run-hello-makefile<br />@echo -n &quot;Hello&quot;<br />@echo &quot; Makefile!&quot;<br />@echo &quot;这里可以执行多条 Shell 命令!&quot;<br />endef</p><p>all:<br />&#160; &#160; $(run-hello-makefile)</p><br /><p># bash 中运行make<br />$ make<br />Hello Makefile!<br />这里可以执行多条 Shell 命令!<br />3.3 条件判断</p><p>条件判断的关键字主要有 ifeq ifneq ifdef ifndef</p><p>语法:</p><p>&lt;conditional-directive&gt;<br />&lt;text-if-true&gt;<br />endif</p><p># 或者<br />&lt;conditional-directive&gt;<br />&lt;text-if-true&gt;<br />else<br />&lt;text-if-false&gt;<br />endif</p><br /><p>示例: ifeq的例子, ifneq和ifeq的使用方法类似, 就是取反</p><p># Makefile 内容<br />all:<br />ifeq (&quot;aa&quot;, &quot;bb&quot;)<br />&#160; &#160; @echo &quot;equal&quot;<br />else<br />&#160; &#160; @echo &quot;not equal&quot;<br />endif</p><p># bash 中执行 make<br />$ make<br />not equal</p><br /><p>示例: ifdef的例子, ifndef和ifdef的使用方法类似, 就是取反</p><p># Makefile 内容<br />SRCS := program.c</p><p>all:<br />ifdef SRCS<br />&#160; &#160; @echo $(SRCS)<br />else<br />&#160; &#160; @echo &quot;no SRCS&quot;<br />endif</p><p># bash 中执行 make<br />$ make<br />program.c</p><p> <br />3.4 Makefile 中的函数</p><p>Makefile 中自带了一些函数, 利用这些函数可以简化 Makefile 的编写.</p><p>函数调用语法如下:</p><p>$(&lt;function&gt; &lt;arguments&gt;) <br /># 或者 <br />${&lt;function&gt; &lt;arguments&gt;}</p><p>&#160; &#160; &lt;function&gt; 是函数名<br />&#160; &#160; &lt;arguments&gt; 是函数参数</p><p> <br />3.4.1 字符串函数</p><p>字符串替换函数: $(subst &lt;from&gt;,&lt;to&gt;,&lt;text&gt;)</p><p>功能: 把字符串&lt;text&gt; 中的 &lt;from&gt; 替换为 &lt;to&gt;</p><p>返回: 替换过的字符串</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(subst t,e,maktfilt)&#160; &lt;-- 将t替换为e</p><p># bash 中执行 make<br />$ make<br />makefile</p><p> </p><p>模式字符串替换函数: $(patsubst &lt;pattern&gt;,&lt;replacement&gt;,&lt;text&gt;)</p><p>功能: 查找&lt;text&gt;中的单词(单词以&quot;空格&quot;, &quot;tab&quot;, &quot;换行&quot;来分割) 是否符合 &lt;pattern&gt;, 符合的话, 用 &lt;replacement&gt; 替代.</p><p>返回: 替换过的字符串</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(patsubst %.c,%.o,programA.c programB.c)</p><p># bash 中执行 make<br />$ make<br />programA.o programB.o</p><p> </p><p>去空格函数: $(strip &lt;string&gt;)</p><p>功能: 去掉 &lt;string&gt; 字符串中开头和结尾的空字符</p><p>返回: 被去掉空格的字符串值</p><p> </p><p># Makefile 内容<br />VAL := &quot;&#160; &#160; &#160; &#160;aa&#160; bb&#160; cc &quot;</p><p>all:<br />&#160; &#160; @echo &quot;去除空格前: &quot; $(VAL)<br />&#160; &#160; @echo &quot;去除空格后: &quot; $(strip $(VAL))</p><p># bash 中执行 make<br />$ make<br />去除空格前:&#160; &#160; &#160; &#160; &#160;aa&#160; bb&#160; cc<br />去除空格后:&#160; &#160;aa bb cc</p><p> </p><p>查找字符串函数: $(findstring &lt;find&gt;,&lt;in&gt;)</p><p>功能: 在字符串 &lt;in&gt; 中查找 &lt;find&gt; 字符串</p><p>返回: 如果找到, 返回 &lt;find&gt; 字符串,&#160; 否则返回空字符串</p><p> </p><p># Makefile 内容<br />VAL := &quot;&#160; &#160; &#160; &#160;aa&#160; bb&#160; cc &quot;</p><p>all:<br />&#160; &#160; @echo $(findstring aa,$(VAL))<br />&#160; &#160; @echo $(findstring ab,$(VAL))</p><p># bash 中执行 make<br />$ make<br />aa</p><p> </p><p>过滤函数: $(filter &lt;pattern...&gt;,&lt;text&gt;)</p><p>功能: 以 &lt;pattern&gt; 模式过滤字符串 &lt;text&gt;, *保留* 符合模式 &lt;pattern&gt; 的单词, 可以有多个模式</p><p>返回: 符合模式 &lt;pattern&gt; 的字符串</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(filter %.o %.a,program.c program.o program.a)</p><br /><p># bash 中执行 make<br />$ make<br />program.o program.a</p><p> </p><p>反过滤函数: $(filter-out &lt;pattern...&gt;,&lt;text&gt;)</p><p>功能: 以 &lt;pattern&gt; 模式过滤字符串 &lt;text&gt;, *去除* 符合模式 &lt;pattern&gt; 的单词, 可以有多个模式</p><p>返回: 不符合模式 &lt;pattern&gt; 的字符串</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(filter-out %.o %.a,program.c program.o program.a)</p><p># bash 中执行 make<br />$ make<br />program.c</p><p> </p><p>排序函数: $(sort &lt;list&gt;)</p><p>功能: 给字符串 &lt;list&gt; 中的单词排序 (升序)</p><p>返回: 排序后的字符串</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(sort bac abc acb cab)</p><p># bash 中执行 make<br />$ make<br />abc acb bac cab</p><p> </p><p> </p><p>取单词函数: $(word &lt;n&gt;,&lt;text&gt;)</p><p>功能: 取字符串 &lt;text&gt; 中的 第&lt;n&gt;个单词 (n从1开始)</p><p>返回: &lt;text&gt; 中的第&lt;n&gt;个单词, 如果&lt;n&gt; 比 &lt;text&gt; 中单词个数要大, 则返回空字符串</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(word 1,aa bb cc dd)<br />&#160; &#160; @echo $(word 5,aa bb cc dd)<br />&#160; &#160; @echo $(word 4,aa bb cc dd)</p><p># bash 中执行 make<br />$ make<br />aa</p><p>dd</p><p>取单词串函数: $(wordlist &lt;s&gt;,&lt;e&gt;,&lt;text&gt;)</p><p>功能: 从字符串&lt;text&gt;中取从&lt;s&gt;开始到&lt;e&gt;的单词串. &lt;s&gt;和&lt;e&gt;是一个数字.</p><p>返回: 从&lt;s&gt;到&lt;e&gt;的字符串</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(wordlist 1,3,aa bb cc dd)<br />&#160; &#160; @echo $(word 5,6,aa bb cc dd)<br />&#160; &#160; @echo $(word 2,5,aa bb cc dd)</p><br /><p># bash 中执行 make<br />$ make<br />aa bb cc</p><p>bb</p><p>单词个数统计函数: $(words &lt;text&gt;)</p><p>功能: 统计字符串 &lt;text&gt; 中单词的个数</p><p>返回: 单词个数</p><p># Makefile 内容</p><p>all:<br />&#160; &#160; @echo $(words aa bb cc dd)<br />&#160; &#160; @echo $(words aabbccdd)<br />&#160; &#160; @echo $(words )</p><p># bash 中执行 make<br />$ make<br />1</p><p>首单词函数: $(firstword &lt;text&gt;)</p><p>功能: 取字符串 &lt;text&gt; 中的第一个单词</p><p>返回: 字符串 &lt;text&gt; 中的第一个单词</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(firstword aa bb cc dd)<br />&#160; &#160; @echo $(firstword aabbccdd)<br />&#160; &#160; @echo $(firstword )</p><p># bash 中执行 make<br />$ make<br />aa<br />aabbccdd</p><p> <br />3.4.2 文件名函数</p><p>取目录函数: $(dir &lt;names...&gt;)</p><p>功能: 从文件名序列 &lt;names&gt; 中取出目录部分</p><p>返回: 文件名序列 &lt;names&gt; 中的目录部分</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(dir /home/a.c ./bb.c ../c.c d.c)</p><br /><p># bash 中执行 make<br />$ make<br />/home/ ./ ../ ./</p><p> </p><p>取文件函数: $(notdir &lt;names...&gt;)</p><p>功能: 从文件名序列 &lt;names&gt; 中取出非目录部分</p><p>返回: 文件名序列 &lt;names&gt; 中的非目录部分</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(notdir /home/a.c ./bb.c ../c.c d.c)</p><p># bash 中执行 make<br />$ make<br />a.c bb.c c.c d.c</p><p> </p><p>取后缀函数: $(suffix &lt;names...&gt;)</p><p>功能: 从文件名序列 &lt;names&gt; 中取出各个文件名的后缀</p><p>返回: 文件名序列 &lt;names&gt; 中各个文件名的后缀, 没有后缀则返回空字符串</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(suffix /home/a.c ./b.o ../c.a d)</p><p># bash 中执行 make<br />$ make<br />.c .o .a</p><p> </p><p>取前缀函数: $(basename &lt;names...&gt;)</p><p>功能: 从文件名序列 &lt;names&gt; 中取出各个文件名的前缀</p><p>返回: 文件名序列 &lt;names&gt; 中各个文件名的前缀, 没有前缀则返回空字符串</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(basename /home/a.c ./b.o ../c.a /home/.d .e)</p><br /><p># bash 中执行 make<br />$ make<br />/home/a ./b ../c /home/</p><p> </p><p> </p><p>加后缀函数: $(addsuffix &lt;suffix&gt;,&lt;names...&gt;)</p><p>功能: 把后缀 &lt;suffix&gt; 加到 &lt;names&gt; 中的每个单词后面</p><p>返回: 加过后缀的文件名序列</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(addsuffix .c,/home/a b ./c.o ../d.c)</p><br /><p># bash 中执行 make<br />$ make<br />/home/a.c b.c ./c.o.c ../d.c.c</p><p>加前缀函数: $(addprefix &lt;prefix&gt;,&lt;names...&gt;)</p><p>功能: 把前缀 &lt;prefix&gt; 加到 &lt;names&gt; 中的每个单词前面</p><p>返回: 加过前缀的文件名序列</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(addprefix test_,/home/a.c b.c ./d.c)</p><p># bash 中执行 make<br />$ make<br />test_/home/a.c test_b.c test_./d.c</p><p>连接函数: $(join &lt;list1&gt;,&lt;list2&gt;)</p><p>功能: &lt;list2&gt; 中对应的单词加到 &lt;list1&gt; 后面</p><p>返回: 连接后的字符串</p><p># Makefile 内容<br />all:<br />&#160; &#160; @echo $(join a b c d,1 2 3 4)<br />&#160; &#160; @echo $(join a b c d,1 2 3 4 5)<br />&#160; &#160; @echo $(join a b c d e,1 2 3 4)</p><p># bash 中执行 make<br />$ make<br />a1 b2 c3 d4<br />a1 b2 c3 d4 5<br />a1 b2 c3 d4 e<br />3.4.3 foreach</p><p>语法:</p><p>$(foreach &lt;var&gt;,&lt;list&gt;,&lt;text&gt;)</p><p>示例:</p><p> </p><p># Makefile 内容<br />targets := a b c d<br />objects := $(foreach i,$(targets),$(i).o)</p><p>all:<br />&#160; &#160; @echo $(targets)<br />&#160; &#160; @echo $(objects)</p><p># bash 中执行 make<br />$ make<br />a b c d<br />a.o b.o c.o d.o</p><p> <br />3.4.4 if</p><p>这里的if是个函数, 和前面的条件判断不一样, 前面的条件判断属于Makefile的关键字</p><p>语法:</p><p>$(if &lt;condition&gt;,&lt;then-part&gt;)</p><p>$(if &lt;condition&gt;,&lt;then-part&gt;,&lt;else-part&gt;)</p><p>示例:</p><p> </p><p># Makefile 内容<br />val := a<br />objects := $(if $(val),$(val).o,nothing)<br />no-objects := $(if $(no-val),$(val).o,nothing)</p><p>all:<br />&#160; &#160; @echo $(objects)<br />&#160; &#160; @echo $(no-objects)</p><p># bash 中执行 make<br />$ make<br />a.o<br />nothing</p><p> <br />3.4.5 call - 创建新的参数化函数</p><p>语法:</p><p>$(call &lt;expression&gt;,&lt;parm1&gt;,&lt;parm2&gt;,&lt;parm3&gt;...)</p><p>示例:</p><p> </p><p># Makefile 内容<br />log = &quot;====debug====&quot; $(1) &quot;====end====&quot;</p><p>all:<br />&#160; &#160; @echo $(call log,&quot;正在 Make&quot;)</p><p># bash 中执行 make<br />$ make<br />====debug==== 正在 Make ====end====</p><p> <br />3.4.6 origin - 判断变量的来源</p><p>语法:</p><p>$(origin &lt;variable&gt;)</p><p>返回值有如下类型:</p><p>类型<br />&#160; &#160; </p><p>含义<br />undefined &#160; &#160; &lt;variable&gt; 没有定义过<br />default &#160; &#160; &lt;variable&gt; 是个默认的定义, 比如 CC 变量<br />environment &#160; &#160; &lt;variable&gt; 是个环境变量, 并且 make时没有使用 -e 参数<br />file &#160; &#160; &lt;variable&gt; 定义在Makefile中<br />command line &#160; &#160; &lt;variable&gt; 定义在命令行中<br />override &#160; &#160; &lt;variable&gt; 被 override 重新定义过<br />automatic &#160; &#160; &lt;variable&gt; 是自动化变量</p><p> </p><p>示例:</p><p> </p><p># Makefile 内容<br />val-in-file := test-file<br />override val-override := test-override</p><p>all:<br />&#160; &#160; @echo $(origin not-define)&#160; &#160; # not-define 没有定义<br />&#160; &#160; @echo $(origin CC)&#160; &#160; &#160; &#160; &#160; &#160; # CC 是Makefile默认定义的变量<br />&#160; &#160; @echo $(origin PATH)&#160; &#160; &#160; &#160; &#160;# PATH 是 bash 环境变量<br />&#160; &#160; @echo $(origin val-in-file)&#160; &#160; # 此Makefile中定义的变量<br />&#160; &#160; @echo $(origin val-in-cmd)&#160; &#160; # 这个变量会加在 make 的参数中<br />&#160; &#160; @echo $(origin val-override) # 此Makefile中定义的override变量<br />&#160; &#160; @echo $(origin @)&#160; &#160; &#160; &#160; &#160; &#160; &#160;# 自动变量, 具体前面的介绍</p><p># bash 中执行 make<br />$ make val-in-cmd=val-cmd<br />undefined<br />default<br />environment<br />file<br />command line<br />override<br />automatic</p><p> <br />3.4.7 shell</p><p>语法:</p><p>$(shell &lt;shell command&gt;)</p><p>它的作用就是执行一个shell命令, 并将shell命令的结果作为函数的返回.</p><p>作用和 `&lt;shell command&gt;` 一样, ` 是反引号</p><p> <br />3.4.8 make 控制函数</p><p>产生一个致命错误: $(error &lt;text ...&gt;)</p><p>功能: 输出错误信息, 停止Makefile的运行</p><p> </p><p># Makefile 内容<br />all:<br />&#160; &#160; $(error there is an error!)<br />&#160; &#160; @echo &quot;这里不会执行!&quot;</p><p># bash 中执行 make<br />$ make<br />Makefile:2: *** there is an error!.&#160; Stop.</p><p> </p><p>输出警告: $(warning &lt;text ...&gt;)</p><p>功能: 输出警告信息, Makefile继续运行</p><p># Makefile 内容<br />all:<br />&#160; &#160; $(warning there is an warning!)<br />&#160; &#160; @echo &quot;这里会执行!&quot;</p><p># bash 中执行 make<br />$ make<br />Makefile:2: there is an warning!<br />这里会执行!<br />3.5 Makefile中一些GNU约定俗成的伪目标</p><p>如果有过在Linux上, 从源码安装软件的经历的话, 就会对 make clean, make install 比较熟悉.</p><p>像 clean, install 这些伪目标, 广为人知, 不用解释就大家知道是什么意思了.</p><p>下面列举一些常用的伪目标, 如果在自己项目的Makefile合理使用这些伪目标的话, 可以让我们自己的Makefile看起来更专业, 呵呵 <img src="https://www.gentoo-zh.org/img/smilies/smile.png" width="15" height="15" alt="smile" /></p><p>伪目标<br />&#160; &#160; </p><p>含义<br />all &#160; &#160; 所有目标的目标，其功能一般是编译所有的目标<br />clean &#160; &#160; 删除所有被make创建的文件<br />install &#160; &#160; 安装已编译好的程序，其实就是把目标可执行文件拷贝到指定的目录中去<br />print &#160; &#160; 列出改变过的源文件<br />tar &#160; &#160; 把源程序打包备份. 也就是一个tar文件<br />dist &#160; &#160; 创建一个压缩文件, 一般是把tar文件压成Z文件. 或是gz文件<br />TAGS &#160; &#160; 更新所有的目标, 以备完整地重编译使用<br />check 或 test &#160; &#160; 一般用来测试makefile的流程</p>]]></description>
			<author><![CDATA[dummy@example.com (batsom)]]></author>
			<pubDate>Mon, 07 Nov 2022 04:55:52 +0000</pubDate>
			<guid>https://www.gentoo-zh.org/viewtopic.php?pid=537#p537</guid>
		</item>
	</channel>
</rss>
