<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><generator uri="https://gohugo.io/" version="0.101.0">Hugo</generator><title type="html">static on A Scripter's Notes</title><subtitle type="html">Emacs, scripting and anything text oriented.</subtitle><link href="https://scripter.co/tags/static/" rel="alternate" type="text/html" title="HTML"/><link href="https://scripter.co/tags/static/index.xml" rel="alternate" type="application/rss+xml" title="RSS"/><link href="https://scripter.co/tags/static/atom.xml" rel="self" type="application/atom+xml" title="Atom"/><link href="https://scripter.co/tags/static/jf2feed.json" rel="alternate" type="application/jf2feed+json" title="jf2feed"/><updated>2026-04-22T08:24:58-04:00</updated><author><name>Kaushal Modi</name><email>kaushal.modi@gmail.com</email></author><id>https://scripter.co/tags/static/</id><entry><title type="html">Generics (not exactly) in SystemVerilog</title><link href="https://scripter.co/generics-not-exactly-in-systemverilog/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/sidenotes-using-ox-hugo/?utm_source=atom_feed" rel="related" type="text/html" title="Sidenotes using ox-hugo"/><link href="https://scripter.co/sidenotes-using-only-css/?utm_source=atom_feed" rel="related" type="text/html" title="Sidenotes using only CSS"/><link href="https://scripter.co/nim-deploying-static-binaries/?utm_source=atom_feed" rel="related" type="text/html" title="Nim: Deploying static binaries"/><id>https://scripter.co/generics-not-exactly-in-systemverilog/</id><author><name>Kaushal Modi</name></author><published>2022-02-11T01:48:00-05:00</published><updated>2022-02-11T01:48:00-05:00</updated><content type="html"><![CDATA[<blockquote>Using <em>parameterized classes</em> with <em>static functions</em> to make up for
the lack of generics in SystemVerilog.</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#a-real-generics-example">A real <em>Generics</em> example</a></li>
<li><a href="#poor-man-s-generics-in-systemverilog"><em>Poor man&rsquo;s Generics</em> in SystemVerilog</a>
<ul>
<li><a href="#parameterized-classes">Parameterized Classes</a></li>
<li><a href="#static-methods">Static methods</a></li>
<li><a href="#should-compile-with-all-types-t">Should compile with all types <em>T</em></a></li>
</ul>
</li>
<li><a href="#final-code">Final Code</a></li>
<li><a href="#cluelib">Cluelib</a></li>
</ul>
</div>
<!--endtoc-->
<p>Many modern languages like <a href="https://nim-lang.org">Nim</a> allow defining <em>Generic</em> functions
types, etc that can work for any type. See Nim Manual <a href="#citeproc_bib_item_2">2022</a> <em>Generics</em>.</p>
<p>This post demonstrates how you can make generics <em>kind of</em> (if you
really squint your eyes, you can see it 😄) work with
SystemVerilog.</p>

<h2 id="a-real-generics-example">A real <em>Generics</em> example&nbsp;<a class="headline-hash no-text-decoration" href="#a-real-generics-example">#</a></h2>


<p>The focus of this post is not how to write generics in Nim, but here&rsquo;s
a quick summary:</p>
<ul>
<li><a href="#org-coderef--51b0fc-1">Line 1</a> overloads the <code>+</code> operator for any type <code>T</code>.</li>
<li><a href="#org-coderef--51b0fc-2">Line 2</a> is a <strong>compile time</strong> check (using <code>when</code>) to
see if <code>T</code> is a <em>string</em>, and then concatenates <em>a</em> and <em>b</em> inputs
using the <code>&amp;</code> <em>string concat</em> operator.</li>
<li>For <a href="#org-coderef--51b0fc-4">other types</a>, it does the expected &ldquo;a + b&rdquo;.</li>
</ul>
<!--listend-->
<p><a id="code-snippet--code-generics-nim"></a></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt" id="org-coderef--51b0fc-1"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-1">1</a>
</span><span class="lnt" id="org-coderef--51b0fc-2"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-2">2</a>
</span><span class="lnt" id="org-coderef--51b0fc-3"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-3">3</a>
</span><span class="lnt" id="org-coderef--51b0fc-4"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-4">4</a>
</span><span class="lnt" id="org-coderef--51b0fc-5"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-5">5</a>
</span><span class="lnt" id="org-coderef--51b0fc-6"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-6">6</a>
</span><span class="lnt" id="org-coderef--51b0fc-7"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-7">7</a>
</span><span class="lnt" id="org-coderef--51b0fc-8"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-8">8</a>
</span><span class="lnt" id="org-coderef--51b0fc-9"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--51b0fc-9">9</a>
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-nim" data-lang="nim"><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">`+`</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">T</span><span class="p">):</span> <span class="n">T</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="k">when</span> <span class="n">T</span> <span class="ow">is</span> <span class="kt">string</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">a</span> <span class="o">&amp;</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">echo</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="n">echo</span> <span class="mf">100.1</span> <span class="o">+</span> <span class="mf">100.2</span>
</span></span><span class="line"><span class="cl"><span class="n">echo</span> <span class="s">&#34;x&#34;</span> <span class="o">+</span> <span class="s">&#34;y&#34;</span> <span class="o">+</span> <span class="s">&#34;z&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--code-generics-nim">Code Snippet 1</a>:</span>
  Example of generics in Nim
</div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">3
</span></span><span class="line"><span class="cl">200.3
</span></span><span class="line"><span class="cl">xyz
</span></span></code></pre></div><p>We will now see how to write something like this in SystemVerilog.</p>

<h2 id="poor-man-s-generics-in-systemverilog"><em>Poor man&rsquo;s Generics</em> in SystemVerilog&nbsp;<a class="headline-hash no-text-decoration" href="#poor-man-s-generics-in-systemverilog">#</a></h2>


