<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>rvemu 学习笔记 on Hacper&#39;s Blog</title>
    <link>https://hacperme.com/posts/series/rvemu_notes/</link>
    <description>Recent content in rvemu 学习笔记 on Hacper&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh</language>
    <lastBuildDate>Sun, 21 May 2023 23:15:59 +0800</lastBuildDate>
    <atom:link href="https://hacperme.com/posts/series/rvemu_notes/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>rvemu 学习笔记-搭建开发环境</title>
      <link>https://hacperme.com/posts/series/rvemu_notes/01_setup_env_notes/</link>
      <pubDate>Sun, 21 May 2023 18:09:04 +0800</pubDate>
      <guid>https://hacperme.com/posts/series/rvemu_notes/01_setup_env_notes/</guid>
      <description>搭建开发环境和总结makefile基础知识</description>
      <content:encoded><![CDATA[<h2 id="视频">视频</h2>
<!DOCTYPE HTML>
<html lang="en">
<head>
    <style type="text/css">
        .bilibili_shortcodes {
            position: relative;
            width: 100%;
            height: 0;
            padding-bottom: 66%;
            margin: auto;
            overflow: hidden;
            text-align: center;
        }
        .bilibili_shortcodes iframe {
            position: absolute;
            width: 100%;
            height: 100%;
            left: 0;
            top: 0;
        }
    </style>
    <title></title>
</head>
<body>
<div class="bilibili_shortcodes">
    <iframe
            src="https://player.bilibili.com/player.html?bvid=BV1uY4y1D7bJ&page=1&high_quality=1&danmaku=0&autoplay=0&as_wide=0"
            scrolling="no"
            border="0"
            frameborder="no"
            framespacing="0"
            allowfullscreen="true"
    >
    </iframe>
</div>
</body>
</html>
<h2 id="搭建环境">搭建环境</h2>
<p>计划使用docker 跑 ubuntu 20.04 系统，并将外部工程目录 D:\workspace\rvemu_env 挂载到容器内，方便共享文件。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">PS </span><span class="n">C:</span><span class="p">\</span><span class="n">Users</span><span class="p">\</span><span class="n">hacper</span><span class="p">&gt;</span> <span class="n">docker</span> <span class="n">run</span> <span class="n">-itd</span> <span class="n">-v</span> <span class="n">D:</span><span class="p">\</span><span class="n">workspace</span><span class="p">\</span><span class="n">rvemu_env</span><span class="err">:</span><span class="p">/</span><span class="n">rvemu_env</span>  <span class="p">-</span><span class="n">-name</span> <span class="n">rvemu</span> <span class="n">ubuntu</span><span class="err">:</span><span class="mf">20.04</span>
</span></span><span class="line"><span class="cl"><span class="n">79a6aa79f8523800b37f878e29a23b6b168808d4588b639a9d24e89743e7c3c3</span>
</span></span><span class="line"><span class="cl"><span class="nb">PS </span><span class="n">C:</span><span class="p">\</span><span class="n">Users</span><span class="p">\</span><span class="n">hacper</span><span class="p">&gt;</span> <span class="n">docker</span> <span class="n">attach</span> <span class="n">79a6aa79f8523</span>
</span></span><span class="line"><span class="cl"><span class="n">root</span><span class="nv">@79a6aa79f852</span><span class="err">:</span><span class="p">/</span><span class="c"># ls</span>
</span></span><span class="line"><span class="cl"><span class="n">bin</span>   <span class="n">dev</span>  <span class="n">home</span>  <span class="n">lib32</span>  <span class="n">libx32</span>  <span class="n">mnt</span>  <span class="n">proc</span>  <span class="n">run</span>        <span class="n">sbin</span>  <span class="n">sys</span>  <span class="n">usr</span>
</span></span><span class="line"><span class="cl"><span class="n">boot</span>  <span class="n">etc</span>  <span class="n">lib</span>   <span class="n">lib64</span>  <span class="n">media</span>   <span class="n">opt</span>  <span class="n">root</span>  <span class="n">rvemu_env</span>  <span class="n">srv</span>   <span class="n">tmp</span>  <span class="n">var</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>安装开发需要的软件包：clang make  gcc</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@79a6aa79f852:/# apt update <span class="o">&amp;&amp;</span> apt install clang make vim  gcc -y     
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">root@79a6aa79f852:/# clang -v
</span></span><span class="line"><span class="cl">clang version 10.0.0-4ubuntu1
</span></span><span class="line"><span class="cl">Target: x86_64-pc-linux-gnu
</span></span><span class="line"><span class="cl">Thread model: posix
</span></span><span class="line"><span class="cl">InstalledDir: /usr/bin
</span></span><span class="line"><span class="cl">Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
</span></span><span class="line"><span class="cl">Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
</span></span><span class="line"><span class="cl">Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
</span></span><span class="line"><span class="cl">Candidate multilib: .<span class="p">;</span>@m64
</span></span><span class="line"><span class="cl">Selected multilib: .<span class="p">;</span>@m64
</span></span><span class="line"><span class="cl">root@79a6aa79f852:/# make -v
</span></span><span class="line"><span class="cl">GNU Make 4.2.1
</span></span><span class="line"><span class="cl">Built <span class="k">for</span> x86_64-pc-linux-gnu
</span></span><span class="line"><span class="cl">Copyright <span class="o">(</span>C<span class="o">)</span> 1988-2016 Free Software Foundation, Inc.
</span></span><span class="line"><span class="cl">License GPLv3+: GNU GPL version <span class="m">3</span> or later &lt;http://gnu.org/licenses/gpl.html&gt;
</span></span><span class="line"><span class="cl">This is free software: you are free to change and redistribute it.
</span></span><span class="line"><span class="cl">There is NO WARRANTY, to the extent permitted by law.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">root@79a6aa79f852:/rvemu_env/rvemu# gcc -v
</span></span><span class="line"><span class="cl">Using built-in specs.
</span></span><span class="line"><span class="cl"><span class="nv">COLLECT_GCC</span><span class="o">=</span>gcc
</span></span><span class="line"><span class="cl"><span class="nv">COLLECT_LTO_WRAPPER</span><span class="o">=</span>/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
</span></span><span class="line"><span class="cl"><span class="nv">OFFLOAD_TARGET_NAMES</span><span class="o">=</span>nvptx-none:hsa
</span></span><span class="line"><span class="cl"><span class="nv">OFFLOAD_TARGET_DEFAULT</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">Target: x86_64-linux-gnu
</span></span><span class="line"><span class="cl">Configured with: ../src/configure -v --with-pkgversion<span class="o">=</span><span class="s1">&#39;Ubuntu 9.4.0-1ubuntu1~20.04.1&#39;</span> --with-bugurl<span class="o">=</span>file:///usr/share/doc/gcc-9/README.Bugs --enable-languages<span class="o">=</span>c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix<span class="o">=</span>/usr --with-gcc-major-version-only --program-suffix<span class="o">=</span>-9 --program-prefix<span class="o">=</span>x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir<span class="o">=</span>/usr/lib --without-included-gettext --enable-threads<span class="o">=</span>posix --libdir<span class="o">=</span>/usr/lib --enable-nls --enable-clocale<span class="o">=</span>gnu --enable-libstdcxx-debug --enable-libstdcxx-time<span class="o">=</span>yes --with-default-libstdcxx-abi<span class="o">=</span>new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib<span class="o">=</span>auto --enable-objc-gc<span class="o">=</span>auto --enable-multiarch --disable-werror --with-arch-32<span class="o">=</span>i686 --with-abi<span class="o">=</span>m64 --with-multilib-list<span class="o">=</span>m32,m64,mx32 --enable-multilib --with-tune<span class="o">=</span>generic --enable-offload-targets<span class="o">=</span>nvptx-none<span class="o">=</span>/build/gcc-9-Av3uEd/gcc-9-9.4.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking<span class="o">=</span>release --build<span class="o">=</span>x86_64-linux-gnu --host<span class="o">=</span>x86_64-linux-gnu --target<span class="o">=</span>x86_64-linux-gnu
</span></span><span class="line"><span class="cl">Thread model: posix
</span></span><span class="line"><span class="cl">gcc version 9.4.0 <span class="o">(</span>Ubuntu 9.4.0-1ubuntu1~20.04.1<span class="o">)</span> 
</span></span></code></pre></td></tr></table>
</div>
</div><p>再安装  RV64 Newlib 版本的工具链: <a href="https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2023.05.19/riscv64-elf-ubuntu-22.04-nightly-2023.05.19-nightly.tar.gz">riscv64-elf-ubuntu-20.04-nightly-2023.05.19-nightly.tar.gz</a>。下载到共享目录和解压，并添加路径到环境变量。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@79a6aa79f852:~# cp riscv64-elf-ubuntu-20.04-nightly-2023.05.19-nightly.tar.gz ~
</span></span><span class="line"><span class="cl">root@79a6aa79f852:~# tar -xvf riscv64-elf-ubuntu-20.04-nightly-2023.05.19-nightly.tar.gz
</span></span><span class="line"><span class="cl">root@79a6aa79f852:~# <span class="nb">echo</span> <span class="s2">&#34;export PATH=</span><span class="nv">$PATH</span><span class="s2">:/root/riscv/bin&#34;</span> &gt; rvemu_env.sh
</span></span><span class="line"><span class="cl">root@79a6aa79f852:~# <span class="nb">source</span> rvemu_env.sh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">root@79a6aa79f852:~# riscv64-unknown-elf-gcc -v
</span></span><span class="line"><span class="cl">Using built-in specs.
</span></span><span class="line"><span class="cl"><span class="nv">COLLECT_GCC</span><span class="o">=</span>riscv64-unknown-elf-gcc
</span></span><span class="line"><span class="cl"><span class="nv">COLLECT_LTO_WRAPPER</span><span class="o">=</span>/root/riscv/bin/../libexec/gcc/riscv64-unknown-elf/12.2.0/lto-wrapper
</span></span><span class="line"><span class="cl">Target: riscv64-unknown-elf
</span></span><span class="line"><span class="cl">Configured with: /home/runner/work/riscv-gnu-toolchain/riscv-gnu-toolchain/gcc/configure --target<span class="o">=</span>riscv64-unknown-elf --prefix<span class="o">=</span>/opt/riscv --disable-shared --disable-threads --enable-languages<span class="o">=</span>c,c++ --with-pkgversion<span class="o">=</span>g2ee5e430018 --with-system-zlib --enable-tls --with-newlib --with-sysroot<span class="o">=</span>/opt/riscv/riscv64-unknown-elf --with-native-system-header-dir<span class="o">=</span>/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src<span class="o">=</span>.././gcc --disable-multilib --with-abi<span class="o">=</span>lp64d --with-arch<span class="o">=</span>rv64gc --with-tune<span class="o">=</span>rocket --with-isa-spec<span class="o">=</span><span class="m">20191213</span> <span class="s1">&#39;CFLAGS_FOR_TARGET=-Os    -mcmodel=medlow&#39;</span> <span class="s1">&#39;CXXFLAGS_FOR_TARGET=-Os    -mcmodel=medlow&#39;</span>
</span></span><span class="line"><span class="cl">Thread model: single
</span></span><span class="line"><span class="cl">Supported LTO compression algorithms: zlib
</span></span><span class="line"><span class="cl">gcc version 12.2.0 <span class="o">(</span>g2ee5e430018<span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>不安装 gcc 使用 riscv64-unknown-elf-gcc 编译代码会出现找不到  libmpc.so.3 的错误，所以在上一步把 gcc 也安装上。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@79a6aa79f852:/rvemu_env/rvemu# riscv64-unknown-elf-gcc test.c -o <span class="nb">test</span>
</span></span><span class="line"><span class="cl">/root/riscv/bin/../libexec/gcc/riscv64-unknown-elf/12.2.0/cc1: error <span class="k">while</span> loading shared libraries: libmpc.so.3: cannot open shared object file: No such file or directory
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="vscode-连接到-docker-容器">vscode 连接到 docker 容器</h2>
<p>vscode 可以直接连接到 docker 容器，不需要再配置网络、sshd 这些，也挺方便。在远程连接界面选择 Attach to Running Contaner 即可。编译跑一下已有的完整代码，验证环境是正常的。</p>
<p><img loading="lazy" src="https://github.com/hacperme/picx_hosting/raw/master/20210507/image.1lg5k9upb3c0.png" alt=""  />
</p>
<h2 id="makefile-基础知识">makefile 基础知识</h2>
<p>借助第一课的基础 makefile 文件，对 makefile 的基础知识做一个整理。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">CFLAGS</span><span class="o">=</span>-O3 -Wall -Werror -Wimplicit-fallthrough
</span></span><span class="line"><span class="cl"><span class="nv">SRCS</span><span class="o">=</span><span class="k">$(</span>wildcard src/*.c<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">HDRS</span><span class="o">=</span><span class="k">$(</span>wildcard src/*.h<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">OBJS</span><span class="o">=</span><span class="k">$(</span>patsubst src/%.c, obj/%.o, <span class="k">$(</span>SRCS<span class="k">))</span>
</span></span><span class="line"><span class="cl"><span class="nv">CC</span><span class="o">=</span>clang
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">rvemu</span><span class="o">:</span> <span class="k">$(</span><span class="nv">OBJS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -lm -o <span class="nv">$@</span> $^ <span class="k">$(</span>LDFLAGS<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(OBJS)</span><span class="o">:</span> <span class="n">obj</span>/%.<span class="n">o</span>: <span class="n">src</span>/%.<span class="n">c</span> <span class="k">$(</span><span class="nv">HDRS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">	@mkdir -p <span class="nv">$$</span><span class="o">(</span>dirname <span class="nv">$@</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -c -o <span class="nv">$@</span> $&lt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">clean</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	rm -rf rvemu obj/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">clean</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="makefile-的编写规则">makefile 的编写规则</h3>
<p>makefile 文件记录了一个工程怎样构建编译得到目标产物的规则，makefile 的规则主要由目标、依赖和命令三部分组成。简单地理解 makefile 规则：想要生成的目标文件依赖于一个或者多个文件，目标的生成规则定义在命令中，一旦依赖文件有更新，就会执行命令构建目标文件。</p>
<p>makefile 通过文件的时间戳来判断是否文件有更新。</p>
<p>makefile文件规则：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">目标：依赖
</span></span><span class="line"><span class="cl">&lt;TAB&gt;命令
</span></span></code></pre></td></tr></table>
</div>
</div><p>目标：可以是可执行文件、中间文件、或者标签（伪目标）。</p>
<p>依赖：可以是源文件、其他目标。</p>
<p>命令：任何 shell 命令</p>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">rvemu</span><span class="o">:</span> <span class="k">$(</span><span class="nv">OBJS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -lm -o <span class="nv">$@</span> $^ <span class="k">$(</span>LDFLAGS<span class="k">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>伪目标不会生成目标文件，只执行命令，用于执行某项特定的任务。</p>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">clean</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	rm -rf rvemu obj/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">clean</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="makefile-变量">makefile 变量</h3>
<p>makefile 里面可以定义和使用变量，可分为预定义变量、自定义变量和自动变量三部分。</p>
<h4 id="常见的预定义变量">常见的预定义变量</h4>
<table>
<thead>
<tr>
<th>AR</th>
<th>归档维护程序的程序名，默认值为ar</th>
</tr>
</thead>
<tbody>
<tr>
<td>ARFLAGS</td>
<td>归档维护程序的选项</td>
</tr>
<tr>
<td>AS</td>
<td>汇编程序的名称，默认值为as</td>
</tr>
<tr>
<td>ASFLAGS</td>
<td>汇编程序的选项</td>
</tr>
<tr>
<td>CC</td>
<td>C编译器的名称，默认值为cc</td>
</tr>
<tr>
<td>CFLAGS</td>
<td>C编译器的选项</td>
</tr>
<tr>
<td>CPP</td>
<td>C预编译器的名称，默认值为$(CC) -E</td>
</tr>
<tr>
<td>CPPFLAGS</td>
<td>C预编译的选项</td>
</tr>
<tr>
<td>CXX</td>
<td>C++编译器的名称，默认值为g++</td>
</tr>
<tr>
<td>CXXFLAGS</td>
<td>C++编译器的选项</td>
</tr>
</tbody>
</table>
<p>环境变量也可以引用，也看作是预定义变量。</p>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">CFLAGS</span><span class="o">=</span>-O3 -Wall -Werror -Wimplicit-fallthrough
</span></span><span class="line"><span class="cl"><span class="nv">CC</span><span class="o">=</span>clang
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="自定义变量和使用">自定义变量和使用</h4>
<p>变量名可以数字开头，区分大小写，定义方法:</p>
<p>变量名=变量值</p>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">SRCS</span><span class="o">=</span><span class="k">$(</span>wildcard src/*.c<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">HDRS</span><span class="o">=</span><span class="k">$(</span>wildcard src/*.h<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">OBJS</span><span class="o">=</span><span class="k">$(</span>patsubst src/%.c, obj/%.o, <span class="k">$(</span>SRCS<span class="k">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>使用变量的值：</p>
<p>$(变量名)或${变量名}</p>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">rvemu</span><span class="o">:</span> <span class="k">$(</span><span class="nv">OBJS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -lm -o <span class="nv">$@</span> $^ <span class="k">$(</span>LDFLAGS<span class="k">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="自动变量">自动变量</h4>
<table>
<thead>
<tr>
<th>$@</th>
<th>目标名</th>
</tr>
</thead>
<tbody>
<tr>
<td>$&lt;</td>
<td>依赖文件列表中的第一个文件</td>
</tr>
<tr>
<td>$^</td>
<td>依赖文件列表中除去重复文件的部分</td>
</tr>
<tr>
<td>$*</td>
<td>不包含扩展名的目标文件名称</td>
</tr>
<tr>
<td>$+</td>
<td>所有的依赖文件，以空格分开，并以出现的先后为序，可能包含重复的依赖文件</td>
</tr>
<tr>
<td>$?</td>
<td>所有时间戳比目标文件晚的依赖文件，并以空格分开</td>
</tr>
<tr>
<td>$%</td>
<td>如果目标是归档成员，则该变量表示目标的归档成员名称</td>
</tr>
</tbody>
</table>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">rvemu</span><span class="o">:</span> <span class="k">$(</span><span class="nv">OBJS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -lm -o <span class="nv">$@</span> $^ <span class="k">$(</span>LDFLAGS<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(OBJS)</span><span class="o">:</span> <span class="n">obj</span>/%.<span class="n">o</span>: <span class="n">src</span>/%.<span class="n">c</span> <span class="k">$(</span><span class="nv">HDRS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">	@mkdir -p <span class="nv">$$</span><span class="o">(</span>dirname <span class="nv">$@</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -c -o <span class="nv">$@</span> $&lt;
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="通配符">通配符</h3>
<p>在规则中可以使用通配符：</p>
<table>
<thead>
<tr>
<th>*</th>
<th>匹配任意长度的任意字符序列。例如，<code>*.c</code> 匹配所有以 <code>.c</code> 结尾的文件。</th>
</tr>
</thead>
<tbody>
<tr>
<td>?</td>
<td>匹配任意单个字符。例如，<code>file?.txt</code> 可以匹配 <code>file1.txt</code>, <code>file2.txt</code>,等。</td>
</tr>
<tr>
<td>[]</td>
<td>匹配方括号内的任意一个字符。例如，<code>file[123].txt</code> 可以匹配 <code>file1.txt</code>, <code>file2.txt</code>, <code>file3.txt</code>。</td>
</tr>
</tbody>
</table>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">SRCS</span><span class="o">=</span><span class="k">$(</span>wildcard src/*.c<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">clean</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    rm -f *.o
</span></span></code></pre></td></tr></table>
</div>
</div><p>在 Makefile 中，<code>%</code> 通配符用于模式规则（pattern rules）中，表示匹配任意字符序列。</p>
<p>如：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">OBJS</span><span class="o">=</span><span class="k">$(</span>patsubst src/%.c, obj/%.o, <span class="k">$(</span>SRCS<span class="k">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="函数">函数</h3>
<p>Makefile 中有很多内建函数。以下是一些常见的内建函数及其功能：</p>
<ul>
<li>
<p>$(subst from, to, text)：在 text 中替换 from 为 to。
STR := replaceAwithB
RESULT := $(subst A, B, $(STR))</p>
<p>RESULT 的值将是 &ldquo;replBceAwithB&rdquo;</p>
</li>
<li>
<p>$(patsubst pattern, replacement, text)：对 text 进行模式替换，将符合 pattern 的字符串替换为 replacement。
SOURCES := file1.c file2.c file3.c
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))</p>
<p>OBJECTS 的值将是 &ldquo;file1.o file2.o file3.o&rdquo;</p>
</li>
<li>
<p>$(strip string)：删除 string 首尾的空白字符（空格和制表符）。
STR =     This is a string
RESULT := $(strip $(STR))
RESULT 的值将是 &ldquo;This is a string&rdquo;</p>
</li>
<li>
<p>$(findstring find, in)：在字符串 in 中查找子串 find，如果找到，返回 find，否则返回空字符串。
IFDEF_TEST := $(findstring <em>TEST</em>, $(DEFINES))
$(filter pattern, text)：从 text 中选择符合 pattern 的字符串。支持 ? 和 % 通配符。
FILES := a.c b.h c.cpp d.hpp
C_FILES :=\$(filter %.c %.cpp, $(FILES))
C_FILES 的值将是 &ldquo;a.c c.cpp&rdquo;</p>
</li>
<li>
<p>$(filter-out pattern, text)：从 text 中排除符合 pattern 的字符串。支持 ? 和 % 通配符。
FILES := a.c b.h c.cpp d.hpp
NOT_C_FILES := $(filter-out %.c %.cpp, $(FILES))</p>
<p>NOT_C_FILES 的值将是 &ldquo;b.h d.hpp&rdquo;</p>
</li>
<li>
<p>$(sort list)：对 list 中的单词进行排序并删除重复项。
WORDS := Z A A C B Y
UNIQUE_SORTED :=\ $(sort $(WORDS))
UNIQUE_SORTED 的值将是 &ldquo;A B C Y Z&rdquo;</p>
</li>
<li>
<p>$(dir names)：返回 names 中各文件的目录部分，包括最后的斜杠。
FILES := src/a.c include/b.h
DIRS := $(dir $(FILES))
DIRS 的值将是 &ldquo;src/ include/&rdquo;</p>
</li>
<li>
<p>$(wildcard pattern)：返回符合 pattern 的文件列表。
C_FILES := $(wildcard *.c)</p>
</li>
</ul>
<p>这只是 Makefile 中内建函数的一部分。更多函数和详细使用方法，可以查阅 GNU Make 的官方文档：
<a href="https://www.gnu.org/software/make/manual/make.html">https://www.gnu.org/software/make/manual/make.html</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
