<?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>Ci-Cd on My Little Blog</title><link>https://www.parkerchenca.com/tags/ci-cd/</link><description>Recent content in Ci-Cd on My Little Blog</description><generator>Hugo</generator><language>en-us</language><copyright>Parker Chen</copyright><lastBuildDate>Thu, 10 Sep 2026 11:23:00 +0000</lastBuildDate><atom:link href="https://www.parkerchenca.com/tags/ci-cd/index.xml" rel="self" type="application/rss+xml"/><item><title>Basic Makefile</title><link>https://www.parkerchenca.com/tech/basic-makefile/</link><pubDate>Thu, 10 Sep 2026 11:23:00 +0000</pubDate><guid>https://www.parkerchenca.com/tech/basic-makefile/</guid><description>The first step to understand makefile</description><content:encoded><![CDATA[<blockquote>
<p>🔔 <strong>Prelude:</strong>
I often noticed Makefile files in the root directory when browsing open-source projects on GitHub. For a long time, I thought it was some kind of sophisticated &ldquo;magic tool&rdquo;. So during my spare time at my internship, I decided to learn some basic syntax&hellip; only to discover that it&rsquo;s actually like a &ldquo;recipe&rdquo; for compilation - to get a target file (the dish), you need some dependencies (ingredients) and commands (cooking instructions). Anyway, at least now I can understand it (mostly).</p>
</blockquote>
<h2 id="make">Make</h2>
<h3 id="basic-rules">Basic Rules</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">target</span><span class="o">:</span> <span class="n">dependencies</span> ..
</span></span><span class="line"><span class="cl"><span class="err">[tab][Command]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">TARGET</span> <span class="o">=</span> main
</span></span><span class="line"><span class="cl"><span class="nf">main</span><span class="o">:</span> <span class="n">hello</span>.<span class="n">o</span> <span class="n">world</span>.<span class="n">o</span>   <span class="c"># will be run by default as the first target
</span></span></span><span class="line"><span class="cl">    gcc $^ -o <span class="k">$(</span>TARGET<span class="k">)</span> <span class="c1"># treat these as normal bash commands</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">hello.o</span><span class="o">:</span> <span class="n">hello</span>.<span class="n">c</span>
</span></span><span class="line"><span class="cl">    gcc -c hello.c      <span class="c1"># -c for compile only</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">world.o</span><span class="o">:</span> <span class="n">world</span>.<span class="n">c</span>
</span></span><span class="line"><span class="cl">    gcc -c world.c
</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 class="c"># will not be run unless &#34;make clean&#34;
</span></span></span><span class="line"><span class="cl">    rm -f <span class="k">$(</span>wildcard *.o<span class="k">)</span> <span class="k">$(</span>TARGET<span class="k">)</span>
</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></div><h3 id="common-cli-parameters">Common CLI Parameters</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="err">-v</span>
</span></span><span class="line"><span class="cl"><span class="err">-n</span> <span class="err">--just-print</span>        <span class="c"># Print commands without executing
</span></span></span><span class="line"><span class="cl"><span class="err">-p</span>                     <span class="c"># Output makefile data (lots of info)
</span></span></span><span class="line"><span class="cl"><span class="err">-t</span> <span class="err">--touch</span>             <span class="c"># Update file timestamps without changing targets (dry run)
</span></span></span><span class="line"><span class="cl"><span class="err">-q</span> <span class="err">--question</span>          <span class="c"># Check if target exists. Do nothing if yes, print error if no
</span></span></span><span class="line"><span class="cl">                       <span class="c1"># Usually used with -qp</span>
</span></span><span class="line"><span class="cl"><span class="err">-W</span> <span class="err">--what-if</span> <span class="err">&lt;file&gt;</span>    <span class="c"># Pretend this file was just modified, trigger related rules
</span></span></span><span class="line"><span class="cl"><span class="err">-B</span>                     <span class="c"># Rebuild everything
</span></span></span><span class="line"><span class="cl"><span class="err">-b</span> <span class="err">-m</span>                  <span class="c"># Used to ignore compatibility between different make versions
</span></span></span><span class="line"><span class="cl"><span class="nv">-debug</span><span class="o">=[</span>option<span class="o">]</span>        <span class="c1"># Debug mode</span>
</span></span><span class="line"><span class="cl">                       <span class="c1"># option can be: a(all), b(basic), v(verbose)</span>
</span></span><span class="line"><span class="cl">                       <span class="c1"># i(implicit), j(jobs), m(makefile)</span>
</span></span><span class="line"><span class="cl">                       <span class="c1"># -d = -debug=a</span>
</span></span><span class="line"><span class="cl"><span class="err">-e</span> <span class="nv">var</span><span class="o">=</span>sth             <span class="c1"># Override environment variable values</span>
</span></span><span class="line"><span class="cl"><span class="err">-h</span>                     <span class="c"># Help me!
</span></span></span><span class="line"><span class="cl"><span class="err">-f</span> <span class="err">&lt;file&gt;</span>              <span class="c"># Execute specific makefile
</span></span></span><span class="line"><span class="cl"><span class="err">-i</span>                     <span class="c"># Ignore errors
</span></span></span><span class="line"><span class="cl"><span class="err">-I</span> <span class="err">--include-dir</span> <span class="err">&lt;dir&gt;</span> <span class="c"># Specify make search directory
</span></span></span><span class="line"><span class="cl"><span class="err">-k</span> <span class="err">--keep-going</span>        <span class="c"># Continue on errors, except missing dependencies
</span></span></span><span class="line"><span class="cl"><span class="err">-s</span> <span class="err">--silent</span>
</span></span><span class="line"><span class="cl"><span class="err">-j</span> <span class="err">--jobs</span>              <span class="c"># Parallel compilation when dependencies allow
</span></span></span><span class="line"><span class="cl">                       <span class="c1"># make will try to parallelize as much as possible by default</span>
</span></span></code></pre></div><h3 id="special-syntax">Special Syntax</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="k">$&lt;</span>                  <span class="c"># First item in dependencies
</span></span></span><span class="line"><span class="cl">                    <span class="c1"># Note: if target is matched via %,</span>
</span></span><span class="line"><span class="cl">                    <span class="c1"># $&lt; represents all matched items</span>
</span></span><span class="line"><span class="cl"><span class="err">$^</span>                  <span class="c"># All dependencies
</span></span></span><span class="line"><span class="cl"><span class="k">$?</span>                  <span class="c"># All dependencies that are newer than target
</span></span></span><span class="line"><span class="cl"><span class="k">$+</span>                  <span class="c"># All dependencies without deduplication
</span></span></span><span class="line"><span class="cl"><span class="k">$*</span>                  <span class="c"># The part matched by %
</span></span></span><span class="line"><span class="cl"><span class="k">$@</span>                  <span class="c"># The target
</span></span></span><span class="line"><span class="cl"><span class="k">$%</span>                  <span class="c"># Target member name (only for archive files)
</span></span></span><span class="line"><span class="cl"><span class="k">$$</span>                  <span class="c"># Escape $ character
</span></span></span><span class="line"><span class="cl"><span class="k">$(</span><span class="nv">wildcard</span> *.<span class="nv">c</span><span class="k">)</span>     <span class="c"># Use wildcards
</span></span></span><span class="line"><span class="cl"><span class="nf">$(source</span><span class="o">:</span>.<span class="n">c</span>=.<span class="n">o</span>)     <span class="c"># Change suffix of variable
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">:=</span>                  <span class="c"># Immediate expansion of $() expressions (no variable hoisting)
</span></span></span><span class="line"><span class="cl"><span class="err">?=</span>                  <span class="c"># Assign only if not already defined
</span></span></span><span class="line"><span class="cl"><span class="err">+=</span>                  <span class="c"># Append to variable value (with leading space)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">%</span>                   <span class="c"># Wildcard in pattern rules
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@[command]</span>          <span class="c"># Execute command silently
</span></span></span><span class="line"><span class="cl"><span class="err">-[command]</span>          <span class="c"># Ignore errors, continue running
</span></span></span><span class="line"><span class="cl"><span class="err">[command];[command]</span> <span class="c"># Similar to pipeline (&#34;|&#34;)
</span></span></span><span class="line"><span class="cl">                    <span class="c1"># If written on separate lines, executed separately</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">override var </span><span class="o">:</span>= <span class="n">new</span>-<span class="n">value</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># $ with uppercase D(Directory) and F(File)
</span></span></span><span class="line"><span class="cl"><span class="c"># Further specify the scope of dependency strings
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">dir/foo.o</span><span class="o">:</span> ...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Need parentheses to avoid ambiguity
</span></span></span><span class="line"><span class="cl"><span class="k">$(</span>@<span class="nv">D</span><span class="k">)</span>               <span class="c"># dir/foo.o -&gt; dir
</span></span></span><span class="line"><span class="cl"><span class="k">$(</span>@<span class="nv">F</span><span class="k">)</span>               <span class="c"># dir/foo.o -&gt; foo.o
</span></span></span></code></pre></div><h3 id="pattern-rules">Pattern Rules</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">%.o</span><span class="o">:</span> %.<span class="n">c</span>    <span class="c"># % means &#34;match&#34;, represents &#34;any string&#34;
</span></span></span><span class="line"><span class="cl">            <span class="c1"># Meaning: to build .o file, its dependency is corresponding .c file</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># No directory search performed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Study these examples for better understanding
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">src/eat</span>
</span></span><span class="line"><span class="cl"><span class="err">e%t</span>
</span></span><span class="line"><span class="cl"><span class="err">%</span> <span class="err">-&gt;</span> <span class="err">src/a</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># then, % is passed to another place...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">c%r</span> <span class="err">-&gt;</span> <span class="err">csrc/ar</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># but if there is a nested % pattern on the original side...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">c%r</span> <span class="err">-&gt;</span> <span class="err">src/car</span>  <span class="c"># % should be &#34;src/a&#34;
</span></span></span><span class="line"><span class="cl">                <span class="c1"># but &#34;src/&#34; will be removed before matching patterns</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># so in this situation, % is &#34;a&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># this rule also applies to the first step</span>
</span></span></code></pre></div><h3 id="functions">Functions</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="c"># Basic syntax
</span></span></span><span class="line"><span class="cl"><span class="k">$(</span>&lt;<span class="nv">function</span>&gt; &lt;<span class="nv">arguments</span>&gt;<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Can also be written as
</span></span></span><span class="line"><span class="cl"><span class="err">${&lt;function&gt;</span> <span class="err">&lt;arguments&gt;}</span>   <span class="c"># Perhaps more readable
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">$(</span><span class="nv">patsubst</span> %.<span class="nv">c</span>,%.<span class="nv">o</span>,<span class="k">$(</span><span class="nv">source</span><span class="k">))</span>  <span class="c"># Better demonstrates % syntax behavior
</span></span></span><span class="line"><span class="cl">                               <span class="c1"># patsubst = pattern substitute</span>
</span></span><span class="line"><span class="cl">                               <span class="c1"># For any .c file, replace with corresponding .o file</span>
</span></span><span class="line"><span class="cl">                               <span class="c1"># Scope is $(source), which should be text</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Common functions
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">subst</span> <span class="err">&lt;from&gt;,&lt;to&gt;,&lt;text&gt;</span>    <span class="c"># Substitute text
</span></span></span><span class="line"><span class="cl"><span class="err">strip</span> <span class="err">&lt;text&gt;</span>                <span class="c"># Remove spaces
</span></span></span><span class="line"><span class="cl"><span class="err">findstring</span> <span class="err">&lt;find&gt;,&lt;in&gt;</span>      <span class="c"># Find substring, return &lt;find&gt; if found
</span></span></span><span class="line"><span class="cl"><span class="err">filter</span> <span class="err">&lt;pattern...&gt;,&lt;text&gt;</span>  <span class="c"># Can pass multiple patterns
</span></span></span><span class="line"><span class="cl"><span class="err">filter-out</span> <span class="err">&lt;pattern...&gt;,&lt;text&gt;</span> <span class="c"># Reverse filter, keeps unmatched items
</span></span></span><span class="line"><span class="cl"><span class="err">sort</span> <span class="err">&lt;list&gt;</span>                 <span class="c"># Default ascending order
</span></span></span><span class="line"><span class="cl"><span class="err">word</span> <span class="err">&lt;n&gt;,&lt;text&gt;</span>             <span class="c"># Get nth word (a.c b.c c.c -&gt; b.c)
</span></span></span><span class="line"><span class="cl"><span class="err">wordlist</span> <span class="err">&lt;s&gt;,&lt;e&gt;,&lt;text&gt;</span>     <span class="c"># Slice
</span></span></span><span class="line"><span class="cl"><span class="err">words</span> <span class="err">&lt;text&gt;</span>                <span class="c"># Count words
</span></span></span><span class="line"><span class="cl"><span class="err">firstword</span> <span class="err">&lt;text&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">dir</span> <span class="err">&lt;names...&gt;</span>              <span class="c"># Extract directory from filename
</span></span></span><span class="line"><span class="cl"><span class="err">notdir</span> <span class="err">&lt;names...&gt;</span>           <span class="c"># Remove directory part, keep filename only
</span></span></span><span class="line"><span class="cl"><span class="err">suffix</span> <span class="err">&lt;names...&gt;</span>           <span class="c"># Extract suffix
</span></span></span><span class="line"><span class="cl"><span class="err">basename</span> <span class="err">&lt;names...&gt;</span>         <span class="c"># Extract name without suffix (prefix)
</span></span></span><span class="line"><span class="cl"><span class="err">addsuffix</span> <span class="err">&lt;suffix&gt;,&lt;names...&gt;</span> <span class="c"># Add suffix
</span></span></span><span class="line"><span class="cl"><span class="err">addprefix</span> <span class="err">&lt;prefix&gt;,&lt;names...&gt;</span>
</span></span><span class="line"><span class="cl"><span class="err">join</span> <span class="err">&lt;list1&gt;,&lt;list2&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">origin</span> <span class="err">&lt;variable&gt;</span>           <span class="c"># Where did this variable come from?
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">shell</span> <span class="err">&lt;command&gt;</span>             <span class="c"># Execute command in shell
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">error</span> <span class="err">&lt;text</span> <span class="err">...&gt;</span>            <span class="c"># Generate error message, but doesn&#39;t abort
</span></span></span><span class="line"><span class="cl"><span class="err">warning</span> <span class="err">&lt;text</span> <span class="err">...&gt;</span>          <span class="c"># Generate warning message
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Iteration
</span></span></span><span class="line"><span class="cl"><span class="err">foreach</span> <span class="err">&lt;var&gt;,&lt;list&gt;,&lt;text&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">names</span> <span class="o">:=</span> a b c d
</span></span><span class="line"><span class="cl"><span class="nv">files</span> <span class="o">:=</span> <span class="k">$(</span>foreach n,<span class="k">$(</span>names<span class="k">)</span>,<span class="k">$(</span>n<span class="k">)</span>.o<span class="k">)</span>  <span class="c1"># a.o b.o c.o d.o</span>
</span></span></code></pre></div><h3 id="custom-functions-with-call">Custom Functions with call</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="err">call</span> <span class="err">&lt;expression&gt;,&lt;parm1&gt;,&lt;parm2&gt;,...,&lt;parmn&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Examples are easier to understand
</span></span></span><span class="line"><span class="cl"><span class="nv">reverse</span> <span class="o">=</span> <span class="k">$(</span>2<span class="k">)</span> <span class="k">$(</span>1<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">foo</span> <span class="o">=</span> <span class="k">$(</span>call reverse,a,b<span class="k">)</span>  <span class="c1"># $(foo) -&gt; b a</span>
</span></span></code></pre></div><h3 id="special-variables">Special Variables</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="err">VPATH</span>                            <span class="c"># Set default search path
</span></span></span><span class="line"><span class="cl"><span class="c"># Syntax: vpath &lt;pattern&gt; &lt;directories&gt;
</span></span></span><span class="line"><span class="cl"><span class="c"># Example: vpath %.h src:../headers:lib  # Directories separated by colon (:)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Can actively set paths
</span></span></span><span class="line"><span class="cl"><span class="c"># Advantage: if file not found, will search in VPATH
</span></span></span><span class="line"><span class="cl"><span class="nv">VPATH</span> <span class="o">=</span> src
</span></span><span class="line"><span class="cl"><span class="nv">BUILD_DIR</span> <span class="o">=</span> build
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(BUILD_DIR)/%.o</span><span class="o">:</span> %.<span class="n">c</span>
</span></span><span class="line"><span class="cl">    gcc -c $&lt; -o <span class="nv">$@</span>
</span></span></code></pre></div><h3 id="sub-makefiles">Sub-Makefiles</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">subsystem</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">cd</span> subdir <span class="o">&amp;&amp;</span> <span class="k">$(</span>MAKE<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Equivalent to
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">subsystem</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>MAKE<span class="k">)</span> -C subdir
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Execute make in subsystem
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">export </span><span class="nv">VAR</span> <span class="o">=</span> value     <span class="c1"># Pass VAR to subsystem</span>
</span></span><span class="line"><span class="cl"><span class="err">un</span><span class="k">export </span><span class="err">VAR_PRIVATE</span>   <span class="c"># Don&#39;t pass this variable
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># $(SHELL) and $(MAKEFLAGS) are always passed to subsystems
</span></span></span></code></pre></div><h3 id="define-directive">Define Directive</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="err">define</span> <span class="err">reusable</span>
</span></span><span class="line"><span class="cl"><span class="err">dosth..</span>
</span></span><span class="line"><span class="cl"><span class="err">dosth..</span>
</span></span><span class="line"><span class="cl"><span class="err">endef</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">$(</span><span class="nv">reusable</span><span class="k">)</span>
</span></span></code></pre></div><h3 id="conditionals">Conditionals</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="c"># Similar to bash syntax
</span></span></span><span class="line"><span class="cl"><span class="err">ifeq</span> <span class="err">(var1,</span> <span class="err">var2)</span>
</span></span><span class="line"><span class="cl">    <span class="err">[command]</span>
</span></span><span class="line"><span class="cl"><span class="err">else</span>
</span></span><span class="line"><span class="cl">    <span class="err">[command]</span>
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Available keywords
</span></span></span><span class="line"><span class="cl"><span class="err">ifeq</span> <span class="err">ifneq</span> <span class="err">ifdef</span> <span class="err">ifndef</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># if as a function
</span></span></span><span class="line"><span class="cl"><span class="k">$(</span><span class="nv">if</span> &lt;<span class="nv">condition</span>&gt;,&lt;<span class="nv">then</span>-<span class="nv">part</span>&gt;<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="k">$(</span><span class="nv">if</span> &lt;<span class="nv">condition</span>&gt;,&lt;<span class="nv">then</span>-<span class="nv">part</span>&gt;,&lt;<span class="nv">else</span>-<span class="nv">part</span>&gt;<span class="k">)</span>
</span></span></code></pre></div><h3 id="implicit-rules">Implicit Rules</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="c"># Implicit rules use these predefined variables:
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CC</span> <span class="o">=</span> gcc        <span class="c1"># C compiler</span>
</span></span><span class="line"><span class="cl"><span class="nv">CXX</span> <span class="o">=</span> g++       <span class="c1"># C++ compiler</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">=</span>        <span class="c1"># C compile options</span>
</span></span><span class="line"><span class="cl"><span class="nv">CXXFLAGS</span> <span class="o">=</span>      <span class="c1"># C++ compile options</span>
</span></span><span class="line"><span class="cl"><span class="nv">LDFLAGS</span> <span class="o">=</span>       <span class="c1"># Linker options</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Only need to define dependencies, compile rules apply automatically
</span></span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">=</span> -Wall -O2
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">main</span><span class="o">:</span> <span class="n">main</span>.<span class="n">o</span> <span class="n">utils</span>.<span class="n">o</span>  <span class="c"># Implicit rules automatically compile .c → .o
</span></span></span><span class="line"><span class="cl">    <span class="k">$(</span>CC<span class="k">)</span> $^ -o <span class="nv">$@</span>    <span class="c1"># Linking rules need to be written manually</span>
</span></span><span class="line"><span class="cl">                      <span class="c1"># (implicit rules only handle single file compilation)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># View all implicit rules
</span></span></span><span class="line"><span class="cl"><span class="err">make</span> <span class="err">-p</span> <span class="err">|</span> <span class="err">grep</span> <span class="s2">&#34;^%&#34;</span>  <span class="c"># Display all pattern rules
</span></span></span></code></pre></div><h3 id="include-directive">Include Directive</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="err">include</span> <span class="err">file1.mk</span> <span class="err">file2.mk</span>
</span></span><span class="line"><span class="cl"><span class="err">-include</span> <span class="err">optional.mk</span>  <span class="c"># Don&#39;t error if file doesn&#39;t exist
</span></span></span></code></pre></div><h3 id="special-targets">Special Targets</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">clean</span> <span class="n">test</span> <span class="n">install</span>      <span class="c"># Declare phony targets
</span></span></span><span class="line"><span class="cl"><span class="nf">.PRECIOUS</span><span class="o">:</span> %.<span class="n">o</span>                  <span class="c"># Preserve intermediate files
</span></span></span><span class="line"><span class="cl"><span class="nf">.SECONDARY</span><span class="o">:</span>                     <span class="c"># All intermediate files are secondary
</span></span></span><span class="line"><span class="cl"><span class="nf">.DELETE_ON_ERROR</span><span class="o">:</span>               <span class="c"># Delete target file if command errors
</span></span></span></code></pre></div><h3 id="tips-and-tricks">Tips and Tricks</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">all</span><span class="o">:</span> <span class="k">$(</span><span class="nv">object</span><span class="k">)</span>                      <span class="c"># make finds dependencies then executes commands
</span></span></span><span class="line"><span class="cl">                                    <span class="c1"># doesn&#39;t have to compile to &#39;all&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nf">$(object) </span><span class="o">:</span> ...
</span></span><span class="line"><span class="cl">    ...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">gcc</span> <span class="err">-MM</span> <span class="err">hello.c</span>                     <span class="c"># Find header dependencies for hello.c
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">dev</span><span class="o">:</span> <span class="n">mymodule</span>.<span class="n">so</span>
</span></span><span class="line"><span class="cl">    @echo <span class="s2">&#34;Development build complete&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">test</span><span class="o">:</span> <span class="n">dev</span>                           <span class="c"># Set prerequisite tasks for multi-language development
</span></span></span><span class="line"><span class="cl">    <span class="k">$(</span>PYTHON<span class="k">)</span> -c <span class="s2">&#34;import mymodule; print(mymodule.hello())&#34;</span>
</span></span></code></pre></div><hr>
]]></content:encoded></item></channel></rss>