<?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">programming on A Scripter's Notes</title><subtitle type="html">Emacs, scripting and anything text oriented.</subtitle><link href="https://scripter.co/categories/programming/" rel="alternate" type="text/html" title="HTML"/><link href="https://scripter.co/categories/programming/index.xml" rel="alternate" type="application/rss+xml" title="RSS"/><link href="https://scripter.co/categories/programming/atom.xml" rel="self" type="application/atom+xml" title="Atom"/><link href="https://scripter.co/categories/programming/jf2feed.json" rel="alternate" type="application/jf2feed+json" title="jf2feed"/><updated>2026-04-22T08:24:57-04:00</updated><author><name>Kaushal Modi</name><email>kaushal.modi@gmail.com</email></author><id>https://scripter.co/categories/programming/</id><entry><title type="html">Cleaning up ${GOPATH}/pkg/</title><link href="https://scripter.co/cleaning-up-gopath-pkg/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/view-github-pull-requests-in-magit/?utm_source=atom_feed" rel="related" type="text/html" title="View GitHub Pull Requests in Magit"/><link href="https://scripter.co/gujarati-fonts-in-emacs/?utm_source=atom_feed" rel="related" type="text/html" title="Gujarati fonts in Emacs"/><link href="https://scripter.co/emacs-lisp-advice-combinators/?utm_source=atom_feed" rel="related" type="text/html" title="Emacs Lisp: Advice Combinators"/><link href="https://scripter.co/org-show-only-post-subtree-headings/?utm_source=atom_feed" rel="related" type="text/html" title="Org: Show only Post subtree headings"/><link href="https://scripter.co/firefox-always-open-a-new-tab-after-current/?utm_source=atom_feed" rel="related" type="text/html" title="Firefox: Always open a New Tab after Current"/><id>https://scripter.co/cleaning-up-gopath-pkg/</id><author><name>Kaushal Modi</name></author><published>2022-06-25T10:48:00-04:00</published><updated>2022-06-25T10:48:00-04:00</updated><content type="html"><![CDATA[<blockquote>Use <code>go clean -modcache</code> to clean up all the old auto-downloaded Go
modules in <code>${GOPATH}/pkg/</code>. That&rsquo;s all you need to know. Rest of the
post gives just the history of how I got there.</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#the-gopath-directory">The <code>$GOPATH</code> directory</a></li>
<li><a href="#the-disk-space-issue">The disk space issue</a></li>
<li><a href="#write-protected-gopath-pkg">Write-protected <code>${GOPATH}/pkg/</code></a></li>
<li><a href="#cleaning-up-modcache">Cleaning up &ldquo;modcache&rdquo;</a></li>
<li><a href="#wrapping-up">Wrapping up</a></li>
<li><a href="#references">References</a></li>
</ul>
</div>
<!--endtoc-->
<p>As I mentioned in the post description above, the solution to clean up
the auto-populated <code>${GOPATH}/pkg/</code> is to run <code>go clean -modcache</code>. While the solution is simple, it wasn&rsquo;t easy for me to
discover, and so I am writing this short piece to make it a bit more
discoverable for others like me.</p>

<h2 id="the-gopath-directory">The <code>$GOPATH</code> directory&nbsp;<a class="headline-hash no-text-decoration" href="#the-gopath-directory">#</a></h2>


<p>The <code>GOPATH</code> environment variable lists places to look for Go code.</p>
<p>If you haven&rsquo;t set this variable and if the <code>${HOME}/go/</code> directory
isn&rsquo;t used to contain the Go distribution, <code>$GOPATH</code> defaults to that
path.</p>
<p>When you run <code>go get</code> to install any Go package,</p>
<ul>
<li><code>${GOPATH}/pkg/</code> gets populated with all the Go module dependencies,</li>
<li>.. and all package&rsquo;s executables if any get installed to <code>${GOPATH}/bin/</code>.</li>
</ul>
<div class="note">
<p>I think that if the user has set the <code>$GOMODCACHE</code> environment
variable, that directory would get populated with Go module downloads
instead. But for my use, I am sticking with only the <code>$GOPATH</code> for
simplicity.</p>
</div>
<p>To confirm the value of <code>GOPATH</code> used by Go, see <code class="code-inline language-shell">go env <span class="p">|</span> rg GOPATH</code>.</p>

<h2 id="the-disk-space-issue">The disk space issue&nbsp;<a class="headline-hash no-text-decoration" href="#the-disk-space-issue">#</a></h2>


<p>I have been happily installing and building Go apps like Hugo using
<code>go get</code> or <code>go build</code>, and all these installations would end up in
the <code>$GOPATH</code>. But over time, I noticed that the disk space used by
<code>${GOPATH}/pkg/</code> just kept on creeping up.</p>
<p>Today I happened to notice that this directory was taking up roughly
<strong>4 GB</strong> of my disk space! I started analyzing why it was taking up so
much space using my favorite tool for this purpose &ndash; <a href="https://dev.yorhel.nl/ncdu">ncdu</a>.</p>
<p>Here&rsquo;s a snapshot showing disk usage by one of the sub-directories
under <code>${GOPATH}/pkg/</code>, which shows the problem &mdash; Over time, I had
accumulated multiple versions of multiple packages!</p>
<p><a id="figure--go-pkg-disk-usage"></a></p>



<figure>
    
        <img src="https://scripter.co/cleaning-up-gopath-pkg/go-pkg-disk-usage.png" alt="Figure 1: Snapshot of ncdu showing disk usage for a ${GOPATH}/pkg/ directory"/> <figcaption>
                <p>
                    <span class="figure-number">Figure 1: </span>Snapshot of <em>ncdu</em> showing disk usage for a <code>${GOPATH}/pkg/</code> directory
                    
                        
                        </p>
                
            </figcaption></figure>


<h2 id="write-protected-gopath-pkg">Write-protected <code>${GOPATH}/pkg/</code>&nbsp;<a class="headline-hash no-text-decoration" href="#write-protected-gopath-pkg">#</a></h2>


<p>I identified the problem. And I knew that I just needed to delete all
the old packages.</p>
<div class="verse">
<p>        But Go wouldn&rsquo;t allow deleting those <code>pkg/</code> directories!<br /></p>
</div>
<p>I had been searching a solution to this on and off, but didn&rsquo;t have
much success, mainly attributed to the short and generic name of the
&ldquo;Go&rdquo; language, and the fact that I didn&rsquo;t know what the
<code>${GOPATH}/pkg/</code> directory was called.</p>

<h2 id="cleaning-up-modcache">Cleaning up &ldquo;modcache&rdquo;&nbsp;<a class="headline-hash no-text-decoration" href="#cleaning-up-modcache">#</a></h2>


<p>Today, I finally had success when I searched for this magic phrase:
<em>golang &ldquo;cannot remove&rdquo; &ldquo;pkg/mod&rdquo;</em> .. and <a href="https://github.com/golang/go/issues/27161#issuecomment-415213240">Golang Issues # 27161</a> was
the first search result!</p>
<p>The solution was so simple, but so difficult to look for ..</p>
<p><a id="code-snippet--go-clean-modcache"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">go clean -modcache
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--go-clean-modcache">Code Snippet 1</a>:</span>
  Command to delete contents in <code>${GOPATH}/pkg/</code> or the Go <i>modcache</i>
</div>
<p>From that issue, I also learned that the <code>${GOPATH}/pkg/</code> directory is
the default &ldquo;modcache&rdquo; or the cache directory for holding all the
installed Go modules.</p>

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


<p>Knowing that the stuff I was trying to delete is called <em>modcache</em>,
this of course works ..</p>
<p><a id="code-snippet--go-help-clean"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">go <span class="nb">help</span> clean <span class="p">|</span> rg modcache -A <span class="m">2</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--go-help-clean">Code Snippet 2</a>:</span>
  Getting help with cleaning up the <i>modcache</i> from <code>go help</code>
</div>
<p>The issue referenced above gets resolved when a <a href="https://github.com/golang/go/issues/27161#issuecomment-625899357"><code>-modcacherw</code> switch
gets added</a> to the <code>go build</code> command. I see that switch when I run
<code>go help build</code>. <em>But that switch is not available for <code>go get</code>?
.. because I don&rsquo;t see it when I run <code>go help get</code>.</em></p>
<p>I don&rsquo;t understand why Go decided to make this so complicated by
taking away the <em>write</em> access from the user who installed the Go
package!</p>
<div class="verse">
<p>        At least <code>go clean -modcache</code> accomplishes what I want .. <em>sigh</em><br /></p>
</div>

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


