<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yuna</title>
    <description>The latest articles on DEV Community by Yuna (@yunar-r).</description>
    <link>https://dev.to/yunar-r</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4069422%2F0496686e-bf2c-4cd0-8922-d90974c1352a.png</url>
      <title>DEV Community: Yuna</title>
      <link>https://dev.to/yunar-r</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yunar-r"/>
    <language>en</language>
    <item>
      <title>Porting Intel SSE Intrinsics to ARM NEON in a Real C Project</title>
      <dc:creator>Yuna</dc:creator>
      <pubDate>Fri, 21 Aug 2026 10:48:49 +0000</pubDate>
      <link>https://dev.to/yunar-r/porting-intel-sse-intrinsics-to-arm-neon-in-a-real-c-project-5f5f</link>
      <guid>https://dev.to/yunar-r/porting-intel-sse-intrinsics-to-arm-neon-in-a-real-c-project-5f5f</guid>
      <description>&lt;p&gt;I recently wanted to see what actually happens when an existing C project containing Intel SSE intrinsics is ported to ARM64.&lt;/p&gt;

&lt;p&gt;The usual example is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_add_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;float32x4_t&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vaddq_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But real porting work is rarely just a table of intrinsic names.&lt;/p&gt;

&lt;p&gt;There are also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compiler flags&lt;/li&gt;
&lt;li&gt;floating-point semantics&lt;/li&gt;
&lt;li&gt;reduction order&lt;/li&gt;
&lt;li&gt;architecture-specific headers&lt;/li&gt;
&lt;li&gt;build-system assumptions&lt;/li&gt;
&lt;li&gt;fallback implementations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I created a deliberately x86-specific C project and passed it through a tool I have been building called &lt;strong&gt;Miruri&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Miruri:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yuna-r/miruri" rel="noopener noreferrer"&gt;https://github.com/yuna-r/miruri&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The interesting part was not only that the code compiled on ARM64, but also how the resulting implementation was structured.&lt;/p&gt;




&lt;h2&gt;
  
  
  The original project
&lt;/h2&gt;

&lt;p&gt;The project is intentionally small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intel-intrinsic-demo/
├── CMakeLists.txt
├── Makefile
├── include/
│   └── simd_math.h
└── src/
    ├── main.c
    └── simd_math.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation directly includes the Intel SSE header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;xmmintrin.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no ARM compatibility code in the original source.&lt;/p&gt;

&lt;p&gt;The project uses these SSE intrinsics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_mm_loadu_ps
_mm_add_ps
_mm_mul_ps
_mm_storeu_ps
_mm_movehl_ps
_mm_shuffle_ps
_mm_add_ss
_mm_cvtss_f32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  SIMD addition
&lt;/h2&gt;

&lt;p&gt;The original implementation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;simd_add4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;va&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;vr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_add_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;va&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;_mm_storeu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a classic 128-bit SSE operation.&lt;/p&gt;

&lt;p&gt;Four 32-bit floating-point values are loaded, added in parallel, and stored.&lt;/p&gt;

&lt;p&gt;The ARM64 implementation became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;float32x4_t&lt;/span&gt; &lt;span class="n"&gt;va&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vld1q_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;float32x4_t&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vld1q_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;vst1q_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vaddq_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;va&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mapping is very direct:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SSE&lt;/th&gt;
&lt;th&gt;NEON&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_mm_loadu_ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vld1q_f32&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_mm_add_ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vaddq_f32&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_mm_storeu_ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vst1q_f32&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both operate naturally on four 32-bit floats in a 128-bit vector.&lt;/p&gt;




&lt;h2&gt;
  
  
  The resulting code kept both architectures
&lt;/h2&gt;

&lt;p&gt;What I liked about the generated port was that it did not simply delete the x86 implementation.&lt;/p&gt;

&lt;p&gt;Instead, it became something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if defined(__SSE__)
&lt;/span&gt;
    &lt;span class="cm"&gt;/* SSE implementation */&lt;/span&gt;

&lt;span class="cp"&gt;#elif defined(__aarch64__) || defined(_M_ARM64)
&lt;/span&gt;
    &lt;span class="cm"&gt;/* NEON implementation */&lt;/span&gt;

&lt;span class="cp"&gt;#else
&lt;/span&gt;
    &lt;span class="cm"&gt;/* portable scalar implementation */&lt;/span&gt;

&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So an originally x86-only function effectively became a small portable SIMD abstraction.&lt;/p&gt;

&lt;p&gt;The result now has three backends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x86
 └─ SSE

ARM64
 └─ NEON

