C/C++/Rust toolchain for Windows

In Linux, GCC is included in the OS as a system compiler, but in Windows, it is necessary to install a compiler separately from the OS.

If software development itself is your business, you should not be stingy and purchase Visual Studio Pro or subscribe to MSDN subscription. However, it would be a waste to subscribe to MSDN if you just want to write some code to compile the results of an experiment or create a simple business improvement tool for internal use. This is a tip for such people.

MSVC license issue

MSVC (Microsoft Visual C++) is a genuine Microsoft compiler, but the conditions under which it can be used are complicated. The following is an overview as of Visual Studio 2022. For the exact conditions of use, please check the license term by yourself.

  • If you use Visual Studio 2017 Express, there are few restrictions. However, Visual Studio 2017 is the final version, and it is no longer provided.
  • For purely personal use, Visual Studio 2022 Community can be used.
  • If you use Visual Studio 2022 Community in an organization, there are restrictions such as a limit of 5 users, and it is difficult to use it in the workplace with proper license management.
    • It is also difficult to apply the OSS exception clause properly.

Visual Studio 2017 Express for Windows Desktop

If you don't want to sign an MSDN contract, one option is to use Express, which has fewer license restrictions. Download and install Visual Studio Express 2017 for Desktop installer and Build Tools installer. Download and install Visual Studio Express 2017 for Desktop installer and Build Tools installer.

If you want to use Rust together, you can install the x86_64-pc-windows-msvc version of the Rust compiler. (rustup-init will install this automatically)

llvm-mingw toolchain

As an alternative to MSVC, we recommend the LLVM MinGW toolchain.

This toolchain uses the libraries included in MinGW, the Windows version of GCC, and replaces the MinGW compiler with LLVM Clang. It has advantages over MSVC for cross-platform development.

  • Compared to MSVC
    • Free & open source, so it can be used freely.
    • Clang is also available for Linux and Mac, so you can unify compilers if you plan to write code for multiple platforms.
    • It is easy to cross-compile Windows target on a Linux host. This is especially useful for building CI environments.
  • Compared to GCC MinGW
    • LLVM MinGW uses ucrt (Universal C Runtime) which is standard since Windows 10 as C runtime, so there is no problem even if combined with DLLs built with recent MSVC.
    • Features not available in MinGW GCC, such as thread local storage, are also available.
    • The aarch64-pc-windows target, which is not supported by GCC, can also be used.

How to use LLVM MinGW

Just extract the ZIP file and set the PATH environment variable.

  • (1) Get llvm-mingw-*-ucrt-x86_64.zip (AMD, Intel PC) or llvm-mingw-*-ucrt-aarch64.zip (ARM64 PC) from the LLVM MinGW release page.
  • (2) Extract the contents of the ZIP (any location is fine)
    • Assuming you have C:\opt\llvm-mingw\bin\x86_64-w64-mingw32-clang.exe as this example)
  • (3) Set environment variables PATH=C:\opt\llvm-mingw\bin;<other PATHs>

Now you can compile from console as follows.

C:\somewhere> x86_64-w64-mingw32-clang.exe -o hello.exe hello.c
C:\somewhere> hello.exe
Hello, World!

Build tools such as MSBuild included in MSVC are not included in LLVM MinGW, so it is better to use them in combination with CMake and others.

Rust *-pc-windows-gnullvm target

Rust *-pc-windows-gnullvm target has been tier 2 since 1.79.0 and can be easily used with LLVM MinGW.

Using Rust + llvm-mingw on Windows host

The procedure is the following 3 steps.

