Question

Cross-Compiling Rust from Linux to Windows

rustlinuxwindowscross-compiling

Question

I want to compile a very simple Rust program for Windows while developing on Linux.

fn main() {
    println!("Hello, and bye.");
}

I found commands like these:

rustc --target=i686-w64-mingw32-gcc main.rs
rustc --target=i686_pc_windows_gnu -C linker=i686-w64-mingw32-gcc main.rs

However, they do not work. I get an error saying the std crate is missing:

$ rustc --target=i686_pc_windows_gnu -C linker=i686-w64-mingw32-gcc main.rs

main.rs:1:1: 1:1 error: can't find crate for `std`
main.rs:1 fn main() {
          ^
error: aborting due to previous error

Is it possible to compile Rust code on Linux so that it runs on Windows? If so, what needs to be installed or configured correctly?

Short Answer

By the end of this page, you will understand how Rust cross-compilation works, why the std crate error happens, how Rust targets and linkers fit together, and how to build a Windows executable from Linux using the correct target toolchain.

Concept

Rust can compile code for platforms other than the one you are currently using. This is called cross-compilation.

When you compile Rust code for another operating system, Rust needs two major things:

  • A target that tells Rust which platform you want to build for
  • The correct standard library and linker tools for that target

In the question, the error says Rust cannot find the std crate. That usually means:

  • the Windows target has not been installed in Rust, or
  • the compiler is being asked to build for a target that does not have its standard library available

In Rust, std is not automatically available for every platform unless that platform's target support is installed. For example, building on Linux for Linux works out of the box because your default toolchain already includes the Linux standard library. But if you want to build for Windows, you must install the Windows target.

A second piece is the linker. Rust compiles your code, but it still needs a platform-appropriate linker to produce the final executable. For the windows-gnu target, developers commonly use a MinGW cross-linker such as:

i686-w64-mingw32-gcc

So the full setup for cross-compiling from Linux to Windows usually means:

  1. Install the Rust Windows target
  2. Install a Windows-compatible linker
  3. Build using that target

This matters in real programming because teams often build software for multiple operating systems from one CI server or one development machine.

Mental Model

Think of Rust cross-compilation like writing a letter in your home country and sending it to another country.

  • Your Rust source code is the message
  • The target triple is the destination country
  • The standard library for that target is the local language and formatting rules
  • The linker is the local postal system that packages the message correctly

If you only write the message but do not know the destination's rules, the package cannot be prepared correctly. That is why Rust complains when std for the Windows target is missing: it does not have the platform-specific pieces needed to finish the build.

Take Quiz

Syntax and Examples

To cross-compile Rust from Linux to Windows, you typically use a target triple.

Common Windows targets

  • x86_64-pc-windows-gnu → 64-bit Windows using GNU toolchain
  • i686-pc-windows-gnu → 32-bit Windows using GNU toolchain
  • x86_64-pc-windows-msvc → 64-bit Windows using MSVC toolchain

From Linux, the GNU Windows target is usually the practical choice.

Install the target with rustup

rustup target add x86_64-pc-windows-gnu

Or for 32-bit Windows:

rustup target add i686-pc-windows-gnu

Install the linker

On Debian or Ubuntu, you might install MinGW like this:

sudo apt install gcc-mingw-w64-x86-64 gcc-mingw-w64-i686

Compile a single file

rustc --target=x86_64-pc-windows-gnu -C linker=x86_64-w64-mingw32-gcc main.rs

Example program

fn main() {
    println!("Hello, and bye.");
}

If the target and linker are installed correctly, this produces a Windows executable such as:

main.exe

Using Cargo instead of rustc

In real Rust projects, you will usually use Cargo:

cargo build --target x86_64-pc-windows-gnu

You can also configure the linker in .cargo/config.toml:

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"

Then build normally:

cargo build --target x86_64-pc-windows-gnu

Cargo is preferred because it manages dependencies, profiles, and project structure much better than calling rustc directly.

Step by Step Execution

Consider this file:

fn main() {
    println!("Hello, and bye.");
}

And this command:

rustc --target=x86_64-pc-windows-gnu -C linker=x86_64-w64-mingw32-gcc main.rs

Here is what happens step by step:

  1. rustc reads main.rs
  2. It sees that the program uses println!, which depends on Rust's standard library
  3. Because you passed --target=x86_64-pc-windows-gnu, Rust tries to build for 64-bit Windows GNU
  4. Rust looks for the std crate compiled for x86_64-pc-windows-gnu
  5. If that target has not been installed with rustup, compilation fails with can't find crate for 'std'
  6. If the target exists, Rust compiles your code into object files for Windows
  7. Rust then calls the linker you provided: x86_64-w64-mingw32-gcc
  8. The linker creates the final Windows executable
  9. The result is a .exe file that can run on Windows

Why the original command failed

The main issue is that passing --target alone is not enough. Rust also needs the target's standard library installed.

For example:

rustc --target=i686-pc-windows-gnu -C linker=i686-w64-mingw32-gcc main.rs

This can still fail if you did not run:

rustup target add i686-pc-windows-gnu

So the missing piece is usually not the source code, but the target support package.

Real World Use Cases

Cross-compiling Rust is useful in many real situations:

  • CI/CD pipelines: Build Linux, Windows, and macOS artifacts from automated build servers
  • Open-source releases: Publish .exe files for Windows users even if maintainers work on Linux
  • Embedded or constrained environments: Build for a platform you are not actively running
  • CLI tools: Ship one command-line app to users on multiple operating systems
  • Internal tooling: Generate Windows utilities from a Linux-based engineering environment

Example scenarios

  • A team maintains a Rust CLI on Ubuntu but wants GitHub Releases to include tool.exe
  • A server-side Linux build machine creates Windows binaries for QA testers
  • A developer writes a small Rust utility on Linux and sends the compiled .exe to Windows coworkers
Take Quiz

Real Codebase Usage

In real projects, developers usually do not invoke rustc manually for cross-platform builds. Instead, they use Cargo, configuration files, and repeatable build scripts.

Common patterns

1. Cargo target builds

cargo build --release --target x86_64-pc-windows-gnu

This places the result in a target-specific folder such as:

target/x86_64-pc-windows-gnu/release/

2. Linker configuration in project config

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"

This avoids repeating linker flags every time.

3. Separate targets for 32-bit and 64-bit

Teams often choose one of these depending on deployment needs:

  • i686-pc-windows-gnu for older 32-bit systems
  • x86_64-pc-windows-gnu for modern 64-bit Windows systems

4. Release builds for distribution

cargo build --release --target x86_64-pc-windows-gnu

Release mode creates optimized binaries suitable for shipping.

5. Validation in CI

Projects often test that all expected targets still build:

cargo check --target x86_64-pc-windows-gnu
cargo build --release --target x86_64-pc-windows-gnu

6. Guarding platform-specific code

If a codebase has OS-specific logic, developers often use conditional compilation:

#[cfg(target_os = "windows")]
fn platform_name() -> &'static str {
    "Windows"
}