other architectures
 └─ scalar C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a small library, I prefer this structure over pretending the Intel intrinsic API itself is portable.&lt;/p&gt;

&lt;p&gt;For very large codebases with thousands of &lt;code&gt;_mm_*&lt;/code&gt; calls, a compatibility layer such as sse2neon may make more sense.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multiply-add was not converted to FMA
&lt;/h2&gt;

&lt;p&gt;I also added this operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;simd_mul_add4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;va&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;vc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_mul_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;va&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_add_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;_mm_storeu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tempting ARM implementation would use a fused multiply-add.&lt;/p&gt;

&lt;p&gt;But the generated NEON code instead preserved the two operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;float32x4_t&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;vmulq_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;va&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;vst1q_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vaddq_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vc&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think this is important.&lt;/p&gt;

&lt;p&gt;The original SSE implementation performs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;multiply
↓
round
↓
add
↓
round
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A fused multiply-add can perform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;multiply + add
↓
round once
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can produce slightly different floating-point results.&lt;/p&gt;

&lt;p&gt;For many programs that difference is irrelevant.&lt;/p&gt;

&lt;p&gt;For numerical software, codecs, simulations, databases, or HPC code, it may not be.&lt;/p&gt;

&lt;p&gt;Porting SIMD code is therefore not always equivalent to selecting the shortest native instruction sequence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Horizontal reduction was more interesting
&lt;/h2&gt;

&lt;p&gt;I intentionally implemented a four-element sum using SSE1 operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nf"&gt;simd_sum4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_movehl_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;pair_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_mm_add_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;shuffled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;_mm_shuffle_ps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;pair_sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;pair_sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;_MM_SHUFFLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;__m128&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;_mm_add_ss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair_sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_mm_cvtss_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The effective reduction order is approximately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(a[0] + a[2]) + (a[1] + a[3])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The NEON version became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;float32x4_t&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;vld1q_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;float32x2_t&lt;/span&gt; &lt;span class="n"&gt;pair_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;vadd_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;vget_low_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;vget_high_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;vget_lane_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;vpadd_f32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair_sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pair_sum&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scalar fallback was also written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was interesting because the transformation preserved the basic pairwise reduction structure instead of reducing the vector in an unrelated order.&lt;/p&gt;

&lt;p&gt;Floating-point addition is not associative, so this can matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture-specific build flags matter too
&lt;/h2&gt;

&lt;p&gt;The original CMake project deliberately contained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_C_COMPILER_ID MATCHES &lt;span class="s2"&gt;"Clang|GNU"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;simd_math PRIVATE -msse&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is perfectly reasonable on x86.&lt;/p&gt;

&lt;p&gt;It is not reasonable on ARM64.&lt;/p&gt;

&lt;p&gt;On Apple Silicon, Clang rejects it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clang: error: unsupported option '-msse' for target 'arm64-apple-darwin'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The port therefore also had to modify the build logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_C_COMPILER_ID MATCHES &lt;span class="s2"&gt;"Clang|GNU"&lt;/span&gt; AND
   CMAKE_SYSTEM_PROCESSOR MATCHES &lt;span class="s2"&gt;"^(x86_64|amd64|AMD64|i[3-6]86)$"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;target_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;simd_math PRIVATE -msse&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a small example of something that becomes important in larger ports:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;architecture dependencies are not limited to source files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They also exist in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMake&lt;/li&gt;
&lt;li&gt;Makefiles&lt;/li&gt;
&lt;li&gt;configure scripts&lt;/li&gt;
&lt;li&gt;compiler options&lt;/li&gt;
&lt;li&gt;linker options&lt;/li&gt;
&lt;li&gt;dependency selection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Testing the result
&lt;/h2&gt;

&lt;p&gt;The demo contains a small self-test.&lt;/p&gt;

&lt;p&gt;Input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a + b
= [11.000, 0.000, 4.000, 4.000]

a * b + c
= [10.250, -3.000, 0.750, -30.000]

sum(a)
= 2.500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On x86:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a + b = [11.000, 0.000, 4.000, 4.000]
a * b + c = [10.250, -3.000, 0.750, -30.000]
sum(a) = 2.500
SELFTEST: PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same source tree was then built for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux ARM64
→ ELF AArch64

macOS ARM64
→ Mach-O arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Linux ARM64 sysroot was provisioned automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;For simple operations, SSE-to-NEON conversion can look almost trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_mm_loadu_ps
→ vld1q_f32

_mm_add_ps
→ vaddq_f32

_mm_mul_ps
→ vmulq_f32

