how-to-write-makefile/variables.html

447 lines
40 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html class="writer-html5" lang="zh-CN" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>使用变量 &mdash; 跟我一起写Makefile 1.0 文档</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/translations.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="索引" href="genindex.html" />
<link rel="search" title="搜索" href="search.html" />
<link rel="next" title="使用条件判断" href="conditionals.html" />
<link rel="prev" title="书写命令" href="recipes.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> 跟我一起写Makefile
</a>
<div class="version">
1.0
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">目录</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="overview.html">概述</a></li>
<li class="toctree-l1"><a class="reference internal" href="introduction.html">makefile介绍</a></li>
<li class="toctree-l1"><a class="reference internal" href="rules.html">书写规则</a></li>
<li class="toctree-l1"><a class="reference internal" href="recipes.html">书写命令</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">使用变量</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#id2">变量的基础</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id3">变量中的变量</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id4">变量高级用法</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id5">追加变量值</a></li>
<li class="toctree-l2"><a class="reference internal" href="#override">override 指示符</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id6">多行变量</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id7">环境变量</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id8">目标变量</a></li>
<li class="toctree-l2"><a class="reference internal" href="#id9">模式变量</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="conditionals.html">使用条件判断</a></li>
<li class="toctree-l1"><a class="reference internal" href="functions.html">使用函数</a></li>
<li class="toctree-l1"><a class="reference internal" href="invoke.html">make 的运行</a></li>
<li class="toctree-l1"><a class="reference internal" href="implicit_rules.html">隐含规则</a></li>
<li class="toctree-l1"><a class="reference internal" href="archives.html">使用make更新函数库文件</a></li>
<li class="toctree-l1"><a class="reference internal" href="postscript.html">后序</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">跟我一起写Makefile</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>使用变量</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/variables.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="id1">
<h1>使用变量<a class="headerlink" href="#id1" title="永久链接至标题"></a></h1>
<p>在Makefile中的定义的变量就像是C/C++语言中的宏一样他代表了一个文本字串在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是你可以在Makefile中改变其值。在Makefile中变量可以使用在“目标”“依赖目标” “命令”或是Makefile的其它部分中。</p>
<p>变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有 <code class="docutils literal notranslate"><span class="pre">:</span></code><code class="docutils literal notranslate"><span class="pre">#</span></code>
<code class="docutils literal notranslate"><span class="pre">=</span></code> 或是空字符空格、回车等。变量是大小写敏感的“foo”、“Foo”和“FOO”是三个不同的变量名。传统的Makefile的变量名是全大写的命名方式但我推荐使用大小写搭配的变量名MakeFlags。这样可以避免和系统的变量冲突而发生意外的事情。</p>
<p>有一些变量是很奇怪字串,如 <code class="docutils literal notranslate"><span class="pre">$&lt;</span></code><code class="docutils literal notranslate"><span class="pre">$&#64;</span></code> 等,这些是自动化变量,我会在后面介绍。</p>
<section id="id2">
<h2>变量的基础<a class="headerlink" href="#id2" title="永久链接至标题"></a></h2>
<p>变量在声明时需要给予初值,而在使用时,需要给在变量名前加上 <code class="docutils literal notranslate"><span class="pre">$</span></code> 符号,但最好用小括号
<code class="docutils literal notranslate"><span class="pre">()</span></code> 或是大括号 <code class="docutils literal notranslate"><span class="pre">{}</span></code> 把变量给包括起来。如果你要使用真实的 <code class="docutils literal notranslate"><span class="pre">$</span></code> 字符,那么你需要用
<code class="docutils literal notranslate"><span class="pre">$$</span></code> 来表示。</p>
<p>变量可以使用在许多地方,如规则中的“目标”、“依赖”、“命令”以及新的变量中。先看一个例子:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">objects</span> <span class="o">=</span> program.o foo.o utils.o
<span class="nf">program </span><span class="o">:</span> <span class="k">$(</span><span class="nv">objects</span><span class="k">)</span>
cc -o program <span class="k">$(</span>objects<span class="k">)</span>
<span class="nf">$(objects) </span><span class="o">:</span> <span class="n">defs</span>.<span class="n">h</span>
</pre></div>
</div>
<p>变量会在使用它的地方精确地展开就像C/C++中的宏一样,例如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">foo</span> <span class="o">=</span> c
<span class="nf">prog.o </span><span class="o">:</span> <span class="n">prog</span>.<span class="k">$(</span><span class="nv">foo</span><span class="k">)</span>
<span class="k">$(</span>foo<span class="k">)$(</span>foo<span class="k">)</span> -<span class="k">$(</span>foo<span class="k">)</span> prog.<span class="k">$(</span>foo<span class="k">)</span>
</pre></div>
</div>
<p>展开后得到:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nf">prog.o </span><span class="o">:</span> <span class="n">prog</span>.<span class="n">c</span>
cc -c prog.c
</pre></div>
</div>
<p>当然千万不要在你的Makefile中这样干这里只是举个例子来表明Makefile中的变量在使用处展开的真实样子。可见其就是一个“替代”的原理。</p>
<p>另外,给变量加上括号完全是为了更加安全地使用这个变量,在上面的例子中,如果你不想给变量加上括号,那也可以,但我还是强烈建议你给变量加上括号。</p>
</section>
<section id="id3">
<h2>变量中的变量<a class="headerlink" href="#id3" title="永久链接至标题"></a></h2>
<p>在定义变量的值时我们可以使用其它变量来构造变量的值在Makefile中有两种方式来在用变量定义变量的值。</p>
<p>先看第一种方式,也就是简单的使用 <code class="docutils literal notranslate"><span class="pre">=</span></code> 号,在 <code class="docutils literal notranslate"><span class="pre">=</span></code> 左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">foo</span> <span class="o">=</span> <span class="k">$(</span>bar<span class="k">)</span>
<span class="nv">bar</span> <span class="o">=</span> <span class="k">$(</span>ugh<span class="k">)</span>
<span class="nv">ugh</span> <span class="o">=</span> Huh?
<span class="nf">all</span><span class="o">:</span>
<span class="nb">echo</span> <span class="k">$(</span>foo<span class="k">)</span>
</pre></div>
</div>
<p>我们执行“make all”将会打出变量 <code class="docutils literal notranslate"><span class="pre">$(foo)</span></code> 的值是 <code class="docutils literal notranslate"><span class="pre">Huh?</span></code> <code class="docutils literal notranslate"><span class="pre">$(foo)</span></code> 的值是
<code class="docutils literal notranslate"><span class="pre">$(bar)</span></code> <code class="docutils literal notranslate"><span class="pre">$(bar)</span></code> 的值是 <code class="docutils literal notranslate"><span class="pre">$(ugh)</span></code> <code class="docutils literal notranslate"><span class="pre">$(ugh)</span></code> 的值是 <code class="docutils literal notranslate"><span class="pre">Huh?</span></code> )可见,变量是可以使用后面的变量来定义的。</p>
<p>这个功能有好的地方,也有不好的地方,好的地方是,我们可以把变量的真实值推到后面来定义,如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">CFLAGS</span> <span class="o">=</span> <span class="k">$(</span>include_dirs<span class="k">)</span> -O
<span class="nv">include_dirs</span> <span class="o">=</span> -Ifoo -Ibar
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">CFLAGS</span></code> 在命令中被展开时,会是 <code class="docutils literal notranslate"><span class="pre">-Ifoo</span> <span class="pre">-Ibar</span> <span class="pre">-O</span></code> 。但这种形式也有不好的地方,那就是递归定义,如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">CFLAGS</span> <span class="o">=</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -O
</pre></div>
</div>
<p>或:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">A</span> <span class="o">=</span> <span class="k">$(</span>B<span class="k">)</span>
<span class="nv">B</span> <span class="o">=</span> <span class="k">$(</span>A<span class="k">)</span>
</pre></div>
</div>
<p>这会让make陷入无限的变量展开过程中去当然我们的make是有能力检测这样的定义并会报错。还有就是如果在变量中使用函数那么这种方式会让我们的make运行时非常慢更糟糕的是他会使用得两个make的函数“wildcard”和“shell”发生不可预知的错误。因为你不会知道这两个函数会被调用多少次。</p>
<p>为了避免上面的这种方法我们可以使用make中的另一种用变量来定义变量的方法。这种方法使用的是 <code class="docutils literal notranslate"><span class="pre">:=</span></code> 操作符,如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">x</span> <span class="o">:=</span> foo
<span class="nv">y</span> <span class="o">:=</span> <span class="k">$(</span>x<span class="k">)</span> bar
<span class="nv">x</span> <span class="o">:=</span> later
</pre></div>
</div>
<p>其等价于:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">y</span> <span class="o">:=</span> foo bar
<span class="nv">x</span> <span class="o">:=</span> later
</pre></div>
</div>
<p>值得一提的是,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是这样:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">y</span> <span class="o">:=</span> <span class="k">$(</span>x<span class="k">)</span> bar
<span class="nv">x</span> <span class="o">:=</span> foo
</pre></div>
</div>
<p>那么y的值是“bar”而不是“foo bar”。</p>
<p>上面都是一些比较简单的变量使用了让我们来看一个复杂的例子其中包括了make的函数、条件表达式和一个系统变量“MAKELEVEL”的使用</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="cp">ifeq (0,${MAKELEVEL})</span>
<span class="nv">cur-dir</span> <span class="o">:=</span> <span class="k">$(</span>shell <span class="nb">pwd</span><span class="k">)</span>
<span class="nv">whoami</span> <span class="o">:=</span> <span class="k">$(</span>shell whoami<span class="k">)</span>
<span class="nv">host-type</span> <span class="o">:=</span> <span class="k">$(</span>shell arch<span class="k">)</span>
<span class="nv">MAKE</span> <span class="o">:=</span> <span class="si">${</span><span class="nv">MAKE</span><span class="si">}</span> host-type<span class="o">=</span><span class="si">${</span><span class="nv">host</span><span class="p">-type</span><span class="si">}</span> <span class="nv">whoami</span><span class="o">=</span><span class="si">${</span><span class="nv">whoami</span><span class="si">}</span>
<span class="cp">endif</span>
</pre></div>
</div>
<p>关于条件表达式和函数我们在后面再说对于系统变量“MAKELEVEL”其意思是如果我们的make有一个嵌套执行的动作参见前面的“嵌套使用make”那么这个变量会记录了我们的当前Makefile的调用层数。</p>
<p>下面再介绍两个定义变量时我们需要知道的,请先看一个例子,如果我们要定义一个变量,其值是一个空格,那么我们可以这样来:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">nullstring</span> <span class="o">:=</span>
<span class="nv">space</span> <span class="o">:=</span> <span class="k">$(</span>nullstring<span class="k">)</span> <span class="c1"># end of the line</span>
</pre></div>
</div>
<p>nullstring是一个Empty变量其中什么也没有而我们的space的值是一个空格。因为在操作符的右边是很难描述一个空格的这里采用的技术很管用先用一个Empty变量来标明变量的值开始了而后面采用“#”注释符来表示变量定义的终止,这样,我们可以定义出其值是一个空格的变量。请注意这里关于“#”的使用,注释符“#”的这种特性值得我们注意,如果我们这样定义一个变量:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">dir</span> <span class="o">:=</span> /foo/bar <span class="c1"># directory to put the frobs in</span>
</pre></div>
</div>
<p>dir这个变量的值是“/foo/bar”后面还跟了4个空格如果我们这样使用这样变量来指定别的目录——“$(dir)/file”那么就完蛋了。</p>
<p>还有一个比较有用的操作符是 <code class="docutils literal notranslate"><span class="pre">?=</span></code> ,先看示例:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">FOO</span> <span class="o">?=</span> bar
</pre></div>
</div>
<p>其含义是如果FOO没有被定义过那么变量FOO的值就是“bar”如果FOO先前被定义过那么这条语将什么也不做其等价于</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="cp">ifeq ($(origin FOO), undefined)</span>
<span class="nv">FOO</span> <span class="o">=</span> bar
<span class="cp">endif</span>
</pre></div>
</div>
</section>
<section id="id4">
<h2>变量高级用法<a class="headerlink" href="#id4" title="永久链接至标题"></a></h2>
<p>这里介绍两种变量的高级使用方法,第一种是变量值的替换。</p>
<p>我们可以替换变量中的共有的部分,其格式是 <code class="docutils literal notranslate"><span class="pre">$(var:a=b)</span></code> 或是 <code class="docutils literal notranslate"><span class="pre">${var:a=b}</span></code> 其意思是把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。</p>
<p>还是看一个示例吧:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">foo</span> <span class="o">:=</span> a.o b.o c.o
<span class="nv">bar</span> <span class="o">:=</span> <span class="k">$(</span>foo:.o<span class="o">=</span>.c<span class="k">)</span>
</pre></div>
</div>
<p>这个示例中,我们先定义了一个 <code class="docutils literal notranslate"><span class="pre">$(foo)</span></code> 变量,而第二行的意思是把 <code class="docutils literal notranslate"><span class="pre">$(foo)</span></code> 中所有以
<code class="docutils literal notranslate"><span class="pre">.o</span></code> 字串“结尾”全部替换成 <code class="docutils literal notranslate"><span class="pre">.c</span></code> ,所以我们的 <code class="docutils literal notranslate"><span class="pre">$(bar)</span></code> 的值就是“a.c b.c c.c”。</p>
<p>另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">foo</span> <span class="o">:=</span> a.o b.o c.o
<span class="nv">bar</span> <span class="o">:=</span> <span class="k">$(</span>foo:%.o<span class="o">=</span>%.c<span class="k">)</span>
</pre></div>
</div>
<p>这依赖于被替换字串中的有相同的模式,模式中必须包含一个 <code class="docutils literal notranslate"><span class="pre">%</span></code> 字符,这个例子同样让
<code class="docutils literal notranslate"><span class="pre">$(bar)</span></code> 变量的值为“a.c b.c c.c”。</p>
<p>第二种高级用法是——“把变量的值再当成变量”。先看一个例子:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">x</span> <span class="o">=</span> y
<span class="nv">y</span> <span class="o">=</span> z
<span class="nv">a</span> <span class="o">:=</span> <span class="k">$($(</span>x<span class="k">))</span>
</pre></div>
</div>
<p>在这个例子中,$(x)的值是“y”所以$($(x))就是$(y),于是$(a)的值就是“z”。注意是“x=y”而不是“x=$(y)”)</p>
<p>我们还可以使用更多的层次:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">x</span> <span class="o">=</span> y
<span class="nv">y</span> <span class="o">=</span> z
<span class="nv">z</span> <span class="o">=</span> u
<span class="nv">a</span> <span class="o">:=</span> <span class="k">$($($(</span>x<span class="k">)))</span>
</pre></div>
</div>
<p>这里的 <code class="docutils literal notranslate"><span class="pre">$(a)</span></code> 的值是“u”相关的推导留给读者自己去做吧。</p>
<p>让我们再复杂一点,使用上“在变量定义中使用变量”的第一个方式,来看一个例子:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">x</span> <span class="o">=</span> <span class="k">$(</span>y<span class="k">)</span>
<span class="nv">y</span> <span class="o">=</span> z
<span class="nv">z</span> <span class="o">=</span> Hello
<span class="nv">a</span> <span class="o">:=</span> <span class="k">$($(</span>x<span class="k">))</span>
</pre></div>
</div>
<p>这里的 <code class="docutils literal notranslate"><span class="pre">$($(x))</span></code> 被替换成了 <code class="docutils literal notranslate"><span class="pre">$($(y))</span></code> ,因为 <code class="docutils literal notranslate"><span class="pre">$(y)</span></code> 值是“z”所以最终结果是
<code class="docutils literal notranslate"><span class="pre">a:=$(z)</span></code> 也就是“Hello”。</p>
<p>再复杂一点,我们再加上函数:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">x</span> <span class="o">=</span> variable1
<span class="nv">variable2</span> <span class="o">:=</span> Hello
<span class="nv">y</span> <span class="o">=</span> <span class="k">$(</span>subst <span class="m">1</span>,2,<span class="k">$(</span>x<span class="k">))</span>
<span class="nv">z</span> <span class="o">=</span> y
<span class="nv">a</span> <span class="o">:=</span> <span class="k">$($($(</span>z<span class="k">)))</span>
</pre></div>
</div>
<p>这个例子中, <code class="docutils literal notranslate"><span class="pre">$($($(z)))</span></code> 扩展为 <code class="docutils literal notranslate"><span class="pre">$($(y))</span></code> ,而其再次被扩展为
<code class="docutils literal notranslate"><span class="pre">$($(subst</span> <span class="pre">1,2,$(x)))</span></code><code class="docutils literal notranslate"><span class="pre">$(x)</span></code> 的值是“variable1”subst函数把“variable1”中的所有“1”字串替换成“2”字串于是“variable1”变成 “variable2”再取其值所以最终
<code class="docutils literal notranslate"><span class="pre">$(a)</span></code> 的值就是 <code class="docutils literal notranslate"><span class="pre">$(variable2)</span></code> 的值——“Hello”。好不容易</p>
<p>在这种方式中,或要可以使用多个变量来组成一个变量的名字,然后再取其值:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">first_second</span> <span class="o">=</span> Hello
<span class="nv">a</span> <span class="o">=</span> first
<span class="nv">b</span> <span class="o">=</span> second
<span class="nv">all</span> <span class="o">=</span> <span class="k">$(</span><span class="nv">$a_$b</span><span class="k">)</span>
</pre></div>
</div>
<p>这里的 <code class="docutils literal notranslate"><span class="pre">$a_$b</span></code> 组成了“first_second”于是 <code class="docutils literal notranslate"><span class="pre">$(all)</span></code> 的值就是“Hello”。</p>
<p>再来看看结合第一种技术的例子:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">a_objects</span> <span class="o">:=</span> a.o b.o c.o
<span class="nv">1_objects</span> <span class="o">:=</span> <span class="m">1</span>.o <span class="m">2</span>.o <span class="m">3</span>.o
<span class="nv">sources</span> <span class="o">:=</span> <span class="k">$($(</span>a1<span class="k">)</span>_objects:.o<span class="o">=</span>.c<span class="k">)</span>
</pre></div>
</div>
<p>这个例子中,如果 <code class="docutils literal notranslate"><span class="pre">$(a1)</span></code> 的值是“a”的话那么 <code class="docutils literal notranslate"><span class="pre">$(sources)</span></code> 的值就是“a.c b.c c.c”如果 <code class="docutils literal notranslate"><span class="pre">$(a1)</span></code> 的值是“1”那么 <code class="docutils literal notranslate"><span class="pre">$(sources)</span></code> 的值是“1.c 2.c 3.c”。</p>
<p>再来看一个这种技术和“函数”与“条件语句”一同使用的例子:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="cp">ifdef do_sort</span>
func :<span class="o">=</span> sort
<span class="cp">else</span>
func :<span class="o">=</span> strip
<span class="cp">endif</span>
<span class="nv">bar</span> <span class="o">:=</span> a d b g q c
<span class="nv">foo</span> <span class="o">:=</span> <span class="k">$($(</span>func<span class="k">)</span> <span class="k">$(</span>bar<span class="k">))</span>
</pre></div>
</div>
<p>这个示例中如果定义了“do_sort”那么 <code class="docutils literal notranslate"><span class="pre">foo</span> <span class="pre">:=</span> <span class="pre">$(sort</span> <span class="pre">a</span> <span class="pre">d</span> <span class="pre">b</span> <span class="pre">g</span> <span class="pre">q</span> <span class="pre">c)</span></code> ,于是
<code class="docutils literal notranslate"><span class="pre">$(foo)</span></code> 的值就是 “a b c d g q”而如果没有定义“do_sort”那么
<code class="docutils literal notranslate"><span class="pre">foo</span> <span class="pre">:=</span> <span class="pre">$(strip</span> <span class="pre">a</span> <span class="pre">d</span> <span class="pre">b</span> <span class="pre">g</span> <span class="pre">q</span> <span class="pre">c)</span></code> 调用的就是strip函数。</p>
<p>当然,“把变量的值再当成变量”这种技术,同样可以用在操作符的左边:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(dir)_print
lpr $($(dir)_sources)
endef
</pre></div>
</div>
<p>这个例子中定义了三个变量“dir”“foo_sources”和“foo_print”。</p>
</section>
<section id="id5">
<h2>追加变量值<a class="headerlink" href="#id5" title="永久链接至标题"></a></h2>
<p>我们可以使用 <code class="docutils literal notranslate"><span class="pre">+=</span></code> 操作符给变量追加值,如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">objects</span> <span class="o">=</span> main.o foo.o bar.o utils.o
<span class="nv">objects</span> <span class="o">+=</span> another.o
</pre></div>
</div>
<p>于是,我们的 <code class="docutils literal notranslate"><span class="pre">$(objects)</span></code> 值变成“main.o foo.o bar.o utils.o another.o”another.o被追加进去了</p>
<p>使用 <code class="docutils literal notranslate"><span class="pre">+=</span></code> 操作符,可以模拟为下面的这种例子:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">objects</span> <span class="o">=</span> main.o foo.o bar.o utils.o
<span class="nv">objects</span> <span class="o">:=</span> <span class="k">$(</span>objects<span class="k">)</span> another.o
</pre></div>
</div>
<p>所不同的是,用 <code class="docutils literal notranslate"><span class="pre">+=</span></code> 更为简洁。</p>
<p>如果变量之前没有定义过,那么, <code class="docutils literal notranslate"><span class="pre">+=</span></code> 会自动变成 <code class="docutils literal notranslate"><span class="pre">=</span></code> ,如果前面有变量定义,那么 <code class="docutils literal notranslate"><span class="pre">+=</span></code> 会继承于前次操作的赋值符。如果前一次的是 <code class="docutils literal notranslate"><span class="pre">:=</span></code> ,那么 <code class="docutils literal notranslate"><span class="pre">+=</span></code> 会以 <code class="docutils literal notranslate"><span class="pre">:=</span></code> 作为其赋值符,如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">variable</span> <span class="o">:=</span> value
<span class="nv">variable</span> <span class="o">+=</span> more
</pre></div>
</div>
<p>等价于:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">variable</span> <span class="o">:=</span> value
<span class="nv">variable</span> <span class="o">:=</span> <span class="k">$(</span>variable<span class="k">)</span> more
</pre></div>
</div>
<p>但如果是这种情况:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nv">variable</span> <span class="o">=</span> value
<span class="nv">variable</span> <span class="o">+=</span> more
</pre></div>
</div>
<p>由于前次的赋值符是 <code class="docutils literal notranslate"><span class="pre">=</span></code> ,所以 <code class="docutils literal notranslate"><span class="pre">+=</span></code> 也会以 <code class="docutils literal notranslate"><span class="pre">=</span></code> 来做为赋值那么岂不会发生变量的递补归定义这是很不好的所以make会自动为我们解决这个问题我们不必担心这个问题。</p>
</section>
<section id="override">
<h2>override 指示符<a class="headerlink" href="#override" title="永久链接至标题"></a></h2>
<p>如果有变量是通常make的命令行参数设置的那么Makefile中对这个变量的赋值会被忽略。如果你想在Makefile中设置这类参数的值那么你可以使用“override”指示符。其语法是:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">override</span> <span class="o">&lt;</span><span class="n">variable</span><span class="o">&gt;</span><span class="p">;</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">value</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">override</span> <span class="o">&lt;</span><span class="n">variable</span><span class="o">&gt;</span><span class="p">;</span> <span class="o">:=</span> <span class="o">&lt;</span><span class="n">value</span><span class="o">&gt;</span><span class="p">;</span>
</pre></div>
</div>
<p>当然,你还可以追加:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">override</span> <span class="o">&lt;</span><span class="n">variable</span><span class="o">&gt;</span><span class="p">;</span> <span class="o">+=</span> <span class="o">&lt;</span><span class="n">more</span> <span class="n">text</span><span class="o">&gt;</span><span class="p">;</span>
</pre></div>
</div>
<p>对于多行的变量定义我们用define指示符在define指示符前也同样可以使用override指示符如:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">override</span> <span class="n">define</span> <span class="n">foo</span>
<span class="n">bar</span>
<span class="n">endef</span>
</pre></div>
</div>
</section>
<section id="id6">
<h2>多行变量<a class="headerlink" href="#id6" title="永久链接至标题"></a></h2>
<p>还有一种设置变量值的方法是使用define关键字。使用define关键字设置变量的值可以有换行这有利于定义一系列的命令前面我们讲过“命令包”的技术就是利用这个关键字</p>
<p>define指示符后面跟的是变量的名字而重起一行定义变量的值定义是以endef 关键字结束。其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开头所以如果你用define定义的命令变量中没有以 <code class="docutils literal notranslate"><span class="pre">Tab</span></code> 键开头那么make 就不会把其认为是命令。</p>
<p>下面的这个示例展示了define的用法:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>define two-lines
echo foo
echo $(bar)
endef
</pre></div>
</div>
</section>
<section id="id7">
<h2>环境变量<a class="headerlink" href="#id7" title="永久链接至标题"></a></h2>
<p>make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中但是如果Makefile中已定义了这个变量或是这个变量由make命令行带入那么系统的环境变量的值将被覆盖。如果make指定了“-e”参数那么系统环境变量将覆盖Makefile中定义的变量</p>
<p>因此,如果我们在环境变量中设置了 <code class="docutils literal notranslate"><span class="pre">CFLAGS</span></code> 环境变量那么我们就可以在所有的Makefile中使用这个变量了。这对于我们使用统一的编译参数有比较大的好处。如果Makefile中定义了CFLAGS那么则会使用Makefile中的这个变量如果没有定义则使用系统环境变量的值一个共性和个性的统一很像“全局变量”和“局部变量”的特性。</p>
<p>当make嵌套调用时参见前面的“嵌套调用”章节上层Makefile中定义的变量会以系统环境变量的方式传递到下层的Makefile 中。当然默认情况下只有通过命令行设置的变量会被传递。而定义在文件中的变量如果要向下层Makefile传递则需要使用export关键字来声明。参见前面章节</p>
<p>当然我并不推荐把许多的变量都定义在系统环境中这样在我们执行不用的Makefile时拥有的是同一套系统变量这可能会带来更多的麻烦。</p>
</section>
<section id="id8">
<h2>目标变量<a class="headerlink" href="#id8" title="永久链接至标题"></a></h2>
<p>前面我们所讲的在Makefile中定义的变量都是“全局变量”在整个文件我们都可以访问这些变量。当然“自动化变量”除外<code class="docutils literal notranslate"><span class="pre">$&lt;</span></code> 等这种类量的自动化变量就属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。</p>
<p>当然我也同样可以为某个目标设置局部变量这种变量被称为“Target-specific Variable”它可以和“全局变量”同名因为它的作用范围只在这条规则以及连带规则中所以其值也只在作用范围内有效。而不会影响规则链以外的全局变量的值。</p>
<p>其语法是:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nf">&lt;target ...&gt; </span><span class="o">:</span> &lt;<span class="n">variable</span>-<span class="n">assignment</span>&gt;;
<span class="nf">&lt;target ...&gt; </span><span class="o">:</span> <span class="n">overide</span> &lt;<span class="n">variable</span>-<span class="n">assignment</span>&gt;
</pre></div>
</div>
<p>&lt;variable-assignment&gt;;可以是前面讲过的各种赋值表达式,如 <code class="docutils literal notranslate"><span class="pre">=</span></code><code class="docutils literal notranslate"><span class="pre">:=</span></code><code class="docutils literal notranslate"><span class="pre">+=</span></code>
或是 <code class="docutils literal notranslate"><span class="pre">?=</span></code> 。第二个语法是针对于make命令行带入的变量或是系统环境变量。</p>
<p>这个特性非常的有用,当我们设置了这样一个变量,这个变量会作用到由这个目标所引发的所有的规则中去。如:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nf">prog </span><span class="o">:</span> <span class="n">CFLAGS</span> = -<span class="n">g</span>
<span class="nf">prog </span><span class="o">:</span> <span class="n">prog</span>.<span class="n">o</span> <span class="n">foo</span>.<span class="n">o</span> <span class="n">bar</span>.<span class="n">o</span>
<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> prog.o foo.o bar.o
<span class="nf">prog.o </span><span class="o">:</span> <span class="n">prog</span>.<span class="n">c</span>
<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> prog.c
<span class="nf">foo.o </span><span class="o">:</span> <span class="n">foo</span>.<span class="n">c</span>
<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> foo.c
<span class="nf">bar.o </span><span class="o">:</span> <span class="n">bar</span>.<span class="n">c</span>
<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> bar.c
</pre></div>
</div>
<p>在这个示例中,不管全局的 <code class="docutils literal notranslate"><span class="pre">$(CFLAGS)</span></code> 的值是什么在prog目标以及其所引发的所有规则中prog.o foo.o bar.o的规则 <code class="docutils literal notranslate"><span class="pre">$(CFLAGS)</span></code> 的值都是 <code class="docutils literal notranslate"><span class="pre">-g</span></code></p>
</section>
<section id="id9">
<h2>模式变量<a class="headerlink" href="#id9" title="永久链接至标题"></a></h2>
<p>在GNU的make中还支持模式变量Pattern-specific Variable通过上面的目标变量中我们知道变量可以定义在某个目标上。模式变量的好处就是我们可以给定一种“模式”可以把变量定义在符合这种模式的所有目标上。</p>
<p>我们知道make的“模式”一般是至少含有一个 <code class="docutils literal notranslate"><span class="pre">%</span></code> 的,所以,我们可以以如下方式给所有以 <code class="docutils literal notranslate"><span class="pre">.o</span></code>
结尾的目标定义目标变量:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nf">%.o </span><span class="o">:</span> <span class="n">CFLAGS</span> = -<span class="n">O</span>
</pre></div>
</div>
<p>同样,模式变量的语法和“目标变量”一样:</p>
<div class="highlight-makefile notranslate"><div class="highlight"><pre><span></span><span class="nf">&lt;pattern ...&gt;; </span><span class="o">:</span> &lt;<span class="n">variable</span>-<span class="n">assignment</span>&gt;;
<span class="nf">&lt;pattern ...&gt;; </span><span class="o">:</span> <span class="n">override</span> &lt;<span class="n">variable</span>-<span class="n">assignment</span>&gt;;
</pre></div>
</div>
<p>override同样是针对于系统环境传入的变量或是make命令行指定的变量。</p>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="recipes.html" class="btn btn-neutral float-left" title="书写命令" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="conditionals.html" class="btn btn-neutral float-right" title="使用条件判断" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; 版权所有 2014-2019, 作者陈皓排版SeisMan.
<span class="lastupdated">最后更新于 2022年5月22日.
</span></p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>