The major version of LLVM used internally by the Rust compiler and the major version of LLVM MinGW must match (can be checked at rustc -V -v ). Rust 1.73-1.77 => LLVM 17, Rust 1.78-1.81 => LLVM 18 , Rust 1.82- => LLVM 19

  • (1) Get Rust compiler from x86_64-pc-windows-gnu with rustup
    C:\somewhere> rustup-init.exe --default-host x86_64-pc-windows-gnu --target x86_64-pc-windows-gnullvm
    ...
    
    • rustup-init explicitly specify x86_64-pc-windows-gnu as the host toolchain. If you do not specify it, x86_64-pc-windows-msvc will be retrieved.
    • --target x86_64-pc-windows-gnullvm (1) It is convenient to retrieve at the same time.
  • (2) Duplicate libgcc*.a to llvm-mingw's library path
  • C:\Users\<username>\.rustup\toolchains\stable-x86_64-pc-windows-gnu\lib\rustlib\x86_64-pc-windows-gnu\lib\self-contained Duplicate libgcc.a, libgcc_eh.a, libgcc_s.a in C:\opt\llvm-mingw\x86_64-w64-mingw32\lib
  • This is a hack for Rust compiler of x86_64-pc-windows-gnu to link libgcc for GCC. It is necessary for compile of build.rs.
  • (3: Optional) Set default target specification in .cargo/config.toml
    [build]
    target = "x86_64-pc-windows-gnullvm"
    
    .cargo/config.toml If you don't write the setting in [build], specify target at build time and use it.
    C:\somewhere> cargo build --target x86_64-pc-windows-gnullvm
    

x86_64-pc-windows-gnu The build will be cross compiled to another x86_64-pc-windows-gnullvm target on the host of As mentioned above, build.rs is compiled by host compiler (-gnu), but the final .exe is compiled by target (-gnullvm).

Using the Windows .msi installer

I think there are few people who install Rust with .msi, in that case, do as follows.

Cross compile on Linux host

To cross compile .exe for Windows target on a Linux host, do the following

  • (1) Get llvm-mingw-*-ucrt-ubuntu-*-x86_64.tar.xz from the llvm-mingw release page.
  • (2) Extract the contents of the ZIP file (any location is fine)
    • The following is an example of the state in which /opt/llvm-mingw/bin/x86_64-w64-mingw32-clang is located.
  • (3) Set environment variables PATH=/opt/llvm-mingw/bin:<other PATHs>
  • (4) Install x86_64-unknown-linux-gnu host toolchain (normal Rust install procedure)
    $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  • (5) Add x86_64-pc-windows-gnullvm with rustup
     $ rustup target add x86_64-pc-windows-gnullvm
    

Rust cross compile as follows

$ cargo build --target x86_64-pc-windows-gnullvm

This will generate a Windows .exe.

Windows 向けの C/C++/Rust toolchain

Linux では OS に GCC が system compiler として付属しているが、Windows では OS とは別途 compiler を導入する必要がある。

Software 開発自体が業務であれば、ケチらずに Visual Studio Pro 購入もしくは MSDN subscription を契約というのが本筋だろう。 しかし、実験結果を集計するためにちょっと code 書くとか、社内利用の簡単な業務改善 tool を作るといった用途で MSDN 契約をするのはちょっともったいない。 これはそんな人のための tips。

MSVC の license issue

Microsoft の純正 compiler として、MSVC (Microsoft Visual C++) があるが、利用できる条件がややこしい。以下は Visual Studio 2022 時点の概要。厳密な利用条件は各自 license term を確認のこと。

  • Visual Studio 2017 Express であれば利用制限は少ない。Express license で BuildTool も利用許諾されている。しかし、Visual Studio 2017 が最終版で、それ以降の提供はなくなってしまった。
  • 純粋に個人利用であれば Visual Studio 2022 Community を利用可能。
  • 組織で Visual Studio 2022 Community 使う場合は 5名までの制限などあり、正しく license 管理された状態で職場で利用するのは難しい。
    • Open source 例外条項もあるが、OSS として公開するほどでもない小物 tool も書くことは十分想定される。OSS 例外条項をきちんと適用することも意外と難しい。

Visual Studio 2017 Express for Windows Desktop

MSDN 契約をするほどでもない場合の選択として、license 上の利用制限が少ないExpress 使うのが1つの方法。 Visual Studio Express 2017 for Desktop installerBuild Tools installer を download して install する。