_mm_storeu_ps
→ vst1q_f32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But that is only the visible part of the problem.&lt;/p&gt;

&lt;p&gt;A serious port also has to consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;instruction semantics
floating-point behavior
operation ordering
compiler flags
build configuration
fallback paths
ABI
target libraries
artifact architecture
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is where automated source transformation becomes more interesting than a simple intrinsic translation table.&lt;/p&gt;

&lt;p&gt;This experiment only uses basic SSE.&lt;/p&gt;

&lt;p&gt;Next I want to try more complicated examples involving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSE2
SSE4
AVX
AVX2
AVX-512
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and see how far the same approach can be pushed.&lt;/p&gt;

</description>
      <category>c</category>
      <category>github</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>I Built Miruri: A Tool That Ports Existing C/C++ Projects Across CPUs and Operating Systems</title>
      <dc:creator>Yuna</dc:creator>
      <pubDate>Fri, 21 Aug 2026 10:46:56 +0000</pubDate>
      <link>https://dev.to/yunar-r/i-built-miruri-a-tool-that-ports-existing-cc-projects-across-cpus-and-operating-systems-2klo</link>
      <guid>https://dev.to/yunar-r/i-built-miruri-a-tool-that-ports-existing-cc-projects-across-cpus-and-operating-systems-2klo</guid>
      <description>&lt;p&gt;CPUs and Operating Systems&lt;/p&gt;

&lt;p&gt;I have been building a tool called &lt;strong&gt;Miruri&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The basic idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Give it an existing software project and a target platform, and let it handle as much of the porting process as possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yuna-r/miruri" rel="noopener noreferrer"&gt;https://github.com/yuna-r/miruri&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is still an alpha project, but it has reached the point where it can already do some surprisingly non-trivial things.&lt;/p&gt;

&lt;p&gt;For example, I have used it to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;port Intel SSE code to ARM NEON&lt;/li&gt;
&lt;li&gt;build Linux ARM64 binaries from an Apple Silicon Mac&lt;/li&gt;
&lt;li&gt;build an Autotools terminal application for macOS&lt;/li&gt;
&lt;li&gt;take a Linux/GNOME Python + GTK application and make it run as a macOS &lt;code&gt;.app&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one surprised me too.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Miruri is trying to solve
&lt;/h2&gt;

&lt;p&gt;Cross-compiling a clean, portable C project is usually not that difficult.&lt;/p&gt;

&lt;p&gt;Real projects are different.&lt;/p&gt;

&lt;p&gt;They contain things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x86 intrinsics
Windows APIs
Linux-specific APIs
architecture-specific compiler flags
platform GUI frameworks
graphics APIs
audio backends
plugins
generated files
custom build scripts
external SDK assumptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A compiler can tell you that something failed.&lt;/p&gt;

&lt;p&gt;It usually cannot tell you how the architecture of the project should change to make another platform a first-class target.&lt;/p&gt;

&lt;p&gt;Miruri tries to operate at that level.&lt;/p&gt;

&lt;p&gt;Instead of thinking only in terms of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source file
→ compiler
→ binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it treats porting more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;existing project
      ↓
analyze platform assumptions
      ↓
construct target requirements
      ↓
choose a migration strategy
      ↓
modify an isolated copy
      ↓
build
      ↓
inspect artifacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;

&lt;p&gt;Miruri itself is written in Go.&lt;/p&gt;

&lt;p&gt;Building it is intentionally simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/yuna-r/miruri.git
&lt;span class="nb"&gt;cd &lt;/span&gt;miruri

go build &lt;span class="nt"&gt;-o&lt;/span&gt; bin/miruri ./cmd/miruri
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the local environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List targets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri targets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then build a project for a target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; macos-arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For projects that actually require source changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri port &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; macos-arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;port&lt;/code&gt; command allows broader source and build-system modifications.&lt;/p&gt;




&lt;h2&gt;
  
  
  It does not edit the original repository
&lt;/h2&gt;

&lt;p&gt;One design decision I made early was that Miruri should not directly mutate the source repository being ported.&lt;/p&gt;

&lt;p&gt;The flow is closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;original repository
        ↓
isolated working copy
        ↓
analysis and modifications
        ↓
build
        ↓
artifact collection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters a lot once automated repair is involved.&lt;/p&gt;

&lt;p&gt;Compiler output, generated files, build caches, object files, and experimental changes should not leak back into the original source tree.&lt;/p&gt;

&lt;p&gt;Accepted source changes can instead be represented as a patch.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI is a repair engine, not the source of truth
&lt;/h2&gt;