#[cfg(target_os = "linux")]
fn platform_name() -> &'static str {
    "Linux"
}

This is especially important when building the same project for multiple operating systems.

Common Mistakes

Here are common beginner mistakes when cross-compiling Rust.

1. Using the wrong target name

Broken:

rustc --target=i686_pc_windows_gnu main.rs

Rust target triples use hyphens, not underscores:

Correct:

rustc --target=i686-pc-windows-gnu main.rs

2. Forgetting to install the target

Broken idea: assuming --target automatically downloads support files.

Correct setup:

rustup target add i686-pc-windows-gnu

Without this, Rust often fails with:

can't find crate for `std`

3. Confusing the target with the linker

Broken:

rustc --target=i686-w64-mingw32-gcc main.rs

i686-w64-mingw32-gcc is a linker executable, not a Rust target triple.

Correct:

rustc --target=i686-pc-windows-gnu -C linker=i686-w64-mingw32-gcc main.rs

4. Not installing MinGW cross tools

Even if Rust has the target installed, linking can still fail if the Windows GNU linker is missing.

Install it through your package manager.

5. Mixing 32-bit and 64-bit tools

If you use:

--target=i686-pc-windows-gnu

then your linker should match that architecture, such as:

i686-w64-mingw32-gcc

For 64-bit:

--target=x86_64-pc-windows-gnu

use:

x86_64-w64-mingw32-gcc

6. Using rustc directly for larger projects

This works for tiny examples, but most real projects should use Cargo because it handles dependencies and configuration more reliably.

Comparisons

ConceptWhat it isExampleWhen to use
Rust target tripleThe platform Rust should compile forx86_64-pc-windows-gnuAlways when cross-compiling
LinkerExternal tool that produces the final executablex86_64-w64-mingw32-gccNeeded to finish the build
Native compilationBuild for your current OSLinux to LinuxDefault case
Cross-compilationBuild for a different OS or CPULinux to WindowsMulti-platform releases
rustcLow-level compiler commandrustc main.rsSmall experiments
CargoRust build tool and package managercargo build --target ...Real projects

GNU target vs MSVC target

Windows targetToolchain stylePractical from Linux?Notes
x86_64-pc-windows-gnuGNU / MinGWYesCommon choice on Linux
x86_64-pc-windows-msvcMicrosoft Visual C++Usually noNormally built on Windows with MSVC tools

32-bit vs 64-bit

TargetArchitectureTypical use
i686-pc-windows-gnu32-bitOlder Windows support
x86_64-pc-windows-gnu64-bitModern Windows systems
Take Quiz

Cheat Sheet

Quick setup

64-bit Windows target

rustup target add x86_64-pc-windows-gnu
sudo apt install gcc-mingw-w64-x86-64
cargo build --target x86_64-pc-windows-gnu

32-bit Windows target

rustup target add i686-pc-windows-gnu
sudo apt install gcc-mingw-w64-i686
cargo build --target i686-pc-windows-gnu

Single-file compilation

rustc --target=x86_64-pc-windows-gnu -C linker=x86_64-w64-mingw32-gcc main.rs

Important rules

  • --target must be a Rust target triple, not a linker name
  • The target's standard library must be installed with rustup target add ...
  • The linker must match the architecture
  • Prefer Cargo for anything beyond tiny examples
  • On Linux, windows-gnu is usually easier than windows-msvc

Common target triples

x86_64-pc-windows-gnu
i686-pc-windows-gnu

Common linker names

x86_64-w64-mingw32-gcc
i686-w64-mingw32-gcc

Common error meaning

can't find crate for `std`

Usually means the target was not installed.

FAQ

Can I compile Rust for Windows while using Linux?

Yes. This is called cross-compilation. You need the correct Rust target and a Windows-compatible linker.

Why does Rust say it cannot find the std crate?

Usually because the target standard library is not installed. Run rustup target add <target> for the Windows target you want.

What is the correct Windows target for Linux users?

Most Linux users choose x86_64-pc-windows-gnu for 64-bit Windows or i686-pc-windows-gnu for 32-bit Windows.

What is the difference between target and linker?

The target tells Rust what platform to build for. The linker is the external tool that creates the final executable for that platform.

Should I use rustc or Cargo for cross-compiling?

Use Cargo for real projects. It is easier to configure, repeat, and maintain.

Can I build the MSVC Windows target from Linux?

In most normal setups, Linux users target windows-gnu instead. MSVC targets usually depend on Microsoft's toolchain.

Why does architecture matter when choosing the linker?

Because 32-bit targets need 32-bit linkers, and 64-bit targets need 64-bit linkers. Mixing them causes build failures.

Take Quiz

Mini Project

Description

Create a tiny Rust command-line program on Linux and build it into a Windows executable. This project demonstrates the full cross-compilation workflow: installing a target, configuring the linker, and producing a .exe file that can run on Windows.

Goal

Build a working Windows .exe from Linux using Cargo and the x86_64-pc-windows-gnu target.

Requirements

  • Create a new Rust binary project using Cargo.
  • Print a simple message that confirms the program is running.
  • Install the Windows GNU Rust target.
  • Configure Cargo to use the correct MinGW linker.
  • Build the project for 64-bit Windows in release mode.
Take Quiz

Keep learning

Related questions

View more