Rust を一緒に使う場合は、x86_64-pc-windows-msvc 版の Rust compiler を入れればよい。(rustup-init はこちらを自動で入れてくれる)

llvm-mingw toolchain

MSVC 以外のお薦めとして、LLVM MinGW toolchain がある。

これは GCC の Windows 版である MinGW に含まれる library 類を利用し、MinGW の compiler を GCC から LLVM Clang に置き換えたもの。 Cross platform での開発を前提とすると MSVC よりも利点がある。

  • MSVC と比較して:
    • Free & open source なので、自由に利用可能。
    • Linux, Mac でも Clang は利用できるので、複数の platform 向けの code を書くつもりなら compiler を統一できる。
    • Linux host で Windows target の cross compile を簡単にできる。特に CI 環境構築に便利。
  • GCC MinGW と比較して:
    • LLVM MinGW は C runtime として Windows 10 以降標準の ucrt (Universal C Runtime) を利用するため、最近の MSVC で build された DLL と結合しても問題が出ない。
    • Thread local storage といった MinGW GCC で利用できない機能も利用可能。
    • GCC が support していない aarch64-pc-windows target も利用可能。

LLVM MinGW の使い方

ZIP を展開して、 PATH 環境変数を設定するだけで利用可能。

  • (1) LLVM MinGW の release page から、llvm-mingw-*-ucrt-x86_64.zip (AMD, Intel PC) か llvm-mingw-*-ucrt-aarch64.zip (ARM64 PC) を取得
  • (2) ZIPの内容を展開 (任意の場所でよい)
    • C:\opt\llvm-mingw\bin\x86_64-w64-mingw32-clang.exe がある状態を例とする
  • (3) 環境変数設定 PATH=C:\opt\llvm-mingw\bin;<other PATHs>

以上で利用可能になる。Console から以下のように compile できる。

C:\somewhere> x86_64-w64-mingw32-clang.exe -o hello.exe hello.c
C:\somewhere> .\hello.exe
Hello, world!

MSVC に含まれる MSBuild のような build tool は LLVM MinGW には含まれないので、CMake などと組み合わせて使うのがよい。

Rust *-pc-windows-gnullvm target

Rust も 1.79.0 から *-pc-windows-gnullvm target が tier 2 になり簡単に LLVM MinGW と組み合わせて利用できるようになっている。

Windows host で Rust + llvm-mingw を利用

手順としては、以下の 3 step で利用可能。

Rust compiler が内部で使っている LLVM の major version と LLVM MinGW の major version を合わせておく必要がある(rustc -V -v で確認可能)。Rust 1.73-1.77 => LLVM 17, Rust 1.78-1.81 => LLVM 18, Rust 1.82- => LLVM19

  • (1) x86_64-pc-windows-gnu の Rust compiler を rustup で取得
    C:\somewhere> rustup-init.exe --default-host x86_64-pc-windows-gnu --target x86_64-pc-windows-gnullvm
    ...
    
    • rustup-init の際に、host toolchain として x86_64-pc-windows-gnu を明示的に指定する。指定しないと x86_64-pc-windows-msvc の方を取得してしまう。
    • --target x86_64-pc-windows-gnullvm もまとめて取得しておくと便利
  • (2) libgcc*.a を llvm-mingw の library path に複製
    • C:\Users\<username>\.rustup\toolchains\stable-x86_64-pc-windows-gnu\lib\rustlib\x86_64-pc-windows-gnu\lib\self-contained にある libgcc.a, libgcc_eh.a, libgcc_s.a の3つを C:\opt\llvm-mingw\x86_64-w64-mingw32\lib に複製する
    • これは x86_64-pc-windows-gnu の Rust compiler が GCC 用の libgcc を link しようとするための hack。build.rs の compile に必要。
  • (3: 任意) .cargo/config.toml で default target 指定を設定する
    [build]
    target = "x86_64-pc-windows-gnullvm"
    
    .cargo/config.toml に設定を書かない場合は、build 時に target を指定して利用する。
    C:\somewhere> cargo build --target x86_64-pc-windows-gnullvm
    