&lt;p&gt;Miruri can use Codex CLI for source-level repair.&lt;/p&gt;

&lt;p&gt;But I did not want the system to become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;paste compiler error into AI
→ trust whatever comes back
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The intended relationship is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI proposes changes

compiler validates syntax and ABI assumptions

linker validates symbol resolution

artifact inspection validates output architecture
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;analyze
↓
build
↓
failure
↓
extract diagnostics
↓
repair isolated source
↓
build again
↓
inspect artifact
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For larger platform ports, the repair may involve more than changing a broken line.&lt;/p&gt;

&lt;p&gt;It can add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;platform backends&lt;/li&gt;
&lt;li&gt;compatibility code&lt;/li&gt;
&lt;li&gt;conditional build logic&lt;/li&gt;
&lt;li&gt;new entry points&lt;/li&gt;
&lt;li&gt;GUI adapters&lt;/li&gt;
&lt;li&gt;resource definitions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Linux sysroots are automatically provisioned
&lt;/h2&gt;

&lt;p&gt;One annoying part of cross-compilation is building the target sysroot.&lt;/p&gt;

&lt;p&gt;For example, compiling Linux ARM64 software from macOS may require:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;headers
libc
crt objects
libgcc runtime
target libraries
multiarch paths
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Miruri can provision this automatically.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; linux-arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does not require manually supplying &lt;code&gt;--sysroot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Under the hood, Miruri can retrieve a matching OCI root filesystem and use it as build data.&lt;/p&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; execute the container image.&lt;/p&gt;

&lt;p&gt;The process is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OCI manifest
    ↓
select architecture
    ↓
download layers
    ↓
verify SHA-256 digests
    ↓
extract root filesystem
    ↓
validate toolchain/runtime files
    ↓
use as Clang sysroot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Docker daemon or QEMU is required for this part.&lt;/p&gt;

&lt;p&gt;The result is cached by content digest.&lt;/p&gt;

&lt;p&gt;You can also prefetch it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri sysroot ensure &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; linux-arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and inspect cached sysroots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri sysroot list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Offline builds can reuse them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; linux-arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--offline&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Build-system detection
&lt;/h2&gt;

&lt;p&gt;Real-world OSS immediately forced me to support more than CMake.&lt;/p&gt;

&lt;p&gt;Miruri currently understands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMake
Meson
Autotools
Make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMakeLists.txt
→ CMake

meson.build
→ Meson

configure.ac / configure.in
→ Autotools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an Autotools Git checkout without a generated &lt;code&gt;configure&lt;/code&gt; script, the flow can become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;configure.ac
↓
autoreconf
↓
configure
↓
make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meson can also be managed by Miruri when it is missing from the host.&lt;/p&gt;

&lt;p&gt;This grew organically from testing actual open-source projects.&lt;/p&gt;




&lt;h1&gt;
  
  
  Real-world test 1: nudoku
&lt;/h1&gt;

&lt;p&gt;One project I tested was &lt;code&gt;nudoku&lt;/code&gt;, a terminal Sudoku application.&lt;/p&gt;

&lt;p&gt;It uses Autotools.&lt;/p&gt;

&lt;p&gt;At first Miruri simply stopped with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;detected: autotools
no supported build system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I added Autotools support.&lt;/p&gt;

&lt;p&gt;After that, the same project could be built for Apple Silicon macOS.&lt;/p&gt;

&lt;p&gt;That was the first point where Miruri started to feel less like a cross-compiler wrapper and more like a porting system.&lt;/p&gt;




&lt;h1&gt;
  
  
  Real-world test 2: a Linux GNOME GUI application on macOS
&lt;/h1&gt;

&lt;p&gt;Then I tried something much more unreasonable.&lt;/p&gt;

&lt;p&gt;I used &lt;strong&gt;Drawing&lt;/strong&gt;, a Python + GTK drawing application designed for the GNOME/Linux desktop.&lt;/p&gt;

&lt;p&gt;I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./bin/miruri port &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--target&lt;/span&gt; macos-arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--codex-mode&lt;/span&gt; port &lt;span class="se"&gt;\&lt;/span&gt;
  ~/src/drawing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exposed one missing feature after another.&lt;/p&gt;

&lt;p&gt;The process looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Meson project
↓
Miruri did not support Meson
↓
add Meson adapter

Meson missing on host
↓
add managed Meson runtime

project produces no native executable
↓
support interpreted install artifacts

Linux install tree is not a macOS app
↓
add .app packaging

Linux Python launcher assumptions fail on macOS
↓
add compatibility rewrites

PyGObject runtime not visible
↓
resolve Homebrew Python runtime