<ul>
<li><a href="https://pkg.go.dev/cmd/go#hdr-GOPATH_environment_variable"><code>go</code> Documentation &ndash; <code>GOPATH</code> environment variable</a></li>
<li><a href="https://pkg.go.dev/cmd/go#hdr-Remove_object_files_and_cached_files"><code>go</code> Documentation &ndash; <code>go help clean</code></a></li>
<li><a href="https://github.com/golang/go/wiki/SettingGOPATH">Go Wiki &ndash; Setting <code>GOPATH</code></a></li>
<li><a href="https://github.com/golang/go/issues/27161">Golang Issue # 27161</a></li>
</ul>
]]></content><category scheme="https://scripter.co/categories/programming" term="programming" label="programming"/><category scheme="https://scripter.co/tags/golang" term="golang" label="golang"/><category scheme="https://scripter.co/tags/100daystooffload" term="100daystooffload" label="100DaysToOffload"/></entry><entry><title type="html">Downloading Nim</title><link href="https://scripter.co/downloading-nim/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/binding-nim-to-c-plus-plus-std-list/?utm_source=atom_feed" rel="related" type="text/html" title="Binding Nim to C++ std::list"/><link href="https://scripter.co/creating-a-patch-file-using-magit/?utm_source=atom_feed" rel="related" type="text/html" title="Creating a patch file using Magit"/><link href="https://scripter.co/presenting-tomelr/?utm_source=atom_feed" rel="related" type="text/html" title="Presenting tomelr!"/><link href="https://scripter.co/defining-tomelr/?utm_source=atom_feed" rel="related" type="text/html" title="Defining tomelr – A library for converting Lisp expressions to TOML"/><link href="https://scripter.co/parsing-backlinks-in-hugo/?utm_source=atom_feed" rel="related" type="text/html" title="Parsing Backlinks in Hugo"/><id>https://scripter.co/downloading-nim/</id><author><name>Kaushal Modi</name></author><published>2022-05-10T10:45:00-04:00</published><updated>2022-05-10T10:45:00-04:00</updated><content type="html"><![CDATA[<blockquote>Download and &ldquo;installing&rdquo; Nim using just <code>curl</code> and <code>tar</code>.</blockquote><p>Today I saw <a href="https://mastodon.art/@hyperlinkyourheart/108277257649997561">this toot by user <em>@hyperlinkyourheart</em></a> regarding
installing Nim:</p>
<blockquote>
<p>Not a great experience so far though - choosenim is broken on Ubuntu
22.04 based systems ..</p>
</blockquote>
<p>..  and that inspired this quick post. I would encourage the user
posting that to bring up that issue on the <a href="https://forum.nim-lang.org/">Nim Forum</a>, but here&rsquo;s a
quick stop-gap solution to install Nim using just <code>curl</code> and <code>tar</code>.</p>
<ol>
<li>Copy and save the below script somewhere, let&rsquo;s say as
<code>~/scripts/download_nim.sh</code>.
<mark>Update the <code>nim_install_dir</code> variable
in there to your choice.</mark> That is set to <code class="code-inline language-bash"><span class="si">${</span><span class="nv">HOME</span><span class="si">}</span>/nim</code> by default.
<a id="code-snippet--nim-download"></a>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1"># Running this script will download and extract nim installation to ~/nim/${nim_version}.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># To uninstall nim, just remove the ~/nim directory.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail <span class="c1"># http://redsymbol.net/articles/unofficial-bash-strict-mode</span>
</span></span><span class="line"><span class="cl"><span class="nv">IFS</span><span class="o">=</span><span class="s1">$&#39;\n\t&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">nim_version</span><span class="o">=</span><span class="s2">&#34;1.6.6&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">nim_archive_url</span><span class="o">=</span><span class="s2">&#34;https://nim-lang.org/download/nim-</span><span class="si">${</span><span class="nv">nim_version</span><span class="si">}</span><span class="s2">-linux_x64.tar.xz&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">nim_install_dir</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">HOME</span><span class="si">}</span><span class="s2">/nim&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">tmp_dir</span><span class="o">=</span><span class="s2">&#34;/tmp/</span><span class="si">${</span><span class="nv">USER</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">nim_download_dir</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">tmp_dir</span><span class="si">}</span><span class="s2">/nim-</span><span class="si">${</span><span class="nv">nim_version</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">nim_version_dir</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_install_dir</span><span class="si">}</span><span class="s2">/</span><span class="si">${</span><span class="nv">nim_version</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">mkdir -p <span class="s2">&#34;</span><span class="si">${</span><span class="nv">tmp_dir</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">tmp_dir</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">||</span> <span class="nb">exit</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Downloading nim archive from </span><span class="si">${</span><span class="nv">nim_archive_url</span><span class="si">}</span><span class="s2"> ..&#34;</span>
</span></span><span class="line"><span class="cl">curl -RLs <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_archive_url</span><span class="si">}</span><span class="s2">&#34;</span> -o <span class="s2">&#34;nim.tar.xz&#34;</span>
</span></span><span class="line"><span class="cl">tar xf nim.tar.xz <span class="c1"># Extracts to ${nim_download_dir}.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> -d <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_version_dir</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span>
</span></span><span class="line"><span class="cl"><span class="k">then</span>
</span></span><span class="line"><span class="cl">    rm -rf <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_version_dir</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_version_dir</span><span class="si">}</span><span class="s2">/doc&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_version_dir</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">||</span> <span class="nb">exit</span>
</span></span><span class="line"><span class="cl">cp -fP <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_download_dir</span><span class="si">}</span><span class="s2">&#34;</span>/doc/*.css ./doc/. <span class="c1"># Required for &#39;nim doc ..&#39; to work</span>
</span></span><span class="line"><span class="cl">cp -rfP <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_download_dir</span><span class="si">}</span><span class="s2">&#34;</span>/bin .
</span></span><span class="line"><span class="cl">cp -rfP <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_download_dir</span><span class="si">}</span><span class="s2">&#34;</span>/lib .
</span></span><span class="line"><span class="cl">cp -rfP <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_download_dir</span><span class="si">}</span><span class="s2">&#34;</span>/compiler . <span class="c1"># Required for &#39;nimterop&#39; package</span>
</span></span><span class="line"><span class="cl">cp -rfP <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_download_dir</span><span class="si">}</span><span class="s2">&#34;</span>/config .
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_install_dir</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">||</span> <span class="nb">exit</span>
</span></span><span class="line"><span class="cl">find . -name <span class="s2">&#34;bin&#34;</span> -type l -delete
</span></span><span class="line"><span class="cl">ln -fs <span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_version_dir</span><span class="si">}</span><span class="s2">&#34;</span>/bin ./bin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Finished downloading </span><span class="k">$(</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">nim_version_dir</span><span class="si">}</span><span class="s2">&#34;</span>/bin/nim -v <span class="p">|</span> head -n 1<span class="k">)</span><span class="s2">&#34;</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-download">Code Snippet 1</a>:</span>
  Nim download script