x86_64-pc-windows-gnu の host 上で、別の x86_64-pc-windows-gnullvm target 向けに cross compile している状態になる。上記で触れているように、build.rs は host compiler (-gnu) で compile されるが、最終の .exe は target (-gnullvm) で compile される。

Windows .msi installer を使う場合

.msi で Rust を install する人は少ないと思うが、その場合は以下のようにする。

Linux host で cross compile

Linux host で Windows target 用の .exe を cross compile する場合は、以下のようにする。

  • (1) llvm-mingw の release page から、llvm-mingw-*-ucrt-ubuntu-*-x86_64.tar.xz を取得
  • (2) ZIPの内容を展開 (任意の場所でよい)
    • /opt/llvm-mingw/bin/x86_64-w64-mingw32-clang がある状態を例とする
  • (3) 環境変数設定 PATH=/opt/llvm-mingw/bin:<other PATHs>
  • (4) x86_64-unknown-linux-gnu host toolchain を入れる (通常の Rust install 手順)
    $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  • (5) rustup で x86_64-pc-windows-gnullvm を追加
    $ rustup target add x86_64-pc-windows-gnullvm
    

Rust の cross compile は以下のようにする。

$ cargo build --target x86_64-pc-windows-gnullvm

これで Windows 版の .exe が生成される。

Windows でも UTF-8 で code を書きたい

Linux も Mac も UTF-8 なので、Windows target も UTF-8 で C/C++ code を書きたい。 以下の3点を実施すれば、UTF-8 で動作するようになる。

  • C/C++ source code の encoding を UTF-8 にする
  • Win32 API を UTF-8 encoding で呼び出せるように、manifest を追加
  • printf() などが化けないように、console code page を指定

最小限の sample が windows_build_tips/hello_utf8 に入っている。

C/C++ source code を UTF-8 で書く

LLVM MinGW の Clang 利用の場合、そもそも Clang が UTF-8 しか受け付けないので、何も考えずに UTF-8 encoding で source code を書けばよい。

MSVC の場合、default では OS の code page を仮定する。例えば日本語環境で MSVC を走らせると ShiftJIS encoding として扱われる。 Source code を UTF-8 で書くためには以下のどちらかを実施。

  • BOM (byte order mark) をつけた UTF-8-BOM 形式で source code を保存。Visual Studio 2013 あたりから対応されている。
  • Compiler option に '/utf-8' をつける。Visual Studio 2015 から対応されている。

Win32 API を UTF-8 encoding で呼び出す

Windows 10 以降であれば、multi byte 版の Win32 API に UTF-8 文字列を渡すことができるようになっている。 ただし、default では 日本語環境なら ShiftJIS という具合に、過去との互換を優先した encoding で動作するため、assembly manifest を書いて UTF-8 で動作することを明示的に宣言する必要がある。

まず manifest の XML を書き、utf8_manifest.xml のような名前で保存する。BOM つき UTF-8 での保存が必要。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>

続いて、resource file (*.rc) に追記する。24 が manifest 用の resource type 番号。

// Application manifest for UTF-8 code page
1 24 "utf8_manifest.xml"

詳しくは Use UTF-8 code pages in Windows apps などを参照。

Console code page を指定

printf() などで console 表示する場合、console の code page も UTF-8 用の code page 65001 に切り替える必要がある。 最小限は SetConsoleOutputCP() を 1度呼ぶだけだが、行儀よく行うなら終了時に元の code page に戻しておくとよい。

// 最小限
SetConsoleOutputCP(CP_UTF8);

行儀よく行う例:

// Set console code-page as UTF-8
const UINT original_cp = GetConsoleOutputCP();
SetConsoleOutputCP(CP_UTF8);

// Application logic
printf("hello\n");

// Restore console code page on exit
SetConsoleOutputCP(original_cp);
return 0;