<p>SystemVerilog is a strongly typed compiled language. So you need to
define the types for <em>function</em> and <em>task</em> arguments.</p>
<p>So if you need an <em>add</em> function for integers, you would do:</p>
<p><a id="code-snippet--sv-add-int"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-systemverilog" data-lang="systemverilog"><span class="line"><span class="cl"><span class="k">function</span> <span class="k">int</span> <span class="n">add_int</span><span class="p">(</span><span class="k">input</span> <span class="k">int</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">endfunction</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--sv-add-int">Code Snippet 2</a>:</span>
  <code>add_int</code> for adding integers
</div>
<p>If you need an <em>add</em> function for real numbers, you would do:</p>
<p><a id="code-snippet--sv-add-real"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-systemverilog" data-lang="systemverilog"><span class="line"><span class="cl"><span class="k">function</span> <span class="k">real</span> <span class="n">add_real</span><span class="p">(</span><span class="k">input</span> <span class="k">real</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">endfunction</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--sv-add-real">Code Snippet 3</a>:</span>
  <code>add_real</code> for adding reals (doubles)
</div>
<p>I am using the <strong>add</strong> functions here only to demonstrate the
concept. In real world code, you would come across many cases where
you would want to avoid such function redefinitions. Some examples
are: dealing with objects of different classes, or queues with
elements of different types (e.g. queues of <em>ints</em>, queues of
<em>strings</em>), or dynamic arrays of different types, etc.</p>

<h3 id="parameterized-classes">Parameterized Classes&nbsp;<a class="headline-hash no-text-decoration" href="#parameterized-classes">#</a></h3>