</div>
</li>
<li>Make the script an executable: <code class="code-inline language-shell">chmod +x ~/scripts/download_nim.sh</code></li>
<li>Run <code>~/scripts/download_nim.sh</code>.. This will download the <code>nim</code>
compiler and its standard libraries (totaling to only 40MB!) to the
path set in <code class="code-inline language-bash"><span class="si">${</span><span class="nv">nim_install_dir</span><span class="si">}</span></code>.</li>
<li>Make sure that the path in <code class="code-inline language-bash"><span class="si">${</span><span class="nv">nim_install_dir</span><span class="si">}</span></code> is added to your <strong>PATH</strong>.</li>
<li>Run <code>nim --version</code> to check the installation.
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Nim Compiler Version 1.6.6 [Linux: amd64]
</span></span><span class="line"><span class="cl">Compiled at 2022-05-05
</span></span><span class="line"><span class="cl">Copyright (c) 2006-2021 by Andreas Rumpf
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">git hash: 0565a70eab02122ce278b98181c7d1170870865c
</span></span><span class="line"><span class="cl">active boot switches: -d:release
</span></span></code></pre></div></li>
</ol>
<p>Now head over to <a href="https://nim-lang.org/learn.html">https://nim-lang.org/learn.html</a> to learn this
awesome ❤️ language!</p>
]]></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/installing" term="installing" label="installing"/><category scheme="https://scripter.co/tags/100daystooffload" term="100daystooffload" label="100DaysToOffload"/></entry><entry><title type="html">Binding Nim to C++ std::list</title><link href="https://scripter.co/binding-nim-to-c-plus-plus-std-list/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/quick-intro-to-emacs-lisp-regression-testing/?utm_source=atom_feed" rel="related" type="text/html" title="Quick Intro to Emacs Lisp Regression Testing"/><link href="https://scripter.co/titleref-referencing-hugo-posts-by-their-titles/?utm_source=atom_feed" rel="related" type="text/html" title="titleref: Referencing Hugo posts by their titles"/><link href="https://scripter.co/hugo-modules-getting-started/?utm_source=atom_feed" rel="related" type="text/html" title="Hugo Modules: Getting Started"/><link href="https://scripter.co/auto-count-100daystooffload-posts/?utm_source=atom_feed" rel="related" type="text/html" title="Auto-count #100DaysToOffload posts"/><link href="https://scripter.co/grep-po/?utm_source=atom_feed" rel="related" type="text/html" title="grep -Po"/><id>https://scripter.co/binding-nim-to-c-plus-plus-std-list/</id><author><name>Kaushal Modi</name></author><published>2022-03-14T01:49:00-04:00</published><updated>2022-03-14T01:49:00-04:00</updated><content type="html"><![CDATA[<blockquote>How to use the Nim <code>importcpp</code> pragma to bind to C++ Standard Template
Libraries like <code>std::list</code>.</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#nim-cpp-bindings-goal">Goal: Be able to easily access C++ <code>std::list</code> elements</a></li>
<li><a href="#importcpp-pragma"><code>importcpp</code> pragma</a></li>
<li><a href="#bindings-to-the-c-plus-plus-list-header">Bindings to the C++ <code>&lt;list&gt;</code> header</a></li>
<li><a href="#test-c-plus-plus-code">Test C++ code</a></li>
<li><a href="#test-nim-code">Test Nim code</a></li>
<li><a href="#extending-the-std-list-api-in-nim">Extending the <code>std::list</code> API in Nim</a></li>
<li><a href="#final-code">Final Code</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#references">References</a></li>
</ul>
</div>
<!--endtoc-->
<p>I like ❤️ using <a href="https://nim-lang.org/">Nim</a> as my go-to programming language &ndash; be it for
scripting, some CLI tool or any <a href="/tags/nim">other application</a>. The nice thing when
using Nim is that you don&rsquo;t have to throw away any of the past work
done in C or C++, because it is pretty easy to bind those C/C++
libraries and extend their functionality in Nim.</p>
<p>To demonstrate that extensibility, in this post, I will add some new
API in Nim that builds on top of the <code>std::list</code> <abbr aria-label="Standard Template Library" tabindex=0>STL</abbr>
<span class="sidenote-number"><small class="sidenote">
The C++ STL is a set of template classes to provide common programming
data structures and functions such as lists, stacks, arrays, etc.
</small></span>
library. I won&rsquo;t be re-writing any of the <code>std::list</code> methods in Nim
&mdash; No need to re-invent the <code>std::list</code> wheel in Nim! &mdash; I will
directly use the C++ <code>std::list</code> methods to build new API functions in
Nim. 🤯</p>

<h2 id="nim-cpp-bindings-goal">Goal: Be able to easily access C++ <code>std::list</code> elements&nbsp;<a class="headline-hash no-text-decoration" href="#nim-cpp-bindings-goal">#</a></h2>


<p>From the <a href="https://en.cppreference.com/w/cpp/container/list"><em>std::list</em> reference</a>, we can see that we cannot access a
<em>list</em> element by index using syntax like <code>list_obj[index]</code>. At the
end of this post, you will be able to convert C++ <em>list</em> objects to
Nim <em>sequences</em> and make the <em>list</em> data super-accessible &mdash; You can
print them using <code>echo</code>, use built-in libraries like <a href="https://nim-lang.github.io/Nim/sequtils"><code>sequtils</code></a>, and
more.</p>

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


