<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>JRNitre&#039;s Blog - Makefile</title>
<link>https://blog.atoery.cn/index.php/tag/makefile/</link>
<atom:link href="https://blog.atoery.cn/index.php/feed/tag/makefile/" rel="self" type="application/rss+xml" />
<language>zh-CN</language>
<description></description>
<lastBuildDate>Sat, 22 Feb 2025 01:12:00 +0800</lastBuildDate>
<pubDate>Sat, 22 Feb 2025 01:12:00 +0800</pubDate>
<item>
<title>Makefile 基本使用</title>
<link>https://blog.atoery.cn/index.php/2025/02/22/29.html</link>
<guid>https://blog.atoery.cn/index.php/2025/02/22/29.html</guid>
<pubDate>Sat, 22 Feb 2025 01:12:00 +0800</pubDate>
<dc:creator>JRNitre</dc:creator>
<description><![CDATA[1.0 Makefile 基础在 Linux 下，通过 make 命令即可实现通过 Makefile 文件定义的规则自动化执行任意命令（包括编译）。即通过一个命令一个文件即可实现预定义好的任意操...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<h1>1.0 Makefile 基础</h1><p>在 Linux 下，通过 <code>make</code> 命令即可实现通过 <code>Makefile</code> 文件定义的规则自动化执行任意命令（包括编译）。</p><p>即通过一个命令一个文件即可实现预定义好的任意操作。</p><h2>1.1 规则</h2><p><code>Makefile</code> 由若干条规则（Rule）构成，每条规则指出一个目标文件（Target），若干依赖文件（Prerequisites），以及生成目标文件的命令。</p><p>例如，如果需要生成文件 <code>m.txt</code> 其由 <code>a.txt</code> 和 <code>b.txt</code> 合并而来，则有如下规则：</p><pre><code class="lang-Makefile"># 目标文件：依赖文件 1 依赖文件 2
m.txt: a.txt b.txt
    cat a.txt b.txt &gt; m.txt</code></pre><p>第一行定义了一条规则，第二行通过<code>tab</code>规定了一条命令，使用 <code>cat</code> 合并两个文件，其中 <code>#</code> 开头的为注释 <code>make</code>命令会忽略。</p><blockquote>在 makefile 中命令必须使用 <code>tab</code> 定义，空格定义的无效。</blockquote><p>由于 <code>make</code> 执行时默认执行第一条规则，所以仿照上述的方法可以写出第二个规则：</p><pre><code>x.txt: m.txt c.txt
    cat m.txt c.txt &gt; x.txt

m.txt: a.txt b.txt
    cat a.txt b.txt &gt; m.txt</code></pre><p>此时在系统内某一文件夹创建 <code>a.txt</code>、<code>b.txt</code>、<code>c.txt</code>，输入一些内容执行 <code>make</code>：</p><p><img src="http://mashirospace.cn:4607/usr/uploads/2025/02/3010390722.png" alt="" title=""></p><p><code>make</code> 默认执行第一条规则，在创建 <code>x.txt</code> 的时候发现 <code>m.txt</code> 不存在，因此先执行规则 <code>m.txt</code> 创建 <code>m.txt</code> 文件，再执行规则 <code>x.txt</code> 。</p><p>综上可见，<code>Makefile</code> 定义了一系列的规则，在每个规则满足目标的前提下执行命令，就能创建出一个目标文件。</p><p>在编写 <code>Makefile</code> 的时候把默认执行的规则放在第一条，其它的规则顺序无关紧要，因为 <code>make</code> 在执行的时候会自行判断依赖。</p><p>此外 <code>make</code> 会打印出每一条执行的命令，便于观察执行顺序。</p><p>在上述 <code>make</code> 命令执行完毕后再次执行 <code>make</code> 后，输出如下：</p><pre><code>$ make
make: “x.txt”已是最新。</code></pre><p><code>make</code> 检测到 <code>x.txt</code> 为最新的版本，无需再次执行，因为 <code>x.txt</code> 的创建时间晚于它依赖文件的最后修改时间。</p><p>可见，<code>make</code> 使用文件的创建和修改时间来判断是否该更新一个目标文件。</p><p>如果修改任意依赖文件后，再次执行 <code>make</code> 命令即可触发 <code>x.txt</code> 的更新。</p><p>假设修改了 <code>c.txt</code> 文件，则执行 <code>make</code> 命令后会触发 <code>x.txt</code> 的更新，并不会触发 <code>m.txt</code> 的更新，因为 <code>m.txt</code> 的依赖文件并没有变化，所以，<code>make</code> 会根据 <code>Makefile</code> 执行必要的规则，并非无脑执行所有规则。</p><p>在编译大型程序时，完全编译一次往往需要几十分钟甚至数小时，若每次对文件修改后都要执行完全编译则太过于浪费时间，<code>Makefile</code> 的存在即可大幅节省编译时间。</p><p>当然，对于 <code>Makefile</code> 是否能高效的完成增量更新，取决于规则书写的是否正确，<code>make</code> 本身并不会检查规则逻辑是否正确。</p><h2>1.2 伪目标</h2><p>在上述的例子中，<code>m.txt</code> 和 <code>x.txt</code> 是自动生成的文件，所以可以安全地删除。</p><p>但是如果我们希望自动删除，则可以编写一个 <code>clean</code> 规则来删除它们：</p><pre><code>clean:
    rm -f m.txt
    rm -f x.txt</code></pre><p><code>clear</code> 命令，与上面所用的命令不同，其没有依赖文件，因此需要执行 <code>clean</code> 命令时必须在命令行使用命令 <code>make clean</code></p><p>值得注意的是，如果在执行 <code>clean</code> 的时候，目录下并没有 <code>clean</code> 文件，每次执行 <code>make clean</code> 命令时都会执行 <code>Makefile</code> 中这个规则的命令。</p><p>所以，如果目录下有一个名为 <code>clean</code> 的文件，则此时 <code>Makefile</code> 中的 <code>clean</code> 规则就不会执行了！</p><p>如果目录下既需要 <code>clean</code> 文件，还想正常使用 <code>Makefile</code> 文件的 <code>clean</code> 规则，则可以添加一个标识：</p><pre><code>.PHONY: clean
clean:
    rm -f m.txt
    rm -f x.txt</code></pre><p>此时的 <code>clean</code> 就不会被视为一个文件，而是伪目标（Phony Target）</p><p>在大型项目中约定俗成下将：<code>clean</code>、<code>install</code> 这些视为伪目标名称，方便用户快速执行对应的任务。</p><blockquote>一般不会有人在目录下创建名为 <code>clean</code> 的文件，除非有人蓄意搞破坏。</blockquote><h2>1.3 执行多条命令</h2><h2>1.4 控制打印</h2><h2>1.5 控制错误</h2><h2>1.6 小结</h2><p>编写 <code>Makefile</code> 就是编写一系列的规则，用来告诉 <code>make</code> 该如何执行这些规则，从而生成我们最终需要的文件。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.atoery.cn/index.php/2025/02/22/29.html#comments</comments>
<wfw:commentRss>https://blog.atoery.cn/index.php/feed/tag/makefile/</wfw:commentRss>
</item>
</channel>
</rss>