Windows 上で Linux を動かすのが Windows Subsystem for Linux (WSL) ですが、その上で、Linux 上で Windows 用の実行バイナリを生成できる MinGW-w64 を使ってみました。
よくある記事だと「WSL と MinGW-w64 のどちらを使うか」のような内容が書かれていますが、本記事では「WSL 上で MinGW-w64 を使用」します。
1. WSL で MinGW-w64 をインストール
例えば Ubuntu であれば apt install
でインストールできます。
環境に応じたパッケージ管理システムを使用してください。
ここでは簡単のために 64bit 版の g++
とその依存パッケージのみインストールします (状況に応じて必要なパッケージをインストールしてください) 。
x86-64
が 64bit 用で i686
が 32bit 用です。
sudo apt install g++-mingw-w64-x86-64
2. 依存ライブラリを静的リンクする (状況に応じて)
実行ファイルを複数含むようなソフトウェアを公開する場合には、DLL を付属した方が合計の容量を小さくできると思いますが、単一の実行ファイルの場合は静的リンクした方が単純にファイル数を少なくできます。
まず、libgcc
は (おそらく) 絶対必要になります。また、状況に応じて他のライブラリも必要になります。
x86_64-w64-mingw32-g++ -o main.exe main.cpp
x86_64-w64-mingw32-objdump -p main.exe | grep 'DLL Name'
DLL Name: KERNEL32.dll
DLL Name: msvcrt.dll
DLL Name: libstdc++-6.dll
(※ libgcc
はこの方法では確認できない?)
KERNEL32.dll
と msvcrt.dll
は Windows に標準で含まれる DLL のため、ここでは libgcc
と libstdc++
を静的リンクすることにします。
x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++ -o main.exe main.cpp
これで、DLL を付属しなくてもエラーが出ずに実行できる Windows 用の実行バイナリを生成できます。
3. おまけ: WSL 上でも Windows 用の実行バイナリを実行できる
拡張子 .exe
を付けることで、WSL 上でも exe ファイルを実行できます。
自身で作成したアプリケーションに限らず、Windows 用の CUI アプリケーションを実行して、そこから Linux のコマンドで grep
するといった使い方ができ、便利です。
CUI アプリケーションを作成する場合は、そのまま WSL 上で動作確認を行うことができます。
※文字コードが合わず文字化けする場合は nkf
コマンド等で対処してください。
※システムの情報にアクセスする必要があるなど、高度なことをする場合には WSL 上で動作しないことがあります。
4. その他注意点
4.1. ソースコードの文字コードが Shift_JIS (CP932) 以外の場合
ソースコードの文字コードが CP932 以外の場合、実行時に、GUI のテキスト等で日本語等が文字化けするので、コマンドラインオプションで文字コードを指定します。
x86_64-w64-mingw32-g++ -finput-charset=UTF-8 -fexec-charset=CP932 \
-static-libgcc -static-libstdc++ -o main.exe main.cpp
g++
では -finput-charset=UTF-8 -fexec-charset=CP932
のように指定できます。
4.2. MinGW-w64 で wmain
や wWinMain
を使いたい場合
MinGW-w64 では、g++
のコマンドライン引数で -municode
を指定することで、wmain
や wWinMain
を使用することができます。
※無印の MinGW では (おそらく) -municode
を使用できないので注意。
また、マルイバイト文字列のコマンドライン引数は、GetCommandLineW()
関数と CommandLineToArgvW()
関数を使って便利に取得することができます。
4.3. MinGW-w64 の std::wcout
で日本語等の文字列が出力されない問題
#include <fcntl.h>
して _setmode(fileno(stdout), _O_U8TEXT);
すると出力できます (コンパイルオプションにより異なる?) 。
MinGW-w64 では std::basic_ios::imbue()
や std::locale()
で対処できないようです…。
#include <iostream>
#include <fcntl.h>
int wmain() {
_setmode(fileno(stdout), _O_U8TEXT);
std::wcout << L"にゃ" << std::endl;
return 0;
}