bundle entry point shadows Python package
↓
fix package resolution

GTK GSettings schemas not visible
↓
adjust macOS GTK runtime environment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually the Linux application opened on macOS as a real GUI application.&lt;/p&gt;

&lt;p&gt;The GTK interface rendered correctly.&lt;/p&gt;

&lt;p&gt;I could use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;menus&lt;/li&gt;
&lt;li&gt;canvas drawing&lt;/li&gt;
&lt;li&gt;text tools&lt;/li&gt;
&lt;li&gt;fonts&lt;/li&gt;
&lt;li&gt;checkboxes&lt;/li&gt;
&lt;li&gt;radio buttons&lt;/li&gt;
&lt;li&gt;Japanese UI&lt;/li&gt;
&lt;li&gt;mouse interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seeing a GNOME-oriented application show up as a macOS window after going through that pipeline was a fun moment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Intel SSE to ARM NEON
&lt;/h2&gt;

&lt;p&gt;Another experiment involved an intentionally x86-only C project.&lt;/p&gt;

&lt;p&gt;The original source directly used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;xmmintrin.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and operations such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;
&lt;span class="n"&gt;_mm_add_ps&lt;/span&gt;
&lt;span class="n"&gt;_mm_mul_ps&lt;/span&gt;
&lt;span class="n"&gt;_mm_shuffle_ps&lt;/span&gt;
&lt;span class="n"&gt;_mm_storeu_ps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Miruri identified the architecture dependency and the resulting code gained separate backends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if defined(__SSE__)
&lt;/span&gt;
    &lt;span class="cm"&gt;/* x86 */&lt;/span&gt;

&lt;span class="cp"&gt;#elif defined(__aarch64__)
&lt;/span&gt;
    &lt;span class="cm"&gt;/* ARM NEON */&lt;/span&gt;

&lt;span class="cp"&gt;#else
&lt;/span&gt;
    &lt;span class="cm"&gt;/* scalar */&lt;/span&gt;

&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;_mm_add_ps&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;vaddq_f32&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;_mm_loadu_ps&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;became:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;vld1q_f32&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same source tree could then produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux ARM64
→ ELF AArch64

macOS ARM64
→ Mach-O arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiler flags such as &lt;code&gt;-msse&lt;/code&gt; also had to be made architecture-aware.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of issue Miruri is intended to find: architecture assumptions exist outside the C file too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Graph and Target Contract
&lt;/h2&gt;

&lt;p&gt;Internally, I am moving toward representing a project as capabilities rather than just files.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Existing Project
      │
      ▼
Project Graph
      │
      ├── sources
      ├── build steps
      ├── resources
      ├── plugins
      ├── shaders
      └── platform capabilities
      │
      ▼
Target Contract
      │
      ▼
Strategy Planner
      │
      ├── native rebuild
      ├── source rewrite
      ├── compatibility layer
      ├── generated adapter
      └── unresolved blocker
      │
      ▼
Artifact Builder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;xmmintrin.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can be classified as a capability such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cpu.x86.intrinsics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Windows-only GUI dependency could similarly become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;platform.windows.gui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it possible to reason about a port at a higher level than individual compiler errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Artifact inspection matters
&lt;/h2&gt;

&lt;p&gt;A successful compiler exit code is not enough.&lt;/p&gt;

&lt;p&gt;Miruri inspects outputs such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ELF
Mach-O
PE
static archives
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and verifies their architecture.&lt;/p&gt;

&lt;p&gt;If the target is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;macOS ARM64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the resulting Mach-O is actually x86_64, that should not be reported as a successful port.&lt;/p&gt;

&lt;p&gt;Build results can also include metadata such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;analysis.json
plan.json
build.log
manifest.json
sysroot.lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so that the generated artifact has some provenance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cross-target artifacts are not automatically executed
&lt;/h2&gt;

&lt;p&gt;Miruri currently avoids automatically running foreign target binaries during the porting process.&lt;/p&gt;

&lt;p&gt;For example, when creating an ARM64 Linux ELF on macOS, it stops at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compile
↓
link
↓
artifact inspection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of automatically launching it under an emulator.&lt;/p&gt;

&lt;p&gt;That is intentional.&lt;/p&gt;

&lt;p&gt;Once automatic execution is introduced, results can become dependent on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;emulator behavior&lt;/li&gt;
&lt;li&gt;kernel behavior&lt;/li&gt;
&lt;li&gt;drivers&lt;/li&gt;
&lt;li&gt;graphics stack&lt;/li&gt;
&lt;li&gt;audio stack&lt;/li&gt;
&lt;li&gt;target services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I currently prefer to keep artifact production and target-runtime validation as separate stages.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Miruri still cannot do
&lt;/h2&gt;

