<?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: Francesco Pira</title>
    <description>The latest articles on DEV Community by Francesco Pira (@pirafrank).</description>
    <link>https://dev.to/pirafrank</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%2F127193%2F4fce8c7a-47db-499c-a7fc-69303b7e9a79.jpg</url>
      <title>DEV Community: Francesco Pira</title>
      <link>https://dev.to/pirafrank</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pirafrank"/>
    <language>en</language>
    <item>
      <title>Cross compilation in Rust</title>
      <dc:creator>Francesco Pira</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:32:01 +0000</pubDate>
      <link>https://dev.to/pirafrank/cross-compilation-in-rust-2nfn</link>
      <guid>https://dev.to/pirafrank/cross-compilation-in-rust-2nfn</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://fpira.com/blog/2025/01/cross-compilation-in-rust/" rel="noopener noreferrer"&gt;fpira.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/postimages/3013/90363-rust-cross-compilation.jpg" class="article-body-image-wrapper"&gt;&lt;img src="/static/postimages/3013/90363-rust-cross-compilation.jpg" alt="Cross compile in Rust"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the advantages of Rust applications is the possibility to ship the same code across different targets, with many CPU architecture and operating systems setup supported as first-class citizen. In such scenario, cross compilation is a fundamental technique for developers who want their Rust applications to run on multiple platforms, as it would be highly unpractical to parallel develop and test on each of your targets. By configuring your development environment to target different architectures, you can build software that operates seamlessly across various systems, and by setting up CI/CD pipelines for cross compilation you can develop on one platform while building, testing, and shipping for all of them in an automated fashion.&lt;/p&gt;

&lt;p&gt;In this article, I'll tell about how to move the first steps for cross compilation in Rust, address common challenges, and provide practical examples for a CI/CD environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Consider a binary Rust application, one like &lt;a href="https://github.com/pirafrank/appimage_updater" rel="noopener noreferrer"&gt;appimage_updater&lt;/a&gt;. We have a &lt;code&gt;rust-toolchain.toml&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Rust Toolchain File&lt;/span&gt;

&lt;span class="c"&gt;# Version of Rust to use&lt;/span&gt;
&lt;span class="nn"&gt;[toolchain]&lt;/span&gt;
&lt;span class="py"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"stable"&lt;/span&gt;

&lt;span class="c"&gt;# Run `rustup target add &amp;lt;target&amp;gt;` to install a target platform&lt;/span&gt;
&lt;span class="nn"&gt;[target]&lt;/span&gt;
&lt;span class="py"&gt;targets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"x86_64-unknown-linux-gnu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"aarch64-unknown-linux-gnu"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as I am coding on x86_64 arch but also want to cross compile to aarch64 to release for that platform as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1 (standard approach)
&lt;/h2&gt;

&lt;p&gt;The first option is the standard one, which requires no extra tools and relies only on &lt;code&gt;cargo&lt;/code&gt; and the usual compilation toolbelt for the target architecture. In this case, we need to install &lt;code&gt;aarch64-linux-gnu-gcc&lt;/code&gt; linker (via your package manager, e.g. &lt;code&gt;sudo apt install gcc-aarch64-linux-gnu&lt;/code&gt;). Then you need to create a file &lt;code&gt;.cargo/config.toml&lt;/code&gt; and add the following content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[target.aarch64-unknown-linux-gnu]&lt;/span&gt;
&lt;span class="py"&gt;linker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"aarch64-linux-gnu-gcc"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to tell cargo which linker to use then compile (for the aarch64 target in this case).&lt;/p&gt;

&lt;p&gt;Now you can compile (on x86_64 arch) for both x86_64 and aarch64 by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo build --target x86_64-unknown-linux-gnu
cargo build --target aarch64-unknown-linux-gnu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;of course, I assume that on x86_64 you already have the necessary compile tools already installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2 (an easier approach via cross)
&lt;/h2&gt;

