(7/29更新)
背景
msys2上のC++コンパイラでwindowsバイナリを作り、エクスプローラから実行すると以下のように実行できないことがある。
これはエクスプローラの環境変数(PATH)に/mingw64/binが通っていないため起こるが、PATHを通さずとも実行できるようにしたい。
結論
コンパイルオプションに-static -lstdc++ -lgcc -lwinpthread
をつける
試した記録
まず、作成したバイナリがどのようなDLL依存関係になっているか調べた。
使用したコード
#include <windows.h> #include <iostream> int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { std::cerr << "Hello" << std::endl; return 0; }
使用したコンパイラ
実行ファイルのDLL依存関係
$ g++ main.cc -o main $ ldd main
ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ffb96eb0000) KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7ffb94750000) KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7ffb932f0000) msvcrt.dll => /c/Windows/System32/msvcrt.dll (0x7ffb96cc0000) (*) libstdc++-6.dll => /mingw64/bin/libstdc++-6.dll (0x6fc40000) USER32.dll => /c/Windows/System32/USER32.dll (0x7ffb961f0000) win32u.dll => /c/Windows/System32/win32u.dll (0x7ffb93280000) (*) libwinpthread-1.dll => /mingw64/bin/libwinpthread-1.dll (0x64940000) GDI32.dll => /c/Windows/System32/GDI32.dll (0x7ffb94810000) gdi32full.dll => /c/Windows/System32/gdi32full.dll (0x7ffb938b0000) msvcp_win.dll => /c/Windows/System32/msvcp_win.dll (0x7ffb93810000) ucrtbase.dll => /c/Windows/System32/ucrtbase.dll (0x7ffb94160000) (*) libgcc_s_seh-1.dll => /mingw64/bin/libgcc_s_seh-1.dll (0x61440000)
この中で(*)をつけたもの3つが、
- libstdc++-6.dll
- libwinpthread-1.dll
- libgcc_s_seh-1.dll
/mingw64/binにPATHが通っていなければ読み込めないため、この3つを静的リンクすることを目指す。
コンパイルオプションの追加
3つを静的リンクにするために、-static -lstdc++ -lgcc -lwinpthread
オプションをつける。
$ g++ main.cc -o main -static -lstdc++ -lgcc -lwinpthread $ ldd main
ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ffb96eb0000) KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7ffb94750000) KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7ffb932f0000) msvcrt.dll => /c/Windows/System32/msvcrt.dll (0x7ffb96cc0000)
なお、libgcc_s_seh-1.dllとlibstdc++-6.dllに関しては、それぞれ-static-libgcc
、-static-libstdc++
オプションでも静的リンクにすることができる。
一方、libwinpthread-1.dllは-static-lwinpthread
オプションが存在しない上、-Wl,-Bstatic -lwinpthread
オプションをつけても静的リンクにならない。(謎)
また、下記のように-static
だけをつけた場合、
$ g++ main.cc -o main -static
同じ結果が得られるが、自作のライブラリを動的リンクした時に期待の動作をしなかったため、上の3つのライブラリに関しては毎回指定したほうがよいと思われる。
静的リンクと動的リンクを混ぜる
自作のhogeというDLLをリンクさせたい場合、-L./ -Wl, -Bdynamic -lhoge
を追加する。なお、-L./
は./
(カレントディレクトリ)をライブラリ検索パスに追加するという意味である。
$ g++ main.cc -o main -static -lstdc++ -lgcc -lwinpthread -L./ -Wl,-Bdynamic -lhoge $ ldd main
ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7fffd7820000) KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7fffd6930000) KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7fffd3f50000) msvcrt.dll => /c/Windows/System32/msvcrt.dll (0x7fffd6b00000) hoge.dll => /home/siun/pro/wintest/hoge.dll (0x67b00000)
この時注意する点としては、静的リンクを必ず先に書くこと。
下記のように動的リンクを先に書いた場合、静的リンクが正しく行われない。
$ g++ main.cc -o main -L./ -Wl,-Bdynamic -lhoge -static -lstdc++ -lgcc -lwinpthread
また当然ではあるが、このhogeというDLLを作る際にも静的リンクオプションをつける必要がある。
$ g++ hoge.cc -o hoge.dll -static -lstdc++ -lgcc -lwinpthread