&lt;p&gt;This is very much an alpha project.&lt;/p&gt;

&lt;p&gt;There are many hard problems left.&lt;/p&gt;

&lt;p&gt;Some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Direct3D ↔ Vulkan ↔ Metal
shader translation
complex proprietary SDKs
driver dependencies
audio backend translation
full dependency resolution
semantic equivalence testing
bit-exact SIMD verification
production-quality standalone GUI packaging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Automatically making something compile is much easier than proving that the new implementation behaves exactly like the old one.&lt;/p&gt;

&lt;p&gt;That is especially true for numerical and SIMD-heavy software.&lt;/p&gt;




&lt;h2&gt;
  
  
  The development process has been surprisingly fun
&lt;/h2&gt;

&lt;p&gt;One thing I have enjoyed is testing Miruri with real open-source projects instead of only synthetic fixtures.&lt;/p&gt;

&lt;p&gt;A fixture tends to fail in the way you expected.&lt;/p&gt;

&lt;p&gt;Real software fails in ways you did not think about.&lt;/p&gt;

&lt;p&gt;The development history has looked something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMake works
↓
try real Autotools project
↓
add Autotools

try Meson project
↓
add Meson

try interpreted GUI app
↓
add staged install artifacts

try Linux GTK application on macOS
↓
add macOS application packaging

try x86 intrinsics
↓
add architecture-level porting logic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each project reveals another assumption hidden inside the tool itself.&lt;/p&gt;

&lt;p&gt;That has probably been the most useful form of testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where I want to take it
&lt;/h2&gt;

&lt;p&gt;Some areas I want to explore next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSE / AVX / AVX2 / AVX-512
→ NEON / SVE / SVE2

x86
→ RISC-V

x86
→ POWER

Windows GUI
→ macOS / Linux GUI

Direct3D
→ Vulkan / Metal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am also interested in making semantic validation a much larger part of the system.&lt;/p&gt;

&lt;p&gt;The hard part of automated porting is not generating different code.&lt;/p&gt;

&lt;p&gt;The hard part is establishing that the different code still means the same thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Miruri is an experiment in automating software porting across CPUs and operating systems.&lt;/p&gt;

&lt;p&gt;Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yuna-r/miruri" rel="noopener noreferrer"&gt;https://github.com/yuna-r/miruri&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the moment it has infrastructure for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMake
Meson
Autotools
Make

Linux
macOS
Windows

x86_64
ARM64
RISC-V
POWER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and I have already used it for experiments including:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intel SSE
→ ARM NEON
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Autotools application
→ Apple Silicon macOS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the slightly ridiculous one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux/GNOME Python + GTK application
→ macOS .app
→ working GUI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is still a lot to build, but the main question behind the project is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How much of real software porting can we turn into a repeatable automated process?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is what I am trying to find out.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>go</category>
      <category>ai</category>
      <category>multiplatform</category>
    </item>
    <item>
      <title>I built RepoTrek: a terminal-first GitHub source browser in Rust</title>
      <dc:creator>Yuna</dc:creator>
      <pubDate>Sun, 09 Aug 2026 03:05:58 +0000</pubDate>
      <link>https://dev.to/yunar-r/i-built-repotrek-a-terminal-first-github-source-browser-in-rust-326d</link>
      <guid>https://dev.to/yunar-r/i-built-repotrek-a-terminal-first-github-source-browser-in-rust-326d</guid>
      <description>&lt;p&gt;I built &lt;strong&gt;RepoTrek&lt;/strong&gt;, a terminal-first GitHub source browser written in Rust.&lt;/p&gt;

&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yuna-r/repotrek" rel="noopener noreferrer"&gt;https://github.com/yuna-r/repotrek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;crates.io:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://crates.io/crates/repotrek" rel="noopener noreferrer"&gt;https://crates.io/crates/repotrek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The basic idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wanted a comfortable way to deeply explore GitHub repositories without constantly switching between the browser, terminal, and editor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RepoTrek is not intended to replace Git clients such as &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;lazygit&lt;/code&gt;, &lt;code&gt;tig&lt;/code&gt;, or &lt;code&gt;gitui&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its focus is different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Git client
    ↓
operate on a repository

RepoTrek
    ↓
explore and read a repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;When reading open-source projects on GitHub, I often move through a sequence like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code
 ↓
Blame
 ↓
Commit
 ↓
Diff
 ↓
File history
 ↓