<p>In <a href="#code-snippet--sv-add-int"><code>add_int</code></a>, we see that the type <code>int</code> has to be specified in the
function signature. That <code>int</code> can be replaced by a <em>parameter</em>
representing a <em>type</em> only if that function is defined inside a
<em>parameterized class</em> (See <span style="color:grey;">§</span> <strong>Parameterized classes</strong> <a href="#citeproc_bib_item_1">2018, sec. 8.25</a>).</p>
<p>So it would look like this:</p>
<p><a id="code-snippet--parameterized-class1-sv"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-systemverilog" data-lang="systemverilog"><span class="line"><span class="cl"><span class="k">class</span> <span class="n">math</span> <span class="p">#(</span><span class="k">parameter</span> <span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="k">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">function</span> <span class="n">T</span> <span class="n">add</span><span class="p">(</span><span class="k">input</span> <span class="n">T</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">endfunction</span>
</span></span><span class="line"><span class="cl"><span class="k">endclass</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--parameterized-class1-sv">Code Snippet 4</a>:</span>
  Parameterized class and method
</div>
<p>This code, though has a problem &mdash; In order to call that function, we
would first need to construct an object of that class for each type
<em>T</em> we plan to use.</p>

<h3 id="static-methods">Static methods&nbsp;<a class="headline-hash no-text-decoration" href="#static-methods">#</a></h3>


<p>The solution to that is to declare the methods/functions in the class
as <strong>static</strong>. That way, that method can be called directly without
constructing the object first. See <span style="color:grey;">§</span> <strong>Static methods</strong> <a href="#citeproc_bib_item_1">2018, sec. 8.10</a>.</p>
<p>And because we don&rsquo;t need to construct an object of that class, and
don&rsquo;t want anyone else to unnecessary construct it, we declare the
class as <em>virtual</em>.</p>
<p><a id="code-snippet--parameterized-class2-sv"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-systemverilog" data-lang="systemverilog"><span class="line hl"><span class="cl"><span class="k">virtual</span> <span class="k">class</span> <span class="n">math</span> <span class="p">#(</span><span class="k">parameter</span> <span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="k">int</span><span class="p">);</span>
</span></span><span class="line hl"><span class="cl">  <span class="k">static</span> <span class="k">function</span> <span class="n">T</span> <span class="n">add</span><span class="p">(</span><span class="k">input</span> <span class="n">T</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">endfunction</span>
</span></span><span class="line"><span class="cl"><span class="k">endclass</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--parameterized-class2-sv">Code Snippet 5</a>:</span>
  Virtual parameterized class and <b>static</b> method
</div>
<p>Now we can call <code class="code-inline language-systemverilog"><span class="n">math</span> <span class="p">#(</span><span class="k">int</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="mh">1</span><span class="p">,</span> <span class="mh">2</span><span class="p">)</span></code> and <code class="code-inline language-systemverilog"><span class="n">math</span> <span class="p">#(</span><span class="k">real</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="mf">100.1</span><span class="p">,</span> <span class="mf">100.2</span><span class="p">)</span></code> and get the expected results.</p>

<h3 id="should-compile-with-all-types-t">Should compile with all types <em>T</em>&nbsp;<a class="headline-hash no-text-decoration" href="#should-compile-with-all-types-t">#</a></h3>


<p>But.. what if the type <em>T</em> is <em>string</em> ..</p>
<p><code>$typename</code> system function (See <span style="color:grey;">§</span> <strong>Type name function</strong> <a href="#citeproc_bib_item_1">2018, sec. 20.6.1</a>) comes to our help here. This function takes in a
variable identifier and returns a string name of that variable&rsquo;s
type. So if a variable <em>x</em> is a <em>string</em>, <code>$typename(x)</code> will return
<code>&quot;string&quot;</code>.</p>
<p>So, we can define the <code>add</code> method like this, right?</p>
<p><a id="code-snippet--parameterized-class3-sv"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-systemverilog" data-lang="systemverilog"><span class="line"><span class="cl"><span class="k">virtual</span> <span class="k">class</span> <span class="n">math</span> <span class="p">#(</span><span class="k">parameter</span> <span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="k">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">static</span> <span class="k">function</span> <span class="n">T</span> <span class="n">add</span><span class="p">(</span><span class="k">input</span> <span class="n">T</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
</span></span><span class="line hl"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">$typename</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;string&#34;</span><span class="p">)</span>
</span></span><span class="line hl"><span class="cl">      <span class="k">return</span> <span class="p">{</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">endfunction</span>
</span></span><span class="line"><span class="cl"><span class="k">endclass</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--parameterized-class3-sv">Code Snippet 6</a>:</span>
  <code>add</code> method with a condition for <i>string</i> type &#x2013; Won't compile!
</div>
<p>❌ <strong>Wrong</strong> ❌</p>
<div class="note">
<p>Even if you have the code execute conditionally based on the
<code>$typename</code>, note that the <code class="code-inline language-systemverilog"><span class="k">if</span> <span class="p">(</span><span class="n">$typename</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;string&#34;</span><span class="p">)</span></code> check is happening at run time, and so the
<strong>entire code</strong> needs to compile for any type <em>T</em> that&rsquo;s planned to be
used.</p>
</div>
<p>In the above example, because the <code>{a, b}</code> concatenation isn&rsquo;t meant
for types like <em>ints</em> and <em>reals</em>, it will fail compilation.
<span class="sidenote-number"><small class="sidenote">
That&rsquo;s the reason for the &ldquo;(not exactly)&rdquo; in this post&rsquo;s title 😄
</small></span></p>
<p>In order to make <code>add</code> work with strings as well, we need this messy
<em>cast</em> when the type name is <em>&ldquo;string&rdquo;</em> : <code class="code-inline language-systemverilog"><span class="n">$cast</span><span class="p">(</span><span class="n">ret_val</span><span class="p">,</span> <span class="nb">$sformatf</span><span class="p">(</span><span class="s">&#34;%s%s&#34;</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">));</span></code>. It&rsquo;s basically
telling the compiler: &ldquo;Trust me, I know what I am doing.. I will be
executing this code only when the <em>ret_val</em> is a string.&rdquo;</p>

<h2 id="final-code">Final Code&nbsp;<a class="headline-hash no-text-decoration" href="#final-code">#</a></h2>


<p>Finally, here&rsquo;s the entire code with the <em>generic</em> <code>add</code> method and
some test code.</p>
<p><a id="code-snippet--math-sv"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-systemverilog" data-lang="systemverilog"><span class="line"><span class="cl"><span class="k">virtual</span> <span class="k">class</span> <span class="n">math</span> <span class="p">#(</span><span class="k">parameter</span> <span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="k">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">static</span> <span class="k">function</span> <span class="n">T</span> <span class="n">add</span><span class="p">(</span><span class="k">input</span> <span class="n">T</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">$typename</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">==</span> <span class="s">&#34;string&#34;</span><span class="p">)</span> <span class="k">begin</span>
</span></span><span class="line"><span class="cl">      <span class="n">T</span> <span class="n">ret_val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="n">$cast</span><span class="p">(</span><span class="n">ret_val</span><span class="p">,</span> <span class="nb">$sformatf</span><span class="p">(</span><span class="s">&#34;%s%s&#34;</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">ret_val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span> <span class="k">else</span> <span class="k">begin</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">endfunction</span> <span class="o">:</span> <span class="n">add</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">endclass</span> <span class="o">:</span> <span class="n">math</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">module</span> <span class="n">test</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">$display</span><span class="p">(</span><span class="s">&#34;1 + 2 = %p&#34;</span><span class="p">,</span> <span class="n">math</span> <span class="p">#(</span><span class="k">int</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="mh">1</span><span class="p">,</span> <span class="mh">2</span><span class="p">));</span>                <span class="c1">// 3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nb">$display</span><span class="p">(</span><span class="s">&#34;1.1 + 2.2 = %p&#34;</span><span class="p">,</span> <span class="n">math</span> <span class="p">#(</span><span class="k">real</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="mf">1.1</span><span class="p">,</span> <span class="mf">2.2</span><span class="p">));</span>       <span class="c1">// 3.3
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nb">$display</span><span class="p">(</span><span class="s">&#34;1 + 1 = %p&#34;</span><span class="p">,</span> <span class="n">math</span> <span class="p">#(</span><span class="k">bit</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="mh">1</span><span class="p">,</span> <span class="mh">1</span><span class="p">));</span>                <span class="c1">// 0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nb">$display</span><span class="p">(</span><span class="s">&#34;abc + def = %p&#34;</span><span class="p">,</span> <span class="n">math</span> <span class="p">#(</span><span class="k">string</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="s">&#34;abc&#34;</span><span class="p">,</span> <span class="s">&#34;def&#34;</span><span class="p">));</span> <span class="c1">// &#34;abcdef&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="nb">$finish</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">endmodule</span> <span class="o">:</span> <span class="n">test</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--math-sv">Code Snippet 7</a>:</span>
  Parameterized class <code>math</code> with <i>static</i> function <code>add</code>
</div>

<h2 id="cluelib">Cluelib&nbsp;<a class="headline-hash no-text-decoration" href="#cluelib">#</a></h2>


<p>If you liked how these <em>&ldquo;generics&rdquo;</em> work in SystemVerilog and how the
<code class="code-inline language-systemverilog"><span class="n">math</span> <span class="p">#(</span><span class="k">int</span><span class="p">)</span><span class="o">::</span><span class="n">add</span><span class="p">(</span><span class="mh">1</span><span class="p">,</span> <span class="mh">2</span><span class="p">));</span></code> syntax
looks, check out the <a href="https://github.com/cluelogic/cluelib"><strong>cluelib</strong></a> library by <em>cluelogic.com</em>. It is an
amazing SystemVerilog library with a big collection of <em>&ldquo;generic&rdquo;</em>
functions like above for handling strings, queues and dynamic arrays,
and a lot more. You can take a peek at its API <a href="http://cluelogic.com/tools/cluelib/api/framed_html/index.html">here</a>.</p>

<h2 id="references">References&nbsp;<a class="headline-hash no-text-decoration" href="#references">#</a></h2>


<div class="csl-bib-body">
  <div class="csl-entry"><a id="citeproc_bib_item_1"></a>IEEE Standard for SystemVerilog–Unified Hardware Design, Specification, and Verification Language. (2018). <i>IEEE Std 1800-2017 (Revision of IEEE Std 1800-2012)</i>, 1–1315. <a href="https://doi.org/10.1109/IEEESTD.2018.8299595">https://doi.org/10.1109/IEEESTD.2018.8299595</a></div>
  <div class="csl-entry"><a id="citeproc_bib_item_2"></a>Nim contributors. (2022). Nim Manual [Website]. In <i>Nim</i>. <a href="https://nim-lang.org/docs/manual.html">https://nim-lang.org/docs/manual.html</a></div>
</div>
]]></content><category scheme="https://scripter.co/categories/systemverilog" term="systemverilog" label="systemverilog"/><category scheme="https://scripter.co/tags/parameterized-classes" term="parameterized-classes" label="parameterized-classes"/><category scheme="https://scripter.co/tags/typename" term="typename" label="typename"/><category scheme="https://scripter.co/tags/static" term="static" label="static"/><category scheme="https://scripter.co/tags/methods" term="methods" label="methods"/><category scheme="https://scripter.co/tags/generics" term="generics" label="generics"/><category scheme="https://scripter.co/tags/100daystooffload" term="100daystooffload" label="100DaysToOffload"/></entry><entry><title type="html">Nim: Deploying static binaries</title><link href="https://scripter.co/nim-deploying-static-binaries/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/nim-fizz-buzz-test/?utm_source=atom_feed" rel="related" type="text/html" title="Nim: Fizz-Buzz test"/><link href="https://scripter.co/notes/nim-fmt/?utm_source=atom_feed" rel="related" type="text/html" title="Nim fmt"/><link href="https://scripter.co/notes/nim/?utm_source=atom_feed" rel="related" type="text/html" title="Nim"/><link href="https://scripter.co/nim-check-if-stdin-stdout-are-associated-with-terminal-or-pipe/?utm_source=atom_feed" rel="related" type="text/html" title="Nim: Check if stdin/stdout are associated with terminal or pipe"/><link href="https://scripter.co/accessing-devdocs-from-emacs/?utm_source=atom_feed" rel="related" type="text/html" title="Accessing Devdocs from Emacs"/><id>https://scripter.co/nim-deploying-static-binaries/</id><author><name>Kaushal Modi</name></author><published>2018-09-24T01:47:00-04:00</published><updated>2018-09-24T01:47:00-04:00</updated><content type="html"><![CDATA[<blockquote>Deploying Nim applications as static binaries for GNU/Linux type
operating systems, built using <strong>musl</strong>.</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#problem-statement">Problem statement</a></li>
<li><a href="#solution">Solution</a></li>
<li><a href="#1-building-static-binaries">1 Building static binaries</a>
<ul>
<li><a href="#what-is-musl">What is musl?</a></li>
<li><a href="#installing-musl">Installing musl</a></li>
<li><a href="#static-linking">Static linking</a></li>
</ul>
</li>
<li><a href="#2-optimizing-the-binary-size">2 Optimizing the binary size</a></li>
<li><a href="#3-doing-the-above-two-easily">3 Doing the above two easily</a>
<ul>
<li><a href="#nimscript">NimScript</a></li>
<li><a href="#config-dot-nims"><code>config.nims</code></a></li>
</ul>
</li>
<li><a href="#4-creating-and-deploying-the-builds-automatically">4 Creating and deploying the builds automatically</a></li>
<li><a href="#how-it-works-in-practice">How it works in practice</a></li>
<li><a href="#repo">Repo</a></li>
<li><a href="#references">References</a></li>
</ul>
</div>
<!--endtoc-->

<h2 id="problem-statement">Problem statement&nbsp;<a class="headline-hash no-text-decoration" href="#problem-statement">#</a></h2>


<p>I&rsquo;d like to create Nim applications, and then be able to easily deploy
the static built binaries so that anyone on GNU/Linux type OS can just
download the binary and run them.</p>
<p><em>If and when I figure out how to do the same for macOS and Windows
too, I&rsquo;ll write a separate post for that. If you can help me out with
that, please comment below, or open an issue/PR in the repo linked at
the end.</em></p>

<h2 id="solution">Solution&nbsp;<a class="headline-hash no-text-decoration" href="#solution">#</a></h2>


<p>The solution is multi-step:</p>
<ol>
<li>Building static binaries (only for GNU/Linux type OS).</li>
<li>Optimizing the binary size.</li>
<li>Doing the above two easily.</li>
<li>Creating and deploying the builds automatcally (on GitHub).</li>
</ol>

<h2 id="1-building-static-binaries">1 Building static binaries&nbsp;<a class="headline-hash no-text-decoration" href="#1-building-static-binaries">#</a></h2>


<p>My primary OS for coding and development is RHEL 6.8.</p>
<p>By default, Nim builds dynamically linked binaries using the <em>glibc</em>
version present on the OS where those binaries are built.</p>
<p>Living on a stable but <span class="underline">old</span> OS like RHEL 6.8 (that has <em>glibc 2.12</em>
by default), I have ended up with the issue many a times<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> where
the deployed binary would be compiled with a newer <em>glibc</em> and so it
wouldn&rsquo;t run on my system. I would need to eventually compile that
binary myself.</p>
<p>I don&rsquo;t want to inflict other people with the same problem.</p>
<p>Inspired by how statically compiled binaries are distributed for tools
built in other languages (<a href="https://github.com/gohugoio/hugo/releases">hugo</a> [Go], <a href="https://github.com/BurntSushi/ripgrep/releases">ripgrep</a> [Rust], <a href="https://github.com/jgm/pandoc/releases">pandoc</a> [Haskell],
etc), I wanted the same for whatever I build with Nim.</p>
<p>I kept looking around for a &ldquo;single press button&rdquo; flow to do this in
Nim for a while, and after finding nothing, I came up a flow myself,
that I present in this post.</p>
<p>I picked <strong>musl</strong> to statically compile my binaries.</p>

<h3 id="what-is-musl">What is musl?&nbsp;<a class="headline-hash no-text-decoration" href="#what-is-musl">#</a></h3>


<p>Here&rsquo;s a one-liner description from <a href="https://en.wikipedia.org/wiki/Musl">Wikipedia</a>:</p>
<blockquote>
<p><strong>musl</strong> is a C standard library intended for operating systems based on
the Linux kernel, released under the MIT License.</p>
</blockquote>
<p>Check out its <a href="https://www.musl-libc.org/intro.html">introduction</a> on its official webpage for more details.</p>

<h3 id="installing-musl">Installing musl&nbsp;<a class="headline-hash no-text-decoration" href="#installing-musl">#</a></h3>


<p>Installing musl was as simple as <a href="https://www.musl-libc.org/download.html">downloading</a> its <em>.tar.gz</em> and running
<code>make &amp;&amp; make install</code> with the <code>--prefix</code> configured
appropriately. For the examples that follow, let&rsquo;s say you set the
prefix to <code>/usr/local/musl/</code>.</p>
<div class="note">
<p>Do <strong>not</strong> install musl at the default <em>prefix</em> location, else it will
override a lot of default header files &ndash; an outcome that you probably
don&rsquo;t want.</p>
</div>
<ul>
<li>With the <em>prefix</em> set as above, the <code>musl-gcc</code> binary would get
installed in the <code>/usr/local/musl/bin/</code> directory.</li>
<li>Add <code>/usr/local/musl/bin/</code> to your <code>PATH</code> environment variable.</li>
</ul>

<h3 id="static-linking">Static linking&nbsp;<a class="headline-hash no-text-decoration" href="#static-linking">#</a></h3>


<p>By default, Nim will use the <code>gcc</code> executable that&rsquo;s found in <code>PATH</code>
for C compilation. But using the <code>--gcc.exe</code> switch, we override to
use the <code>musl-gcc</code> executable. Similarly, we use the <code>--gcc.linkerexe</code>
switch to use <code>musl-gcc</code> too, and then the <code>-static</code> option is passed
to the linker using the <code>--passL</code> switch.</p>
<p>With a <code>hello.nim</code> containing:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nim" data-lang="nim"><span class="line"><span class="cl"><span class="n">echo</span> <span class="s">&#34;Hello, World!&#34;</span>
</span></span></code></pre></div><p>running the below:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Assuming that musl-gcc binary is found in PATH.</span>
</span></span><span class="line"><span class="cl">nim --gcc.exe:musl-gcc --gcc.linkerexe:musl-gcc --passL:-static c hello.nim
</span></span></code></pre></div><p>I got a <em>98kB</em> statically linked <code>hello</code> binary.</p>

<h2 id="2-optimizing-the-binary-size">2 Optimizing the binary size&nbsp;<a class="headline-hash no-text-decoration" href="#2-optimizing-the-binary-size">#</a></h2>


<p>The binary size can be optimized by Nim itself by doing a Release
build (<code>-d:release</code>) which disables runtime checks used for debugging,
and enables certain optimizations. Adding <code>--opt:size</code> does further
binary-size optimization.</p>
<p>So, with the same <code>hello.nim</code>, running the below:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Assuming that musl-gcc binary is found in PATH.</span>
</span></span><span class="line"><span class="cl">nim --gcc.exe:musl-gcc --gcc.linkerexe:musl-gcc --passL:-static -d:release --opt:size c hello.nim
</span></span></code></pre></div><p>shrunk down the binary size to <em>43kB</em>.</p>
<p>Upon running external utilities like <a href="https://sourceware.org/binutils/docs/binutils/strip.html"><code>strip</code> (from <code>binutils</code>)</a><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>
and <a href="https://github.com/upx/upx"><code>upx</code></a><sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, the binary size shrunk even further! &ndash; <strong>16kB</strong>.</p>
<p><a id="code-snippet--musl-plus-opt"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Assuming that musl-gcc binary is found in PATH.</span>
</span></span><span class="line"><span class="cl">nim --gcc.exe:musl-gcc --gcc.linkerexe:musl-gcc --passL:-static -d:release --opt:size c hello.nim
</span></span><span class="line"><span class="cl">strip -s ./hello
</span></span><span class="line"><span class="cl">upx --best ./hello
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--musl-plus-opt">Code Snippet 1</a>:</span>
  Static linking using <code>musl-gcc</code> plus binary size optimization
</div>

<h2 id="3-doing-the-above-two-easily">3 Doing the above two easily&nbsp;<a class="headline-hash no-text-decoration" href="#3-doing-the-above-two-easily">#</a></h2>


<p>All of that is great, but it wouldn&rsquo;t be fun or elegant to do all the
steps in <a href="#code-snippet--musl-plus-opt">Code Snippet 1</a> manually (or even in a <em>shell</em> script).</p>
<p>Wouldn&rsquo;t it be awesome if I could just run a <code>nim musl hello.nim</code> command‽</p>
<div class="verse">
<p>    &mdash; And that&rsquo;s what I do! 😎<br /></p>
</div>

<h3 id="nimscript">NimScript&nbsp;<a class="headline-hash no-text-decoration" href="#nimscript">#</a></h3>


<p>The &ldquo;nim musl&rdquo; command is not available out-of-box, but it is easy to
create one using a <a href="https://nim-lang.org/docs/nims.html">NimScript config file</a>, which is in the form of a
project-specific <code>config.nims</code>.</p>
<div class="note">
<p>Think of NimScripts as much superior &ldquo;bash scripts&rdquo; as they are
written in Nim 😄</p>
</div>
<p>From the <a href="https://nim-lang.org/docs/nims.html">NimScript docs</a>:</p>
<blockquote>
<p>Strictly speaking, NimScript is the subset of Nim that can be
evaluated by Nim&rsquo;s builtin virtual machine (VM). This VM is used for
Nim&rsquo;s compiletime function evaluation features, but also replaces
Nim&rsquo;s existing configuration system.</p>
<p>The VM cannot deal with <code>importc</code>, the FFI is not available, so there
are not many stdlib modules that you can use with Nim&rsquo;s VM. However,
at least the following modules are available:</p>
<ul>
<li><a href="https://nim-lang.org/docs/strutils.html">strutils</a></li>
<li><a href="https://nim-lang.org/docs/math.html">math</a></li>
<li><a href="https://nim-lang.org/docs/distros.html">distros</a></li>
</ul>
</blockquote>
<p>That list of modules is not comprehensive. I believe that the <a href="https://nim-lang.org/docs/macros.html">macros</a>
module should be added to that list too (we also happen to need it for
the <code>error</code> macros in the <code>config.nims</code> below 😄).</p>
<p>So, instead of having to resort to the hacky bash scripts, NimScript
allows one to write scripts in the awesome Nim syntax, and it&rsquo;s
platform-agnostic too!</p>
<p>Also, as you see below, the <em>tasks</em> in NimScripts basically become
user-defined Nim-subcommands. For example, &ldquo;nim musl&rdquo; command doesn&rsquo;t
exist, but I could make one <em>just like that</em> by defining a &ldquo;musl&rdquo;
NimScript <em>task</em>.</p>

<h3 id="config-dot-nims"><code>config.nims</code>&nbsp;<a class="headline-hash no-text-decoration" href="#config-dot-nims">#</a></h3>


<p>Below <code>config.nims</code> is generic and would work for most Nim
projects. You need to just put it in the directory from where you
compile the Nim code.</p>
<p><em>Nim <strong>devel</strong> (v0.18.1) is needed for the below NimScript to work,
because the <code>findExe</code> I use in there was not present in Nim v0.18.0.</em></p>
<p><a id="code-snippet--musl-config-nims"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nim" data-lang="nim"><span class="line"><span class="cl"><span class="c"># config.nims</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="n">macros</span> <span class="kn">import</span> <span class="n">error</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="n">ospaths</span> <span class="kn">import</span> <span class="n">splitFile</span><span class="p">,</span> <span class="p">`</span><span class="o">/</span><span class="p">`</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># -d:musl</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="n">defined</span><span class="p">(</span><span class="n">musl</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="n">muslGccPath</span><span class="p">:</span> <span class="kt">string</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;  [-d:musl] Building a static binary using musl ..&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">muslGccPath</span> <span class="o">=</span> <span class="n">findExe</span><span class="p">(</span><span class="s">&#34;musl-gcc&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo &#34;debug: &#34; &amp; muslGccPath</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">muslGccPath</span> <span class="o">==</span> <span class="s">&#34;&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">error</span><span class="p">(</span><span class="s">&#34;&#39;musl-gcc&#39; binary was not found in PATH.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">switch</span><span class="p">(</span><span class="s">&#34;gcc.exe&#34;</span><span class="p">,</span> <span class="n">muslGccPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">switch</span><span class="p">(</span><span class="s">&#34;gcc.linkerexe&#34;</span><span class="p">,</span> <span class="n">muslGccPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">switch</span><span class="p">(</span><span class="s">&#34;passL&#34;</span><span class="p">,</span> <span class="s">&#34;-static&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">binOptimize</span><span class="p">(</span><span class="n">binFile</span><span class="p">:</span> <span class="kt">string</span><span class="p">)</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="sd">## Optimize size of the ``binFile`` binary.</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">findExe</span><span class="p">(</span><span class="s">&#34;strip&#34;</span><span class="p">)</span> <span class="o">!=</span> <span class="s">&#34;&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">echo</span> <span class="s">&#34;Running &#39;strip -s&#39; ..&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">exec</span> <span class="s">&#34;strip -s &#34;</span> <span class="o">&amp;</span> <span class="n">binFile</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">findExe</span><span class="p">(</span><span class="s">&#34;upx&#34;</span><span class="p">)</span> <span class="o">!=</span> <span class="s">&#34;&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c"># https://github.com/upx/upx/releases/</span>
</span></span><span class="line"><span class="cl">    <span class="n">echo</span> <span class="s">&#34;Running &#39;upx --best&#39; ..&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">exec</span> <span class="s">&#34;upx --best &#34;</span> <span class="o">&amp;</span> <span class="n">binFile</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># nim musl foo.nim</span>
</span></span><span class="line"><span class="cl"><span class="n">task</span> <span class="n">musl</span><span class="p">,</span> <span class="s">&#34;Builds an optimized static binary using musl&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="sd">## Usage: nim musl &lt;.nim file path&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="k">let</span>
</span></span><span class="line"><span class="cl">    <span class="n">numParams</span> <span class="o">=</span> <span class="n">paramCount</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">numParams</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">error</span><span class="p">(</span><span class="s">&#34;The &#39;musl&#39; sub-command needs exactly 1 argument, the Nim file (but &#34;</span> <span class="o">&amp;</span>
</span></span><span class="line"><span class="cl">      <span class="o">$</span><span class="p">(</span><span class="n">numParams</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="s">&#34; were detected).&#34;</span> <span class="o">&amp;</span>
</span></span><span class="line"><span class="cl">      <span class="s">&#34;</span><span class="se">\n</span><span class="s">  Usage Example: nim musl FILE.nim.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">let</span>
</span></span><span class="line"><span class="cl">    <span class="n">nimFile</span> <span class="o">=</span> <span class="n">paramStr</span><span class="p">(</span><span class="n">numParams</span><span class="p">)</span> <span class="sd">## The nim file name *must* be the last.</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">dirName</span><span class="p">,</span> <span class="n">baseName</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="o">=</span> <span class="n">splitFile</span><span class="p">(</span><span class="n">nimFile</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">binFile</span> <span class="o">=</span> <span class="n">dirName</span> <span class="o">/</span> <span class="n">baseName</span>  <span class="c"># Save the binary in the same dir as the nim file</span>
</span></span><span class="line"><span class="cl">    <span class="n">nimArgs</span> <span class="o">=</span> <span class="s">&#34;c -d:musl -d:release --opt:size &#34;</span> <span class="o">&amp;</span> <span class="n">nimFile</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo &#34;[debug] nimFile = &#34; &amp; nimFile &amp; &#34;, binFile = &#34; &amp; binFile</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c"># Build binary</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">Running &#39;nim &#34;</span> <span class="o">&amp;</span> <span class="n">nimArgs</span> <span class="o">&amp;</span> <span class="s">&#34;&#39; ..&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">selfExec</span> <span class="n">nimArgs</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c"># Optimize binary</span>
</span></span><span class="line"><span class="cl">  <span class="n">binOptimize</span><span class="p">(</span><span class="n">binFile</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">Created binary: &#34;</span> <span class="o">&amp;</span> <span class="n">binFile</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--musl-config-nims">Code Snippet 2</a>:</span>
  <code>config.nims</code> defining the <b>musl</b> NimScript <i>task</i>
</div>
<p>Here&rsquo;s a quick breakdown of that script:</p>
<ul>
<li>We first import the modules we would need for the sugar-syntax
<code>error</code> macro, and for basic file path operations.</li>
<li><code>when defined(musl)</code> block is used to do something extra to the nim
command if user has passed a <code>-d:musl</code> switch during compilation
(this custom compile-time define switch is used in the &ldquo;musl&rdquo; task).</li>
<li>The <code>binOptimize</code> is just a Nim <em>proc</em> to contain the outside-Nim
binary size optimization commands.</li>
<li>Finally, the NimScript <a href="https://nim-lang.org/docs/nimscript.html#task.t,untyped,string,untyped"><strong>task</strong></a> &ldquo;musl&rdquo; allows me to define my custom
&ldquo;musl&rdquo; sub-command for <code>nim</code> so that I can run <code>nim musl FOO.nim</code>.</li>
</ul>
<p>With a directory containing this <code>config.nims</code> and a <code>FOO.nim</code>,
running <code>nim musl FOO.nim</code> will be analogous to manually running the
commands in <a href="#code-snippet--musl-plus-opt">Code Snippet 1</a>.</p>

<h2 id="4-creating-and-deploying-the-builds-automatically">4 Creating and deploying the builds automatically&nbsp;<a class="headline-hash no-text-decoration" href="#4-creating-and-deploying-the-builds-automatically">#</a></h2>


<p>All of that is still great, but ..</p>
<div class="verse">
<p>    Wouldn&rsquo;t it be awesome if I could do all of that <strong>automatically</strong> to create static binary releases for my Nim projects‽<br /></p>
</div>
<p>And of course, I can do that too! &ndash; At least on GitHub using Travis
CI.</p>
<p><em>I would also like to know how to do the same on non-GitHub repos
too. If you know, please comment below.</em></p>
<p>Below is a generic <code>.travis.yml</code> that works for a repo name &ldquo;FOO&rdquo; and
containing the Nim code in its &ldquo;src/FOO.nim&rdquo; file. Notes on what this
config file does follow after that snippet.</p>
<p><a id="code-snippet--musl-travis"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">language</span><span class="p">:</span><span class="w"> </span><span class="l">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sudo</span><span class="p">:</span><span class="w"> </span><span class="l">required</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">cache</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">directories</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">nim</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">upx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">env</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">global</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">PROGNAME=&#34;$(basename ${TRAVIS_BUILD_DIR})&#34;</span><span class="w"> </span><span class="c"># /travis/build/kaushalmodi/hello_musl -&gt; hello_musl</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">NIMFILE=&#34;src/${PROGNAME}.nim&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">BINFILE=&#34;src/${PROGNAME}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">ASSETFILE=&#34;${PROGNAME}-${TRAVIS_TAG}.Linux_64bit_musl.tar.xz&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">NIMREPO=&#34;https://github.com/nim-lang/Nim&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">NIMVER=&#34;$(git ls-remote ${NIMREPO} devel | cut -f 1)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">NIMDIR=&#34;${TRAVIS_BUILD_DIR}/nim/${NIMVER}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="l">UPXVER=&#34;3.95&#34;            </span><span class="w"> </span><span class="c"># Change this value when upgrading upx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">addons</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">apt</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># For building MUSL static builds on Linux.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">musl-tools</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">install</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">echo &#34;NIMDIR = ${NIMDIR}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># After building nim, wipe csources to save on cache space.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="s2">&#34;{ [ -f ${NIMDIR}/bin/nim ]; } ||
</span></span></span><span class="line"><span class="cl"><span class="s2">      ( rm -rf nim;
</span></span></span><span class="line"><span class="cl"><span class="s2">        mkdir -p nim;
</span></span></span><span class="line"><span class="cl"><span class="s2">        git clone --single-branch --branch devel --depth=1 ${NIMREPO} ${NIMDIR};
</span></span></span><span class="line"><span class="cl"><span class="s2">        cd ${NIMDIR};
</span></span></span><span class="line"><span class="cl"><span class="s2">        [ -d csources ] || git clone --depth 1 https://github.com/nim-lang/csources.git;
</span></span></span><span class="line"><span class="cl"><span class="s2">        cd csources;
</span></span></span><span class="line"><span class="cl"><span class="s2">        sh build.sh;
</span></span></span><span class="line"><span class="cl"><span class="s2">        cd ..;
</span></span></span><span class="line"><span class="cl"><span class="s2">        ./bin/nim c koch;
</span></span></span><span class="line"><span class="cl"><span class="s2">        ./koch boot -d:release;
</span></span></span><span class="line"><span class="cl"><span class="s2">        rm -rf csources;
</span></span></span><span class="line"><span class="cl"><span class="s2">      )&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">export PATH=&#34;${NIMDIR}/bin:${PATH}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">nim -v</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">echo &#34;Installing upx ..&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="s2">&#34;{ [ -f upx/${UPXVER}/upx ]; } ||
</span></span></span><span class="line"><span class="cl"><span class="s2">      { curl -OL https://github.com/upx/upx/releases/download/v${UPXVER}/upx-${UPXVER}-amd64_linux.tar.xz;
</span></span></span><span class="line"><span class="cl"><span class="s2">        tar xvf upx-${UPXVER}-amd64_linux.tar.xz;
</span></span></span><span class="line"><span class="cl"><span class="s2">        mkdir -p upx;
</span></span></span><span class="line"><span class="cl"><span class="s2">        mv upx-${UPXVER}-amd64_linux upx/${UPXVER};
</span></span></span><span class="line"><span class="cl"><span class="s2">      }&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">export PATH=&#34;${TRAVIS_BUILD_DIR}/upx/${UPXVER}/:${PATH}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">upx --version | grep -E &#39;^upx&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">script</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># Ensure that you are in repo/build root now.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">cd &#34;${TRAVIS_BUILD_DIR}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">echo &#34;NIMFILE = ${NIMFILE}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">echo &#34;BINFILE = ${BINFILE}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># Compile the static binary using musl.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">nim musl &#34;${NIMFILE}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># See that the binary is not dynamic.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">ldd &#34;${BINFILE}&#34; || true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c"># Run the binary.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="s2">&#34;${BINFILE}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">before_deploy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">cd &#34;${TRAVIS_BUILD_DIR}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">cp &#34;${BINFILE}&#34; &#34;${PROGNAME}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">tar caf &#34;${ASSETFILE}&#34; &#34;${PROGNAME}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">deploy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">provider</span><span class="p">:</span><span class="w"> </span><span class="l">releases</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">api_key</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;${GITHUB_OAUTH_TOKEN}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">file</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;${ASSETFILE}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">skip_cleanup</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">tags</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--musl-travis">Code Snippet 3</a>:</span>
  GitHub Travis CI config file to generate musl-built Release assets
</div>
<ul>
<li>I like environment variables to do all the configuration. So I do
that in the <em>env / global</em> block.</li>
<li>Caching is enabled for &ldquo;nim&rdquo; and &ldquo;upx&rdquo; directories, which are
created in the <em>install</em> block.
<ul>
<li>So if the Nim <em>devel</em> branch hasn&rsquo;t been updated since the last
Travis build, the cached Nim build is used.</li>
<li>And similar applies to the <code>upx</code> binary, which relies on the value
of the <code>UPXVER</code> env variable.</li>
</ul>
</li>
<li>In the <em>install</em> block, <code>nim</code> is built from the Nim <em>devel</em> branch
HEAD, and <code>upx</code> binary is downloaded from the Releases section of
its repo.</li>
<li>The key command is <code>nim musl &quot;${NIMFILE}&quot;</code> in the <em>script</em> block,
which uses the <strong>musl</strong> NimScript task defined in the <a href="#code-snippet--musl-config-nims"><code>config.nims</code></a> in
the same repo.</li>
<li>In <em>before_deploy</em>, <code>tar</code> is used to create an archive of the
generated binary.</li>
<li>The <em>deploy</em> section is mainly copy-paste of <a href="https://docs.travis-ci.com/user/deployment/releases/">what&rsquo;s suggested</a> in the
Travis CI documentation.
<ul>
<li>About the <code>${GITHUB_OAUTH_TOKEN}</code>, the first step is to get your
GitHub account&rsquo;s <strong>repo</strong> level token from <a href="https://github.com/settings/tokens">GitHub Tokens settings</a>.</li>
<li>The second step is to create a custom environment variable named
<strong>GITHUB_OAUTH_TOKEN</strong> in that repo&rsquo;s Travis CI settings (ensure
that the variable&rsquo;s value is not made public in the Travis CI&rsquo;s
logs, though they are private by default), and assigning that
token string to that variable.</li>
</ul>
</li>
</ul>

<h2 id="how-it-works-in-practice">How it works in practice&nbsp;<a class="headline-hash no-text-decoration" href="#how-it-works-in-practice">#</a></h2>


<p>Let&rsquo;s assume that the one-time setup for a new repo is already
done. The <code>config.nims</code> and <code>.travis.yml</code> are committed and pushed to
the GitHub repo, and the <code>GITHUB_OAUTH_TOKEN</code> environment variable is
set in the repo&rsquo;s Travis settings.</p>
<p>Now, to auto-generate the assets for each <em>release</em>, all I need to do
is:</p>
<ol>
<li>Commit my changes to the Nim code.</li>
<li>Tag the commit.</li>
<li>Push the commit <strong>and</strong> tag to GitHub.</li>
</ol>

<h2 id="repo">Repo&nbsp;<a class="headline-hash no-text-decoration" href="#repo">#</a></h2>


<p>You can find the latest versions of the above code in my <em>Nim+musl</em>
template repo <a href="https://github.com/kaushalmodi/hello_musl"><strong>hello_musl</strong></a>.</p>
<p>You can also try downloading and running (on a GNU/Linux 64-bit OS)
the deployed static binary from <a href="https://github.com/kaushalmodi/hello_musl/releases">its Releases section</a> and see this
printed in full glory! 😄</p>
<blockquote>
<p>Hello, World!</p>
</blockquote>

<h2 id="references">References&nbsp;<a class="headline-hash no-text-decoration" href="#references">#</a></h2>


<ul>
<li><a href="https://www.reddit.com/r/programming/comments/2wk7q6/static_linking_with_nim/corwtl7/">r/nim &ndash; Static Linking with Nim</a></li>
<li><a href="https://hookrace.net/blog/nim-binary-size/#using-the-c-standard-library">hookrace.net &ndash; Statically linking against musl libc</a></li>
<li><a href="https://github.com/nim-lang/Nim/wiki/Using-NimScript-for-configuration">Using NimScript for configuration</a></li>
<li><a href="https://nim-lang.org/docs/nimscript.html">NimScript &ldquo;API&rdquo;</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://github.com/dom96/choosenim/issues/15">One example</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>The <em>binutils</em> <strong>strip</strong> utility is used to remove complete
symbol tables and other debug info that are not needed for running the
executable.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>From <a href="https://github.com/upx/upx/blob/master/README">its docs</a>, <strong>UPX</strong> is an advanced executable file
compressor. UPX will typically reduce the file size of programs and
DLLs by around 50%-70%, thus reducing disk space, network load times,
download times and other distribution and storage costs.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content><category scheme="https://scripter.co/categories/programming" term="programming" label="programming"/><category scheme="https://scripter.co/tags/nim" term="nim" label="nim"/><category scheme="https://scripter.co/tags/static" term="static" label="static"/><category scheme="https://scripter.co/tags/binary" term="binary" label="binary"/><category scheme="https://scripter.co/tags/musl" term="musl" label="musl"/><category scheme="https://scripter.co/tags/gnu-linux" term="gnu-linux" label="gnu-linux"/><category scheme="https://scripter.co/tags/github" term="github" label="github"/><category scheme="https://scripter.co/tags/travis-ci" term="travis-ci" label="travis-ci"/></entry></feed>