<p>The first thing we&rsquo;ll need is to be able to call the C++ <em>list</em>
methods directly in Nim, and we will need the <code>importcpp</code> pragma
<span class="sidenote-number"><small class="sidenote">
This post will highlight some key features of this pragma. For full
details, check out this section in the Nim Manual <a href="#ref-importcpp">linked</a> in
References.
</small></span>
for that. This pragma is used to import a C++ <em>method</em> or <em>type</em> into
the Nim space.</p>
<p>This pragma is typically used like this:</p>
<p><a id="code-snippet--nim-bindings-importcpp"></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="p">{.</span><span class="n">link</span><span class="p">:</span> <span class="s">&#34;/path/to/libCppCode.so&#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">type</span>
</span></span><span class="line"><span class="cl">  <span class="n">MyNimType</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;MyCppType&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;libCppCode.hpp&#34;</span><span class="p">.}</span> <span class="o">=</span> <span class="k">object</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">myNimProc</span><span class="p">():</span> <span class="n">MyNimType</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;myCppMethod&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;libCppCode.hpp&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span>
</span></span><span class="line"><span class="cl">  <span class="n">foo</span> <span class="o">=</span> <span class="n">MyNimProc</span><span class="p">()</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-importcpp">Code Snippet 1</a>:</span>
  General use of <code>importcpp</code> pragma
</div>
<ul>
<li><code>MyCppType</code> type from the C++ library is mapped to <code>MyNimType</code>
<span class="sidenote-number"><small class="sidenote">
You would typically name the type and method identifiers same same
when binding external libraries to Nim, just to prevent any
confusion. You can name them differently if you want to though.
</small></span>
in the Nim code.</li>
<li><code>myCppMethod</code> from C++ is mapped to <code>myNimProc</code>.</li>
<li>Then the code can call that <code>myNimProc</code> in the Nim code along with
other Nim stuff.</li>
<li>The <a href="https://nim-lang.github.io/Nim/manual.html#noalias-pragma-link-pragma"><code>link</code> pragma</a> is needed if we need to tell the Nim compiler
where to find the implementation
<span class="sidenote-number"><small class="sidenote">
For the case of linking to the C++ STL <code>&lt;list&gt;</code> header, we do not
need to provide the <code>std::list</code> implementation because the GNU GCC
compiler provides that.
</small></span>
of linked methods.</li>
</ul>

<h2 id="bindings-to-the-c-plus-plus-list-header">Bindings to the C++ <code>&lt;list&gt;</code> header&nbsp;<a class="headline-hash no-text-decoration" href="#bindings-to-the-c-plus-plus-list-header">#</a></h2>


<p>Below code snippet shows us all the <code>&lt;list&gt;</code> header bindings we will
need to meet the <a href="#nim-cpp-bindings-goal">goal</a> of this post.</p>
<p><a id="code-snippet--nim-std-list-bindings"></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--045394-1"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-1">1</a>
</span><span class="lnt" id="org-coderef--045394-2"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-2">2</a>
</span><span class="lnt" id="org-coderef--045394-3"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-3">3</a>
</span><span class="lnt" id="org-coderef--045394-4"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-4">4</a>
</span><span class="lnt" id="org-coderef--045394-5"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-5">5</a>
</span><span class="lnt" id="org-coderef--045394-6"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-6">6</a>
</span><span class="lnt" id="org-coderef--045394-7"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-7">7</a>
</span><span class="lnt" id="org-coderef--045394-8"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--045394-8">8</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">type</span>
</span></span><span class="line"><span class="cl">  <span class="n">List</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span>                              <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;std::list&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span> <span class="o">=</span> <span class="k">object</span>
</span></span><span class="line"><span class="cl">  <span class="n">ListIter</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span>                          <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;std::list&lt;&#39;0&gt;::iterator&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span> <span class="o">=</span> <span class="k">object</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">initList</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">():</span> <span class="n">List</span><span class="o">[</span><span class="n">T</span><span class="o">]</span>            <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;std::list&lt;&#39;*0&gt;()&#34;</span><span class="p">,</span> <span class="n">constructor</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">size</span><span class="o">*</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="n">List</span><span class="p">):</span> <span class="n">csize_t</span>            <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;size&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">begin</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="n">List</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">):</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;begin&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><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">it</span><span class="p">:</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">):</span> <span class="n">T</span>       <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;*#&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-std-list-bindings">Code Snippet 2</a>:</span>
  Nim bindings for basic <code>std::list</code> object types and methods
</div>
<ul>
<li><a href="#org-coderef--045394-2">Line 2</a> binds the C++ <code>std::list</code> type with the Nim
<code>List</code> type. So, a <code class="code-inline language-nim"><span class="n">List</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span></code> type in Nim
get mapped to <code class="code-inline language-cpp"><span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span></code> in C++.</li>
<li><a href="#org-coderef--045394-3">Line 3</a> binds the C++ <code>iterator</code> type from
<code>std::list</code> with the Nim type <code>ListIter</code>.
<ul>
<li>Note special pattern <code>&lt;'0&gt;</code>
<span class="sidenote-number"><small class="sidenote">
See <a href="https://nim-lang.github.io/Nim/manual.html#importcpp-pragma-importcpp-for-procs">📖 <code>importcpp</code> for procs</a> for details on such special
patterns.
</small></span>
in the <code>importcpp</code> argument for this binding. The apostrophe
followed by an integer <em>i</em> is replaced by the <em>i&rsquo;th</em> parameter in
the <code>ListIter[T]</code> type i.e. the <code>T</code> type. So, <code class="code-inline language-nim"><span class="n">ListIter</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span></code> in Nim gets mapped to <code class="code-inline language-cpp"><span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;::</span><span class="n">iterator</span></code> in C++.</li>
</ul>
</li>
<li><a href="#org-coderef--045394-5">Line 5</a> binds the <em>list</em> constructor <code>()</code> with
the Nim proc <code>initList[T]()</code>. As the constructor returns a <em>list</em>
type, the return type on the Nim side set to the equivalent
<code>List[T]</code>.
<ul>
<li>Note the slightly different pattern in the <code>importcpp</code> argument
for this binding: <code>&lt;'*​0&gt;</code>. If we had <strong>not</strong> used that <em>asterisk</em>
there, that would have mapped to the proc&rsquo;s return type,
<code>List[T]</code>. But we want the C++ mapped constructor to look like
<code class="code-inline language-cpp"><span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">()</span></code> i.e. we need <code>T</code> and not
<code>List[T]</code> in the C++ template type. The <code>*</code> does the job of
deriving <code>T</code> from its &ldquo;container&rdquo; type <code>List[T]</code>.</li>
</ul>
</li>
<li>In lines <a href="#org-coderef--045394-6">6</a> and <a href="#org-coderef--045394-7">7</a>, <code>size</code> and
<code>begin</code> on C++ get mapped to same named procs on the Nim side, with
the correct return types.
<ul>
<li><a href="https://nim-lang.github.io/Nim/system.html#csize_t"><code>csize_t</code></a> is a Nim type that maps to the C <code>size_t</code> type.</li>
<li>As <a href="https://en.cppreference.com/w/cpp/container/list/begin"><code>begin</code></a> returns an <em>iterator</em> handle, the return type of
<code>begin</code> is <code>ListIter[T]</code>.</li>
<li>Note that I did not use the <code>std::list</code> prefix for these mappings,
because these procs will always be called in context of their
arguments. For example, <code class="code-inline language-nim"><span class="n">listIterVar</span><span class="p">.</span><span class="n">size</span><span class="p">()</span></code>
in Nim will map to <code class="code-inline language-cpp"><span class="n">listIterVar</span><span class="p">.</span><span class="n">size</span><span class="p">()</span></code> in
C++..</li>
</ul>
</li>
<li><a href="#org-coderef--045394-8">Line 8</a> maps the C/C++ <em>indirection operator <code>*</code></em>
with Nim <em>dereferencing operator <code>[]</code></em>. The input argument type is
an <em>iterator</em>. So if <code>iter</code> is a variable of type <code>ListIter[cint]</code>,
<code class="code-inline language-nim"><span class="n">iter</span><span class="o">[]</span></code> will return the value of type <code>cint</code>
pointed to by that iterator.
<ul>
<li>The <code>importcpp</code> argument for this mapping has a different pattern:
<code>*#</code>. The <code>#</code> is replaced by the first argument of the proc:
<code>iter</code>. So <code class="code-inline language-nim"><span class="n">iter</span><span class="o">[]</span></code> in Nim code
<span class="sidenote-number"><small class="sidenote">
<code>iter[]</code> is same as writing <code>`[]`(iter)</code>, but one might agree that the
former style is better and more readable.
</small></span>
will translate to <code class="code-inline language-cpp"><span class="o">*</span><span class="err">​</span><span class="n">iter</span></code><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> on the C++
side.</li>
</ul>
</li>
</ul>

<h2 id="test-c-plus-plus-code">Test C++ code&nbsp;<a class="headline-hash no-text-decoration" href="#test-c-plus-plus-code">#</a></h2>


<p>We have the <code>&lt;list&gt;</code> bindings ready, but now we need some test C++
code which will be our &ldquo;library&rdquo; for use in the Nim code.</p>
<p>So here it is:</p>
<p><a id="code-snippet--nim-bindings-cpp-test-code"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">generateList</span><span class="p">(</span><span class="kt">int</span> <span class="n">num</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="o">*</span><span class="n">retList</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">num</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">retList</span><span class="o">-&gt;</span><span class="n">push_back</span><span class="p">(</span><span class="n">i</span> <span class="o">*</span> <span class="mi">2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-cpp-test-code">Code Snippet 3</a>:</span>
  Dummy C++ "library" that we will extend in Nim
</div>
<p>The C++ &ldquo;library&rdquo; here has a <code>generateList</code> API with expects an
integer <code>num</code> as the first arg, and it save a <code>num</code> element
<code>std::list&lt;int&gt;</code> object to the pointer passed as its second arg.</p>
<p>Now, we can either go the conventional route of compiling this code to
a shared object (<code>.so</code> or <code>.dll</code>) and then linking it to the Nim code
using the <a href="https://nim-lang.github.io/Nim/manual.html#noalias-pragma-link-pragma"><code>link</code> pragma</a>.</p>
<div class="verse">
<p>    But.. that is boring 💤<br /></p>
</div>
<p>We will do something cooler.. we will inline that C++ code in Nim
using the <a href="https://nim-lang.github.io/Nim/manual.html#noalias-pragma-emit-pragma"><code>emit</code> pragma</a> and bind to it using <code>importcpp</code> just as we
did for the <code>&lt;list&gt;</code> methods! 😎</p>
<p><a id="code-snippet--nim-bindings-emit"></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="p">{.</span><span class="n">emit</span><span class="p">:</span> <span class="s">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s">void generateList(int num, std::list&lt;int&gt; *retList)
</span></span></span><span class="line"><span class="cl"><span class="s">{
</span></span></span><span class="line"><span class="cl"><span class="s">    for (int i = 0; i &lt; num; ++i) {
</span></span></span><span class="line"><span class="cl"><span class="s">        retList-&gt;push_back(i * 2);
</span></span></span><span class="line"><span class="cl"><span class="s">    }
</span></span></span><span class="line"><span class="cl"><span class="s">}
</span></span></span><span class="line"><span class="cl"><span class="s">&#34;&#34;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">generateList</span><span class="p">(</span><span class="n">num</span><span class="p">:</span> <span class="n">cint</span><span class="p">;</span> <span class="n">lPtr</span><span class="p">:</span> <span class="k">ptr</span> <span class="n">List</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span><span class="p">)</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;generateList(@)&#34;</span><span class="p">.}</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-emit">Code Snippet 4</a>:</span>
  Inlining C++ code in Nim using the <code>emit</code> pragma and then binding to it using <code>importcpp</code>
</div>
<p>Here, I also introduce you readers to a new <code>importcpp</code> pattern:
<code>@</code>. The <code>@</code> expands to comma-separated arguments passed on the Nim
side.</p>
<p>Note the equivalence between the C++ function signature
<code class="code-inline language-cpp"><span class="kt">void</span> <span class="n">generateList</span><span class="p">(</span><span class="kt">int</span> <span class="n">num</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="o">*</span><span class="err">​</span><span class="n">retList</span><span class="p">)</span></code> and Nim proc signature <code class="code-inline language-nim"><span class="k">proc </span><span class="nf">generateList</span><span class="p">(</span><span class="n">num</span><span class="p">:</span> <span class="n">cint</span><span class="p">;</span> <span class="n">lPtr</span><span class="p">:</span> <span class="k">ptr</span> <span class="n">List</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span><span class="p">)</span></code>.</p>

<h2 id="test-nim-code">Test Nim code&nbsp;<a class="headline-hash no-text-decoration" href="#test-nim-code">#</a></h2>


<p>Below Nim code will call the test C++ <code>generateList</code> method defined
above and then print the whole <em>list</em> object after converting it to a
Nim sequence.</p>
<p><a id="code-snippet--nim-bindings-test-nim-code"></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="kd">var</span>
</span></span><span class="line"><span class="cl">  <span class="n">l</span> <span class="o">=</span> <span class="n">initList</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">generateList</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="k">addr</span> <span class="n">l</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span>
</span></span><span class="line"><span class="cl">  <span class="n">s</span> <span class="o">=</span> <span class="n">l</span><span class="p">.</span><span class="n">toSeq</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">echo</span> <span class="s">&#34;sequence   = &#34;</span><span class="p">,</span> <span class="n">s</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-test-nim-code">Code Snippet 5</a>:</span>
  Test Nim code that will call the <code>generateList</code> method implemented in C++
</div>
<ul>
<li>In above snippet, <a href="#org-coderef--045394-5"><code>initList</code></a> bindings defined in
<a href="#code-snippet--nim-std-list-bindings">Code Snippet 2</a> is used to initialize the <em>list</em> object
<code>l</code>.</li>
<li>Its address or pointer is passed to <code>generateList</code> which will
populate the Nim allocated memory with 10 elements.</li>
<li>Then we call a <code>toSeq</code> proc (that we will define in the next
section) to convert that <em>list</em> to a Nim sequence.</li>
<li>Now that the <em>list</em> object is converted to a Nim sequence, printing
it out as easy as you see above 😄.</li>
</ul>

<h2 id="extending-the-std-list-api-in-nim">Extending the <code>std::list</code> API in Nim&nbsp;<a class="headline-hash no-text-decoration" href="#extending-the-std-list-api-in-nim">#</a></h2>


<p>The <a href="#nim-cpp-bindings-goal">end goal</a> is to be able to write a <code>toSeq</code> proc that can convert a
<code>std::list</code> object to a Nim sequence. Here&rsquo;s a psuedo-code I began
before it evolved into <a href="#code-snippet--nim-bindings-toSeq">Code Snippet 7</a>.</p>
<p><a id="code-snippet--nim-bindings-toSeq-pseudo"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">proc toSeq (l: list_obj): sequence
</span></span><span class="line"><span class="cl">  lBegin = handle to the iterator for the beginning of list_obj; use `begin`
</span></span><span class="line"><span class="cl">  lSize = number of elements in list_obj; use `size`
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  lIter = lBegin
</span></span><span class="line"><span class="cl">  for idx in 0 ..&lt; lSize:
</span></span><span class="line"><span class="cl">    sequence[idx] = *lIter; use the `[]` dereferencing operator
</span></span><span class="line"><span class="cl">    lIter = pointer to the next element; use `next` from &lt;iterator&gt;
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-toSeq-pseudo">Code Snippet 6</a>:</span>
  Pseudocode on how I plan to implement <code>toSeq</code>
</div>
<p>As it turned out, the real Nim code wasn&rsquo;t longer or more complicated
than the pseudocode 😆.</p>
<p><a id="code-snippet--nim-bindings-toSeq"></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--7ad52f-1"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-1">1</a>
</span><span class="lnt" id="org-coderef--7ad52f-2"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-2">2</a>
</span><span class="lnt" id="org-coderef--7ad52f-3"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-3">3</a>
</span><span class="lnt" id="org-coderef--7ad52f-4"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-4">4</a>
</span><span class="lnt" id="org-coderef--7ad52f-5"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-5">5</a>
</span><span class="lnt" id="org-coderef--7ad52f-6"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-6">6</a>
</span><span class="lnt" id="org-coderef--7ad52f-7"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-7">7</a>
</span><span class="lnt" id="org-coderef--7ad52f-8"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-8">8</a>
</span><span class="lnt" id="org-coderef--7ad52f-9"><a style="outline: none; text-decoration:none; color:inherit" href="#org-coderef--7ad52f-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">next</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">it</span><span class="p">:</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">;</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1</span><span class="p">):</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;next(@)&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;iterator&gt;&#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">toSeq</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="n">List</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">):</span> <span class="kt">seq</span><span class="o">[</span><span class="n">T</span><span class="o">]</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="n">result</span> <span class="o">=</span> <span class="n">newSeq</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">l</span><span class="p">.</span><span class="n">size</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span>
</span></span><span class="line"><span class="cl">    <span class="n">it</span> <span class="o">=</span> <span class="n">l</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="mi">0</span> <span class="p">..</span><span class="o">&lt;</span> <span class="n">l</span><span class="p">.</span><span class="n">size</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">result</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">it</span><span class="o">[]</span>
</span></span><span class="line"><span class="cl">    <span class="n">it</span> <span class="o">=</span> <span class="n">it</span><span class="p">.</span><span class="n">next</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-toSeq">Code Snippet 7</a>:</span>
  Adding new API <code>toSeq</code> for <code>std::list</code> objects
</div>
<ul>
<li><a href="#org-coderef--7ad52f-1">Line 1</a> - We needed a binding to the <a href="https://en.cppreference.com/w/cpp/iterator/next"><code>std::next</code></a>
method from iterator so that we can increment the iterator starting
from the <code>begin()</code> returned value.</li>
<li><a href="#org-coderef--7ad52f-4">Line 4</a> - We already know the size of the <em>list</em>
object, so we pre-allocated the Nim sequence to the same size by
using the <a href="https://nim-lang.github.io/Nim/system.html#newSeq"><code>newSeq</code></a> proc.</li>
<li>Then rest of the code follows the idea presented in the pseudocode
above.</li>
</ul>

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


<p>The final code to (i) wrap the <code>&lt;list&gt;</code> types and methods and (ii) one
method from <code>&lt;iterator&gt;</code>, and (iii) define a proc for converting
<code>std::list</code> objects to Nim sequences was only 22 lines! (including
comments and blank lines)</p>
<details>
<summary>Click here to see the full code + output</summary>
<div class="details">
<p><a id="code-snippet--nim-bindings-full-code"></a></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</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">when</span> <span class="ow">not</span> <span class="n">defined</span><span class="p">(</span><span class="n">cpp</span><span class="p">):</span> <span class="p">{.</span><span class="n">error</span><span class="p">:</span> <span class="s">&#34;This file needs to be compiled with cpp backend: Run &#39;nim -b:cpp r &lt;file&gt;&#39;.&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">## &lt;list&gt; bindings -- https://en.cppreference.com/w/cpp/container/list</span>
</span></span><span class="line"><span class="cl"><span class="k">type</span>
</span></span><span class="line"><span class="cl">  <span class="n">List</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span>                              <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;std::list&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span> <span class="o">=</span> <span class="k">object</span>
</span></span><span class="line"><span class="cl">  <span class="n">ListIter</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span>                          <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;std::list&lt;&#39;0&gt;::iterator&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span> <span class="o">=</span> <span class="k">object</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">initList</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">():</span> <span class="n">List</span><span class="o">[</span><span class="n">T</span><span class="o">]</span>            <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;std::list&lt;&#39;*0&gt;()&#34;</span><span class="p">,</span> <span class="n">constructor</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">size</span><span class="o">*</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="n">List</span><span class="p">):</span> <span class="n">csize_t</span>            <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;size&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">begin</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="n">List</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">):</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;begin&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><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">it</span><span class="p">:</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">):</span> <span class="n">T</span>       <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;*#&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;list&gt;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">## std::list processing procs and iterators</span>
</span></span><span class="line"><span class="cl"><span class="k">proc </span><span class="nf">next</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">it</span><span class="p">:</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">;</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">1</span><span class="p">):</span> <span class="n">ListIter</span><span class="o">[</span><span class="n">T</span><span class="o">]</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;next(@)&#34;</span><span class="p">,</span> <span class="n">header</span><span class="p">:</span> <span class="s">&#34;&lt;iterator&gt;&#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">toSeq</span><span class="o">*[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">l</span><span class="p">:</span> <span class="n">List</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">):</span> <span class="kt">seq</span><span class="o">[</span><span class="n">T</span><span class="o">]</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">  <span class="n">result</span> <span class="o">=</span> <span class="n">newSeq</span><span class="o">[</span><span class="n">T</span><span class="o">]</span><span class="p">(</span><span class="n">l</span><span class="p">.</span><span class="n">size</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span>
</span></span><span class="line"><span class="cl">    <span class="n">it</span> <span class="o">=</span> <span class="n">l</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="mi">0</span> <span class="p">..</span><span class="o">&lt;</span> <span class="n">l</span><span class="p">.</span><span class="n">size</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">result</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">it</span><span class="o">[]</span>
</span></span><span class="line"><span class="cl">    <span class="n">it</span> <span class="o">=</span> <span class="n">it</span><span class="p">.</span><span class="n">next</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">## Test</span>
</span></span><span class="line"><span class="cl"><span class="k">when</span> <span class="n">isMainModule</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="p">{.</span><span class="n">emit</span><span class="p">:</span> <span class="s">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s">  void generateList(int num, std::list&lt;int&gt; *retList)
</span></span></span><span class="line"><span class="cl"><span class="s">  {
</span></span></span><span class="line"><span class="cl"><span class="s">      for (int i = 0; i &lt; num; ++i) {
</span></span></span><span class="line"><span class="cl"><span class="s">          retList-&gt;push_back(i * 2);
</span></span></span><span class="line"><span class="cl"><span class="s">      }
</span></span></span><span class="line"><span class="cl"><span class="s">  }
</span></span></span><span class="line"><span class="cl"><span class="s">  &#34;&#34;&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl">  <span class="k">proc </span><span class="nf">generateList</span><span class="p">(</span><span class="n">num</span><span class="p">:</span> <span class="n">cint</span><span class="p">;</span> <span class="n">lPtr</span><span class="p">:</span> <span class="k">ptr</span> <span class="n">List</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span><span class="p">)</span> <span class="p">{.</span><span class="n">importcpp</span><span class="p">:</span> <span class="s">&#34;generateList(@)&#34;</span><span class="p">.}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">var</span>
</span></span><span class="line"><span class="cl">    <span class="n">l</span> <span class="o">=</span> <span class="n">initList</span><span class="o">[</span><span class="n">cint</span><span class="o">]</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="n">generateList</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="k">addr</span> <span class="n">l</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span>
</span></span><span class="line"><span class="cl">    <span class="n">s</span> <span class="o">=</span> <span class="n">l</span><span class="p">.</span><span class="n">toSeq</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;sequence   = &#34;</span><span class="p">,</span> <span class="n">s</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;first elem = &#34;</span><span class="p">,</span> <span class="n">s</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;elem 5     = &#34;</span><span class="p">,</span> <span class="n">s</span><span class="o">[</span><span class="mi">5</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;last elem  = &#34;</span><span class="p">,</span> <span class="n">s</span><span class="o">[</span><span class="p">^</span><span class="mi">1</span><span class="o">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--nim-bindings-full-code">Code Snippet 8</a>:</span>
  Full Nim solution for converting <code>std::list</code> to a Nim sequence, with test C++ code
</div>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sequence   = @[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
</span></span><span class="line"><span class="cl">first elem = 0
</span></span><span class="line"><span class="cl">elem 5     = 10
</span></span><span class="line"><span class="cl">last elem  = 18
</span></span></code></pre></div></div>
</details>
<p>You can try this code by saving to a <code>list_to_seq.nim</code> file and
running <code>nim -b:cpp r list_to_seq.nim</code>.</p>
<p>Alternatively, you can paste this code on <a href="https://play.nim-lang.org/">https://play.nim-lang.org/</a>,
set the &lsquo;Compilation target&rsquo; to <strong>C++</strong> and hit the yellow &lsquo;Run!&rsquo;
button.</p>

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


<p>It becomes fairly easy to map any C++ (or C) library to Nim. Once that
it done, you can leverage the power of Nim to extend that mapped
library or manipulate data generated by that library. And you do not
need to be a C++ programmer to do so (I am not).</p>
<p>The folks on <a href="https://forum.nim-lang.org/">Nim Forum</a>, <a href="https://discord.gg/nim">Discord</a> and elsewhere have been very generous
with their help and support, and that&rsquo;s one of the main reasons it&rsquo;s a
joy to use Nim. 🙏</p>

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


<ul>
<li><span class="org-target" id="ref-importcpp"></span>📖 <a href="https://nim-lang.github.io/Nim/manual.html#noalias-pragma-importcpp-pragma">Nim Manual &ndash; <code>importcpp</code> pragma</a></li>
<li><a href="https://en.cppreference.com/w/cpp/container/list">C++ <code>std::list</code> reference</a></li>
<li>Nim <a href="https://github.com/Clonkk/nim-cppstl"><code>cppstl</code></a>
<span class="sidenote-number"><small class="sidenote">
This package contains bindings to <code>std::string</code>, <code>std::vector</code> and
<code>std::complex</code> as of <span class="timestamp-wrapper"><span class="timestamp">&lt;2022-03-10 Thu&gt;</span></span>.
</small></span>
package &ndash; can be installed using <code>nimble install cppstl</code></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I have almost no experience with coding in C++; I got help with
this <code>importcpp: *#</code> binding from user <em>sls1005</em> on <a href="https://forum.nim-lang.org/t/8994">this Nim Forums
thread</a>. Thank you!&#160;<a href="#fnref:1" 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/binding" term="binding" label="binding"/><category scheme="https://scripter.co/tags/cpp" term="cpp" label="cpp"/><category scheme="https://scripter.co/tags/stl" term="stl" label="stl"/><category scheme="https://scripter.co/tags/list" term="list" label="list"/><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><entry><title type="html">Nim: Fizz-Buzz test</title><link href="https://scripter.co/nim-fizz-buzz-test/?utm_source=atom_feed" rel="alternate" type="text/html"/><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"/><link href="https://scripter.co/notes/string-fns-nim-vs-python/?utm_source=atom_feed" rel="related" type="text/html" title="String Functions: Nim vs Python"/><id>https://scripter.co/nim-fizz-buzz-test/</id><author><name>Kaushal Modi</name></author><published>2018-06-05T11:13:00-04:00</published><updated>2018-06-05T11:13:00-04:00</updated><content type="html"><![CDATA[<blockquote>My attempt at <em>FizzBuzz</em> in Nim.</blockquote><div class="mf2 reply">In reply to: <p><a class="u-in-reply-to h-cite" rel="in-reply-to" href="https://masahiko-ofgp-notebook.blogspot.com/2018/06/fizzbuzz-by-nim-lang.html">https://masahiko-ofgp-notebook.blogspot.com/2018/06/fizzbuzz-by-nim-lang.html</a></p></div>
<p>Today I came across this <a href="https://masahiko-ofgp-notebook.blogspot.com/2018/06/fizzbuzz-by-nim-lang.html">FizzBuzz attempt for Nim</a>, so I thought of
giving it a try too.</p>
<p>Here&rsquo;s how <em>Fizz buzz</em> is <a href="https://en.wikipedia.org/wiki/Fizz_buzz">defined on Wikipedia</a>:</p>
<blockquote>
<p>Fizz buzz is a group word game for children to teach them about
division. Players take turns to count incrementally, replacing any
number divisible by three with the word &ldquo;fizz&rdquo;, and any number
divisible by five with the word &ldquo;buzz&rdquo;.</p>
</blockquote>
<p>And it&rsquo;s also one of those basic programming problems (labeled as
<em>interview questions</em>) that&rsquo;s written in <a href="https://rosettacode.org/wiki/FizzBuzz">many languages</a>. Here&rsquo;s how
Rosetta Code defines this programming task &mdash;</p>
<blockquote>
<p>Write a program that prints the integers from 1 to 100 (inclusive).</p>
<p>But:</p>
<ul>
<li>for multiples of three, print Fizz (instead of the number)</li>
<li>for multiples of five, print Buzz (instead of the number)</li>
<li>for multiples of both three and five, print FizzBuzz (instead of the
number)</li>
</ul>
</blockquote>
<p>I am not doing anything radical in this post.. just recording my
attempt at FizzBuzz using Nim 😄.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-nim" data-lang="nim"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="mi">1</span> <span class="p">..</span> <span class="mi">100</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="n">str</span> <span class="o">=</span> <span class="o">$</span><span class="n">i</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="ow">mod</span> <span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;Fizz&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="ow">mod</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">str</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">&#34;Buzz&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">elif</span> <span class="p">(</span><span class="n">i</span> <span class="ow">mod</span> <span class="mi">5</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">str</span> <span class="o">=</span> <span class="s">&#34;Buzz&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="n">str</span>
</span></span></code></pre></div><details>
<summary>See the output</summary>
<div class="details">
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">1
</span></span><span class="line"><span class="cl">2
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">4
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">7
</span></span><span class="line"><span class="cl">8
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">11
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">13
</span></span><span class="line"><span class="cl">14
</span></span><span class="line"><span class="cl">FizzBuzz
</span></span><span class="line"><span class="cl">16
</span></span><span class="line"><span class="cl">17
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">19
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">22
</span></span><span class="line"><span class="cl">23
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">26
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">28
</span></span><span class="line"><span class="cl">29
</span></span><span class="line"><span class="cl">FizzBuzz
</span></span><span class="line"><span class="cl">31
</span></span><span class="line"><span class="cl">32
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">34
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">37
</span></span><span class="line"><span class="cl">38
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">41
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">43
</span></span><span class="line"><span class="cl">44
</span></span><span class="line"><span class="cl">FizzBuzz
</span></span><span class="line"><span class="cl">46
</span></span><span class="line"><span class="cl">47
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">49
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">52
</span></span><span class="line"><span class="cl">53
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">56
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">58
</span></span><span class="line"><span class="cl">59
</span></span><span class="line"><span class="cl">FizzBuzz
</span></span><span class="line"><span class="cl">61
</span></span><span class="line"><span class="cl">62
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">64
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">67
</span></span><span class="line"><span class="cl">68
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">71
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">73
</span></span><span class="line"><span class="cl">74
</span></span><span class="line"><span class="cl">FizzBuzz
</span></span><span class="line"><span class="cl">76
</span></span><span class="line"><span class="cl">77
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">79
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">82
</span></span><span class="line"><span class="cl">83
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">86
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">88
</span></span><span class="line"><span class="cl">89
</span></span><span class="line"><span class="cl">FizzBuzz
</span></span><span class="line"><span class="cl">91
</span></span><span class="line"><span class="cl">92
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">94
</span></span><span class="line"><span class="cl">Buzz
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">97
</span></span><span class="line"><span class="cl">98
</span></span><span class="line"><span class="cl">Fizz
</span></span><span class="line"><span class="cl">Buzz
</span></span></code></pre></div></div>
</details>
]]></content><category scheme="https://scripter.co/categories/programming" term="programming" label="programming"/><category scheme="https://scripter.co/categories/replies" term="replies" label="replies"/><category scheme="https://scripter.co/tags/nim" term="nim" label="nim"/><category scheme="https://scripter.co/tags/fizz-buzz" term="fizz-buzz" label="fizz-buzz"/><category scheme="https://scripter.co/tags/test" term="test" label="test"/></entry><entry><title type="html">Nim: Check if stdin/stdout are associated with terminal or pipe</title><link href="https://scripter.co/nim-check-if-stdin-stdout-are-associated-with-terminal-or-pipe/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/accessing-devdocs-from-emacs/?utm_source=atom_feed" rel="related" type="text/html" title="Accessing Devdocs from Emacs"/><link href="https://scripter.co/notes/string-fns-nim-vs-python/?utm_source=atom_feed" rel="related" type="text/html" title="String Functions: Nim vs Python"/><link href="https://scripter.co/installing-bleeding-edge-hugo-goorgeous/?utm_source=atom_feed" rel="related" type="text/html" title="Installing bleeding edge Hugo + Goorgeous"/><link href="https://scripter.co/count-down-timer-in-shell/?utm_source=atom_feed" rel="related" type="text/html" title="Count Down Timer in Shell"/><link href="https://scripter.co/check-if-a-command-exists-from-shell-script/?utm_source=atom_feed" rel="related" type="text/html" title="Check If a Command/Executable Exists from Shell Script"/><id>https://scripter.co/nim-check-if-stdin-stdout-are-associated-with-terminal-or-pipe/</id><author><name>Kaushal Modi</name></author><published>2018-05-15T13:12:00-04:00</published><updated>2018-05-15T13:12:00-04:00</updated><content type="html"><![CDATA[<blockquote><p>When writing bash scripts, I often need to know if the script is
receiving input from the terminal, or some piped process. I would also
need to know if the script is sending output to the terminal, or
to another piped process.</p>
<p>As I am learning Nim and trying to write new scripts using that, I
need to know how to do the same in Nim.</p>
</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#bash">Bash</a></li>
<li><a href="#nim">Nim</a>
<ul>
<li><a href="#using-os-dot-getfileinfo">Using <code>os.getFileInfo</code></a></li>
<li><a href="#stdin-stdout-isatty">Using <code>terminal.isatty</code></a></li>
</ul>
</li>
<li><a href="#result">Result</a></li>
</ul>
</div>
<!--endtoc-->
<p>Today, I came across this <strong>r/nim</strong> <a href="https://www.reddit.com/r/nim/comments/8jki3k/checking_stdin_for_content/">thread</a> where a user needed to know
if the Nim-compiled binary was receiving input from <em>stdin</em>.</p>
<p>That reminded me of <a href="https://github.com/kaushalmodi/eless/blob/0065c3b9629bcc74b5d1f818336d9dcf1ccd2b05/eless#L166-L196">this technique</a> that I had used in my bash project
<a href="https://eless.scripter.co/"><strong>eless</strong></a>..  (by checking <code>[[ -t 0 ]]</code> and <code>[[ -t 1 ]]</code>).</p>

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


<p>Here&rsquo;s a similar bash snippet if you want to try it out:</p>
<p><a id="code-snippet--stdin-stdout-bash"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1"># How to detect whether input is from keyboard, a file, or another process.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Useful for writing a script that can read from standard input, or prompt the</span>
</span></span><span class="line"><span class="cl"><span class="c1"># user for input if there is none.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># https://gist.github.com/davejamesmiller/1966557</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> -t <span class="m">0</span> <span class="o">]]</span> <span class="c1"># Script is called normally - Terminal input (keyboard) - interactive</span>
</span></span><span class="line"><span class="cl"><span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># eless foo</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># eless foo | cat -</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;--&gt; Input from terminal&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="c1"># Script is getting input from pipe or file - non-interactive</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># echo bar | eless foo</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># echo bar | eless foo | cat -</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;--&gt; Input from PIPE/FILE&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># https://stackoverflow.com/a/911213/1219634</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> -t <span class="m">1</span> <span class="o">]]</span> <span class="c1"># Output is going to the terminal</span>
</span></span><span class="line"><span class="cl"><span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># eless foo</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># echo bar | eless foo</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;    Output to terminal --&gt;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="c1"># Output is going to a pipe, file?</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># eless foo | cat -</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># echo bar | eless foo | cat -</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;    Output to a PIPE --&gt;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--stdin-stdout-bash">Code Snippet 1</a>:</span>
  Checking <b>stdin</b> and <b>stdout</b> in bash
</div>
<p>So using that as the basis, I went down the path of figuring out how
to do the same in Nim.</p>

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


<p>I remembered seeing the variables <a href="https://nim-lang.org/docs/system.html#stdin"><code>stdin</code></a> and <a href="https://nim-lang.org/docs/system.html#stdout"><code>stdout</code></a> defined in the
implicitly<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> imported <code>system</code> module. So I started with trying
to get the value of those variables and see if they helped me figure
out how they are associated with the terminal.</p>

<h3 id="using-os-dot-getfileinfo">Using <code>os.getFileInfo</code>&nbsp;<a class="headline-hash no-text-decoration" href="#using-os-dot-getfileinfo">#</a></h3>


<p>From the docs of <code>stdin</code> and <code>stdout</code>, I learned that the <strong>type</strong> of
both of those is <code>File</code>. So while searching for &ldquo;File&rdquo;, I ended up on
<a href="https://devdocs.io/nim/os#FileInfo"><code>os.FileInfo</code></a>, whose value I can get using <a href="https://devdocs.io/nim/os#getFileInfo"><code>os.getFileInfo</code></a>.</p>
<p>Based on the structure of that <code>FileInfo</code> object:</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">FileInfo</span> <span class="o">=</span> <span class="k">object</span>
</span></span><span class="line hl"><span class="cl">  <span class="n">id</span><span class="o">*</span><span class="p">:</span> <span class="k">tuple</span><span class="o">[</span><span class="n">device</span><span class="p">:</span> <span class="n">DeviceId</span><span class="p">,</span> <span class="n">file</span><span class="p">:</span> <span class="n">FileId</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">kind</span><span class="o">*</span><span class="p">:</span> <span class="n">PathComponent</span>
</span></span><span class="line"><span class="cl">  <span class="n">size</span><span class="o">*</span><span class="p">:</span> <span class="n">BiggestInt</span>
</span></span><span class="line"><span class="cl">  <span class="n">permissions</span><span class="o">*</span><span class="p">:</span> <span class="kt">set</span><span class="o">[</span><span class="n">FilePermission</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="n">linkCount</span><span class="o">*</span><span class="p">:</span> <span class="n">BiggestInt</span>
</span></span><span class="line"><span class="cl">  <span class="n">lastAccessTime</span><span class="o">*</span><span class="p">:</span> <span class="n">times</span><span class="p">.</span><span class="n">Time</span>
</span></span><span class="line"><span class="cl">  <span class="n">lastWriteTime</span><span class="o">*</span><span class="p">:</span> <span class="n">times</span><span class="p">.</span><span class="n">Time</span>
</span></span><span class="line"><span class="cl">  <span class="n">creationTime</span><span class="o">*</span><span class="p">:</span> <span class="n">times</span><span class="p">.</span><span class="n">Time</span>
</span></span></code></pre></div><p>I guessed that the <code>id</code> field in there might hold the information I
needed.. and indeed it did!</p>
<p>By printing out the value of <code>getFileInfo(stdin).id.file</code>, and running
the Nim-compiled binary by itself (<code>./binary</code>) <em>vs</em> providing it the
output of another process (<code>echo foo | ./binary</code>), I learned that its
value is <code>35</code> if the binary is not receiving input from another
process/pipe.</p>
<p><em>Similarly the value of <code>getFileInfo(stdout).id.file</code> is also <code>35</code> if
the binary is not sending the output to another process/pipe.</em></p>
<p>Based on that deduction, this worked!</p>
<p><a id="code-snippet--stdin-stdout-getFileInfo"></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"># Figuring out if input is coming from a pipe and if output is going to a pipe.</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="n">std</span><span class="o">/[</span><span class="n">os</span><span class="p">,</span> <span class="n">strutils</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># https://nim-lang.org/docs/os.html#FileInfo</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">getFileInfo</span><span class="p">(</span><span class="n">stdin</span><span class="p">).</span><span class="n">id</span><span class="p">.</span><span class="n">file</span><span class="o">==</span><span class="mi">35</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="c"># ./stdin_stdout foo</span>
</span></span><span class="line"><span class="cl">  <span class="c"># ./stdin_stdout foo | cat</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;--&gt; Input from terminal&#34;</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="c"># echo bar | ./stdin_stdout</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo bar | ./stdin_stdout | cat</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;--&gt; Input from a PIPE/FILE: `&#34;</span> <span class="o">&amp;</span> <span class="n">readAll</span><span class="p">(</span><span class="n">stdin</span><span class="p">).</span><span class="n">strip</span><span class="p">()</span> <span class="o">&amp;</span> <span class="s">&#34;&#39;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">getFileInfo</span><span class="p">(</span><span class="n">stdout</span><span class="p">).</span><span class="n">id</span><span class="p">.</span><span class="n">file</span><span class="o">==</span><span class="mi">35</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="c"># ./stdin_stdout foo</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo bar | ./stdin_stdout foo</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;    Output to terminal --&gt;&#34;</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="c"># ./stdin_stdout | cat</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo bar | ./stdin_stdout | cat</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;    Output to a PIPE --&gt;&#34;</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--stdin-stdout-getFileInfo">Code Snippet 2</a>:</span>
  Using <code>os.getFileInfo</code> to check <b>stdin</b> and <b>stdout</b>
</div>
<div class="note">
<p>But there&rsquo;s a catch .. That value of <code>35</code> might not be the same on all
POSIX systems. So instead, use the <code>isatty()</code> based approach that I
show next.</p>
</div>

<h3 id="stdin-stdout-isatty">Using <code>terminal.isatty</code>&nbsp;<a class="headline-hash no-text-decoration" href="#stdin-stdout-isatty">#</a></h3>


<p>In the same reddit thread, <a href="https://www.reddit.com/user/bpbio"><strong>/u/bpbio</strong></a> from Reddit provides a better,
concise <a href="https://www.reddit.com/r/nim/comments/8jki3k/checking_stdin_for_content/dz0pmjd/">answer</a>&mdash;using the <code>isatty</code> proc from the <code>terminal</code> module:</p>
<blockquote>
<div class="highlight"><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">isatty</span><span class="p">(</span><span class="n">f</span><span class="p">:</span> <span class="n">File</span><span class="p">):</span> <span class="kt">bool</span> <span class="p">{.</span><span class="n">raises</span><span class="p">:</span> <span class="o">[]</span><span class="p">,</span> <span class="n">tags</span><span class="p">:</span> <span class="o">[]</span><span class="p">.}</span>
</span></span></code></pre></div><p>Returns true if f is associated with a terminal device.</p>
</blockquote>
<p>From my brief testing, I saw that <code>isatty(stdin)</code> is equivalent to
<code>getFileInfo(stdin).id.file==35</code>, and the same for <code>stdout</code> too.</p>
<p>So my above snippet can be rewritten as:</p>
<p><a id="code-snippet--stdin-stdout-isatty"></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"># Figuring out if input is coming from a pipe and if output is going to a pipe.</span>
</span></span><span class="line hl"><span class="cl"><span class="kn">import</span> <span class="n">std</span><span class="o">/[</span><span class="n">terminal</span><span class="p">,</span> <span class="n">strutils</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl"><span class="k">if</span> <span class="n">isatty</span><span class="p">(</span><span class="n">stdin</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="c"># ./stdin_stdout foo</span>
</span></span><span class="line"><span class="cl">  <span class="c"># ./stdin_stdout foo | cat</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;--&gt; Input from terminal&#34;</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="c"># echo bar | ./stdin_stdout</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo bar | ./stdin_stdout | cat</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;--&gt; Input from a PIPE/FILE: `&#34;</span> <span class="o">&amp;</span> <span class="n">readAll</span><span class="p">(</span><span class="n">stdin</span><span class="p">).</span><span class="n">strip</span><span class="p">()</span> <span class="o">&amp;</span> <span class="s">&#34;&#39;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl"><span class="k">if</span> <span class="n">isatty</span><span class="p">(</span><span class="n">stdout</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="c"># ./stdin_stdout foo</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo bar | ./stdin_stdout foo</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;    Output to terminal --&gt;&#34;</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="c"># ./stdin_stdout | cat</span>
</span></span><span class="line"><span class="cl">  <span class="c"># echo bar | ./stdin_stdout | cat</span>
</span></span><span class="line"><span class="cl">  <span class="n">echo</span> <span class="s">&#34;    Output to a PIPE --&gt;&#34;</span>
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--stdin-stdout-isatty">Code Snippet 3</a>:</span>
  Using <code>terminal.isatty</code> to check <b>stdin</b> and <b>stdout</b>
</div>

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


<p>Assuming that the Nim-compiled binary of the above code<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> is
<code>stdin_stdout</code>, you get this output:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt; ./stdin_stdout
</span></span><span class="line"><span class="cl">--&gt; Input from terminal
</span></span><span class="line"><span class="cl">    Output to terminal --&gt;
</span></span><span class="line"><span class="cl">&gt; ./stdin_stdout | cat
</span></span><span class="line"><span class="cl">--&gt; Input from terminal
</span></span><span class="line"><span class="cl">    Output to a PIPE --&gt;
</span></span><span class="line"><span class="cl">&gt; echo foo | ./stdin_stdout
</span></span><span class="line"><span class="cl">--&gt; Input from a PIPE/FILE: `foo&#39;
</span></span><span class="line"><span class="cl">    Output to terminal --&gt;
</span></span><span class="line"><span class="cl">&gt; echo foo | ./stdin_stdout | cat
</span></span><span class="line"><span class="cl">--&gt; Input from a PIPE/FILE: `foo&#39;
</span></span><span class="line"><span class="cl">    Output to a PIPE --&gt;
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Nim has the concept of implictly and explicitly imported
modules. You do not need to manually import the former using the
<code>import</code> keyword, while you need to do that for the latter.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>It doesn&rsquo;t matter if you use <a href="#code-snippet--stdin-stdout-getFileInfo">Code Snippet 2</a> or
<a href="#code-snippet--stdin-stdout-isatty">Code Snippet 3</a>.&#160;<a href="#fnref:2" 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/stdin" term="stdin" label="stdin"/><category scheme="https://scripter.co/tags/stdout" term="stdout" label="stdout"/><category scheme="https://scripter.co/tags/tty" term="tty" label="tty"/><category scheme="https://scripter.co/tags/terminal" term="terminal" label="terminal"/><category scheme="https://scripter.co/tags/pipe" term="pipe" label="pipe"/><category scheme="https://scripter.co/tags/bash" term="bash" label="bash"/></entry></feed>