Another file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub's web interface is excellent, but when I spend a long time reading source code, I prefer staying in the terminal and using the keyboard.&lt;/p&gt;

&lt;p&gt;So I started building a TUI specifically around &lt;strong&gt;source code exploration&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  No clone required
&lt;/h2&gt;

&lt;p&gt;You can open a repository directly from GitHub.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rust-lang/rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;torvalds/linux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RepoTrek retrieves the repository information through GitHub APIs, so you don't need to clone the entire repository just to inspect it.&lt;/p&gt;

&lt;p&gt;This is especially convenient for quickly looking through large projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;RepoTrek currently includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository tree browsing&lt;/li&gt;
&lt;li&gt;Source code viewer with line numbers&lt;/li&gt;
&lt;li&gt;Syntax highlighting&lt;/li&gt;
&lt;li&gt;Dark / Light themes&lt;/li&gt;
&lt;li&gt;Commit history&lt;/li&gt;
&lt;li&gt;Commit diffs&lt;/li&gt;
&lt;li&gt;File history&lt;/li&gt;
&lt;li&gt;Git blame&lt;/li&gt;
&lt;li&gt;Branch switching&lt;/li&gt;
&lt;li&gt;File search&lt;/li&gt;
&lt;li&gt;Repository-wide code search&lt;/li&gt;
&lt;li&gt;Symbol navigation&lt;/li&gt;
&lt;li&gt;Definition search&lt;/li&gt;
&lt;li&gt;Pull Requests&lt;/li&gt;
&lt;li&gt;Issues&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Releases&lt;/li&gt;
&lt;li&gt;Keyboard-based text selection and copy&lt;/li&gt;
&lt;li&gt;Source/diff wrapping&lt;/li&gt;
&lt;li&gt;HTML export for printing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interface is designed to make moving between these views fast without leaving the terminal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Source code browsing
&lt;/h2&gt;

&lt;p&gt;The main view works like a terminal-native repository browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app.rs
├── auth.rs
├── export.rs
├── highlight.rs
├── provider/
└── ui/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a file and RepoTrek displays it with line numbers and syntax highlighting.&lt;/p&gt;

&lt;p&gt;Common languages such as Rust, Python, JavaScript, TypeScript, C/C++, Go, Java, YAML, TOML, JSON, Shell, HTML, CSS, and Markdown are recognized.&lt;/p&gt;

&lt;p&gt;Unknown formats simply fall back to plain text.&lt;/p&gt;




&lt;h2&gt;
  
  
  Blame and file history
&lt;/h2&gt;

&lt;p&gt;One feature I especially wanted was the ability to move naturally between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source line
    ↓
blame
    ↓
commit
    ↓
diff
    ↓
history
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current source code often tells you &lt;strong&gt;what&lt;/strong&gt; the program does.&lt;/p&gt;

&lt;p&gt;History often tells you &lt;strong&gt;why&lt;/strong&gt; it became that way.&lt;/p&gt;

&lt;p&gt;That makes blame and file history important parts of RepoTrek rather than secondary features.&lt;/p&gt;




&lt;h2&gt;
  
  
  Commit diffs
&lt;/h2&gt;

&lt;p&gt;Commit diffs include both old and new line numbers.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  81   81     fn example() {
  82          - old_code();
       82     + new_code();
  83   83     }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Added and removed lines also have separate highlighting.&lt;/p&gt;

&lt;p&gt;Long source lines and diffs can be wrapped directly inside the TUI.&lt;/p&gt;




&lt;h2&gt;
  
  
  Search and navigation
&lt;/h2&gt;

&lt;p&gt;RepoTrek provides several ways to move around a repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  File search
&lt;/h3&gt;

&lt;p&gt;Search files by name and quickly jump to a result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code search
&lt;/h3&gt;

&lt;p&gt;Search repository contents and open matching files directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symbol navigation
&lt;/h3&gt;

&lt;p&gt;Inside a source file, &lt;code&gt;@&lt;/code&gt; opens a symbol picker.&lt;/p&gt;

&lt;p&gt;For Rust, for example, RepoTrek can identify things such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct
enum
trait
impl
fn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Definition search
&lt;/h3&gt;

&lt;p&gt;Pressing &lt;code&gt;d&lt;/code&gt; searches for likely definitions of the identifier around the current cursor position.&lt;/p&gt;

&lt;p&gt;This is currently heuristic-based rather than a full LSP implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  GitHub information inside the TUI
&lt;/h2&gt;

&lt;p&gt;RepoTrek is gradually bringing more of the GitHub repository experience into the terminal.&lt;/p&gt;