&lt;p&gt;This approach uses &lt;code&gt;cross&lt;/code&gt; and doesn’t require we to install a linker for the target platform. It will handle the underground work for us. It works using tailored-made Docker images, one per each target, for an easy setup that doesn’t require install tooling on the host.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cross&lt;/code&gt; requirements are &lt;a href="https://github.com/cross-rs/cross/wiki/Getting-Started" rel="noopener noreferrer"&gt;just a few&lt;/a&gt; and it’s likely you already have them installed. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Rust stable toolchain (which you can install via &lt;code&gt;rustup toolchain install stable&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;a container engine, like &lt;code&gt;docker&lt;/code&gt; or &lt;code&gt;podman&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you got them, you can install &lt;code&gt;cross&lt;/code&gt; . Either install it from source using &lt;code&gt;cargo&lt;/code&gt; by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo install cross
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or, if you have &lt;a href="https://github.com/cargo-bins/cargo-binstall" rel="noopener noreferrer"&gt;cargo-binstall&lt;/a&gt;, you can get the pre-built binary via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo binstall cross
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, there’s no need to setup the project cargo config in &lt;code&gt;.cargo/config.toml&lt;/code&gt; . We can just cross compile by replacing the word &lt;code&gt;cargo&lt;/code&gt; with &lt;code&gt;cross&lt;/code&gt; in the compilation commands we used earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cross build --target x86_64-unknown-linux-gnu
cross build --target aarch64-unknown-linux-gnu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Going GitHub Actions
&lt;/h2&gt;

&lt;p&gt;To cross compile on a GitHub Action, the process is pretty similar. You just need to setup the Rust stable toolchain, then install cross as you’d do locally. Considering I did not want to setup &lt;em&gt;cargo-binstall&lt;/em&gt; on the Action, I went with &lt;code&gt;cargo install&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Rust&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions-rust-lang/setup-rust-toolchain@v1&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;toolchain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup cross toolchain&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo install cross&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cross compile&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cross build --release --target x86_64-unknown-linux-gnu&lt;/span&gt;
      &lt;span class="s"&gt;cross build --release --target aarch64-unknown-linux-gnu&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a full setup, including a release pipeline with assets, please check my &lt;a href="https://github.com/pirafrank/appimage_updater/blob/e5b616af6466baa80fb16e3890fbfb5cc85ef7a3/.github/workflows/release.yml" rel="noopener noreferrer"&gt;Appimage Updater&lt;/a&gt; project.&lt;/p&gt;

&lt;h2&gt;
  
  
  A different GitHub Action approach
&lt;/h2&gt;

&lt;p&gt;A different approach, one with more targets, may use a GitHub Action matrix configuration to compile on different runners with different host operating systems. It may help parallelizing the build and speed up CI and release pipelines.&lt;/p&gt;

&lt;p&gt;Here's an example of a CI pipeline I built for one of my private projects that's still in development. For the sake of clarity, I put combinations of OS and targets I want to compile on on a separate file called &lt;code&gt;matrix.jsonc&lt;/code&gt;.  Consider that GitHub Actions hosted runners have a limited set of available OS so cross compilation is needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;raw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ubuntu-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"x86_64-unknown-linux-gnu"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ubuntu-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aarch64-unknown-linux-gnu"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ubuntu-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"x86_64-unknown-linux-musl"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ubuntu-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aarch64-unknown-linux-musl"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ubuntu-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"x86_64-unknown-freebsd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"macos-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"x86_64-apple-darwin"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"macos-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aarch64-apple-darwin"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"windows-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"x86_64-pc-windows-gnu"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"windows-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"x86_64-pc-windows-msvc"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"windows-latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aarch64pcwindowsmsvc"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;endraw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow file has a job called &lt;code&gt;make_matrix&lt;/code&gt; to parse and process &lt;code&gt;matrix.jsonc&lt;/code&gt;, which is then set as a output for later retrieval in the next &lt;code&gt;ci&lt;/code&gt; job. The process configures tooling via &lt;a href="https://github.com/taiki-e/setup-cross-toolchain-action" rel="noopener noreferrer"&gt;taiki-e/setup-cross-toolchain-action&lt;/a&gt;, a GitHub Action for easy setup of toolchains for cross compilation and cross testing for Rust. Each combination of the matrix is an input of such step, sparking a dedicated parallel run. If any of those runs fails, other jobs are stopped and the whole workflow run quits on failure, as you would expect for a CI job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;% raw %&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.github/workflows/ci.yml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/**&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tests/**&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build.rs&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Cargo.toml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Cargo.lock&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rust-toolchain.toml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;matrix.json&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;make_matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.set-matrix.outputs.matrix }}&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MATRIX_FILE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;matrix.jsonc&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;set-matrix&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo "matrix=$(grep -v '//' $MATRIX_FILE | jq -c '.')" &amp;gt;&amp;gt; "$GITHUB_OUTPUT"&lt;/span&gt;

  &lt;span class="na"&gt;ci&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make_matrix&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{fromJson(needs.make_matrix.outputs.matrix)}}&lt;/span&gt;
      &lt;span class="na"&gt;max-parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Rust&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions-rust-lang/setup-rust-toolchain@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;toolchain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install cross compilation tools&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;taiki-e/setup-cross-toolchain-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.target }}&lt;/span&gt;

      &lt;span class="c1"&gt;# setup-cross-toolchain-action sets the `CARGO_BUILD_TARGET` environment variable,&lt;/span&gt;
      &lt;span class="c1"&gt;# so there is no need for an explicit `--target` flag.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build project&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test project&lt;/span&gt;
        &lt;span class="c1"&gt;# Skip tests on FreeBSD, because testing are not supported by cross on FreeBSD.&lt;/span&gt;
        &lt;span class="c1"&gt;# https://github.com/cross-rs/cross#supported-targets&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ !contains(matrix.target, 'freebsd') &amp;amp;&amp;amp; !contains(matrix.target, 'aarch64-pc-windows-msvc') }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo test verbose&lt;/span&gt;

&lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;% endraw %&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note I made some adjustments to comply with the scenarios supported by &lt;em&gt;setup-cross-toolchain-action&lt;/em&gt;. For example, &lt;code&gt;cargo test&lt;/code&gt; is unsupported when compile for &lt;code&gt;freebsd&lt;/code&gt; (&lt;a href="https://github.com/taiki-e/setup-cross-toolchain-action?tab=readme-ov-file#freebsd" rel="noopener noreferrer"&gt;source&lt;/a&gt;) or for triple &lt;code&gt;aarch64-pc-windows-msvc&lt;/code&gt; (&lt;a href="https://github.com/taiki-e/setup-cross-toolchain-action?tab=readme-ov-file#windows-msvc" rel="noopener noreferrer"&gt;source&lt;/a&gt;) so I’ve disabled it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Cross compiling Rust code can be achieved through multiple ways, from the standard &lt;code&gt;cargo&lt;/code&gt;-based approach requiring manual setup of toolchains to more streamlined solutions using tools like &lt;code&gt;cross&lt;/code&gt;, or dedicated GitHub Actions, each with its own advantages. While the standard approach offers more control and understanding of the underlying process, tools like cross and &lt;em&gt;setup-cross-toolchain-action&lt;/em&gt; significantly simplify the workflow, especially in CI/CD pipelines.&lt;/p&gt;

&lt;p&gt;The choice between these methods depends on your specific needs: for local development, &lt;code&gt;cross&lt;/code&gt; provides a clean containerized solution, while for automated builds GitHub Actions with matrix configurations offer scalable and parallel compilation across multiple targets and architectures.&lt;/p&gt;

&lt;p&gt;I hope it helps. Thank for reading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fpira.com/blog" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Read more at fpira.com&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cicd</category>
    </item>
    <item>
      <title>A 30 seconds fix to a WSL2 catastrophic failure</title>
      <dc:creator>Francesco Pira</dc:creator>
      <pubDate>Wed, 08 Jul 2026 22:00:00 +0000</pubDate>
      <link>https://dev.to/pirafrank/a-30-seconds-fix-to-a-wsl2-catastrophic-failure-3e5</link>
      <guid>https://dev.to/pirafrank/a-30-seconds-fix-to-a-wsl2-catastrophic-failure-3e5</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://fpira.com/blog/2026/07/wsl2-fix/" rel="noopener noreferrer"&gt;fpira.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I like WSL2 a lot. It is one of those pieces of my Windows setup that I expect to just be there: open the terminal, get my Linux shell, do the thing. It makes Windows 11 livable.&lt;/p&gt;

&lt;p&gt;That also means that when it breaks, it feels worse than a normal application crash. It means I need to fix it fast. I use &lt;a href="https://rioterm.com/" rel="noopener noreferrer"&gt;Rio&lt;/a&gt; and I configured it to start directly into zsh inside WSL2. One morning it simply closed immediately after launch. No time to read the error, no useful terminal left behind, just a very quick nope.&lt;/p&gt;

&lt;p&gt;WSL2 is accessed from &lt;code&gt;wsl.exe&lt;/code&gt; Windows executable so, as I usually do for those kind of Windows quirks, I opened a Powershell console e run &lt;code&gt;wsl&lt;/code&gt; there to have a shell that stays open even if &lt;code&gt;wsl.exe&lt;/code&gt; crashes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;It printed the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh1eth15g7f13jw7yai7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh1eth15g7f13jw7yai7c.png" alt="PowerShell terminal showing the command wsl and the error message Catastrophic failure, Error code Wsl Service E_UNEXPECTED." width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wow! &lt;em&gt;Catastrophic&lt;/em&gt; is a word I have very rarely seen in my life. Not one I’d rather use in code anyway. So I feared my WSL2 install was gone. Well, I thought &lt;em&gt;fair enough, I will re-import the backup as start again&lt;/em&gt;, as have a backup on a ZFS pool server over a Samba share (but that’s a topic for a future blog post, maybe).&lt;/p&gt;

&lt;p&gt;Then the &lt;code&gt;/Service/&lt;/code&gt; string in the error caught my eye. Windows WSL integration is tight and makes wonders, like exposing localhost port bindings in WSL to Windows, allow Windows to access WSL files and viceversa, and more. Those functionalities are managed by a Windows Service.&lt;/p&gt;

&lt;p&gt;What if it was the Windows Service the one who suffered from the &lt;em&gt;catastrophic&lt;/em&gt; failure? Traditionally, a full Windows restart fixes many things but I had too many open apps to be willing to restart my laptop, so I took another path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix
&lt;/h2&gt;

&lt;p&gt;First turn off the WSL2 tiny VM to keep it safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--shutdown&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then manually restart the crashed Windows Service. Search for &lt;em&gt;Services&lt;/em&gt;  in Start Menu and right click &lt;em&gt;WSL Service&lt;/em&gt;, then &lt;em&gt;Restart&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nt1h4xag79dly74j01y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nt1h4xag79dly74j01y.png" alt="Windows Services application with WSL Service selected and the Restart option highlighted in the context menu" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once it’s done, back to the terminal to check if it’s fixed. Type &lt;code&gt;wsl&lt;/code&gt; to restart the WSL2 machine and open its shell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flnwankqehtrlqby69tqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flnwankqehtrlqby69tqx.png" alt="PowerShell terminal showing an initial WSL catastrophic failure, then wsl shutdown, then a successful WSL shell prompt after running wsl again" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bingo! My WSL install is still safe and sound. The &lt;em&gt;catastrophe&lt;/em&gt; was actually avoided and I get back to work.&lt;/p&gt;

&lt;p&gt;I hope it helps. Thanks for reading.&lt;/p&gt;

</description>
      <category>windows</category>
      <category>wsl</category>
    </item>
  </channel>
</rss>