&lt;p&gt;It can display information for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code
Commits
Pull Requests
Issues
Actions
Releases
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the web interface is still useful, pressing &lt;code&gt;o&lt;/code&gt; opens the corresponding GitHub page.&lt;/p&gt;

&lt;p&gt;The goal isn't to eliminate the browser completely.&lt;/p&gt;

&lt;p&gt;The goal is to make it optional during normal source exploration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keyboard-first
&lt;/h2&gt;

&lt;p&gt;I wanted the application to remain usable almost entirely from the keyboard.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shift+J    extend selection downward
Shift+K    extend selection upward
Shift+A    select all
Shift+C    copy

v          Vim-style selection
y          copy selection

Esc        clear selection / go back
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are also shortcuts for searching, switching branches, toggling themes, wrapping lines, and opening external GitHub pages.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dark and Light themes
&lt;/h2&gt;

&lt;p&gt;RepoTrek supports both Dark and Light themes.&lt;/p&gt;

&lt;p&gt;The Light theme is not just an inverted Dark theme.&lt;/p&gt;

&lt;p&gt;Syntax colors, selected lines, active lines, and diff colors are defined separately so source code remains readable in both modes.&lt;/p&gt;

&lt;p&gt;The selected theme is persisted between sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Printing source code from a TUI
&lt;/h2&gt;

&lt;p&gt;One slightly unusual feature is HTML export.&lt;/p&gt;

&lt;p&gt;RepoTrek can generate printable HTML for source files and diffs.&lt;/p&gt;

&lt;p&gt;Exports include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Syntax highlighting&lt;/li&gt;
&lt;li&gt;Line numbers&lt;/li&gt;
&lt;li&gt;Old/new diff line numbers&lt;/li&gt;
&lt;li&gt;Added/removed line backgrounds&lt;/li&gt;
&lt;li&gt;Print-oriented layout&lt;/li&gt;
&lt;li&gt;A4 landscape CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Files are automatically written to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with timestamped filenames.&lt;/p&gt;

&lt;p&gt;I sometimes like reading larger pieces of source code away from the editor, so I wanted RepoTrek to treat printing as a real output format rather than an afterthought.&lt;/p&gt;




&lt;h2&gt;
  
  
  Built with Rust and Ratatui
&lt;/h2&gt;

&lt;p&gt;RepoTrek is written in Rust and uses Ratatui for the terminal UI.&lt;/p&gt;

&lt;p&gt;At a high level, the architecture looks roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub API
    ↓
Provider
    ↓
RepoTrek models
    ↓
Application state
    ↓
Ratatui UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I intentionally keep GitHub-specific API structures away from most of the UI.&lt;/p&gt;

&lt;p&gt;The idea is to make support for other Git forges possible later.&lt;/p&gt;

&lt;p&gt;Potential future providers could include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitLab
Gitea
Forgejo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cross-platform releases
&lt;/h2&gt;

&lt;p&gt;RepoTrek is built for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Linux
  x86_64
  ARM64

macOS
  Apple Silicon
  Intel

Windows
  x86_64
  ARM64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Release builds are automated with GitHub Actions.&lt;/p&gt;

&lt;p&gt;The project is also available through crates.io:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;repotrek
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;RepoTrek is still a v0.x project, so there are many things I want to improve.&lt;/p&gt;

&lt;p&gt;Some ideas include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better symbol analysis&lt;/li&gt;
&lt;li&gt;LSP integration&lt;/li&gt;
&lt;li&gt;Improved commit graphs&lt;/li&gt;
&lt;li&gt;Better PR review navigation&lt;/li&gt;
&lt;li&gt;More GitHub Actions information&lt;/li&gt;
&lt;li&gt;Smarter caching&lt;/li&gt;
&lt;li&gt;Performance improvements for very large repositories&lt;/li&gt;
&lt;li&gt;GitLab / Gitea / Forgejo support&lt;/li&gt;
&lt;li&gt;Better terminal capability detection&lt;/li&gt;
&lt;li&gt;Mouse support where useful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the main goal will stay the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make exploring source code from the terminal enjoyable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yuna-r/repotrek" rel="noopener noreferrer"&gt;https://github.com/yuna-r/repotrek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;crates.io:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://crates.io/crates/repotrek" rel="noopener noreferrer"&gt;https://crates.io/crates/repotrek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install with Cargo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;repotrek
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you enjoy Rust, TUIs, open source, or simply reading other people's code, I'd love for you to try it.&lt;/p&gt;

&lt;p&gt;Feedback, issues, and pull requests are welcome 🐻🦀&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
