C++開発環境構築(MSYS2) - 002

- [001 - g++でコンパイルできる環境作成](https://qiita.com/arta-crypt/items/7717faf51ad581a8af98) 
- **[002 - Windows上で実行可能にする](https://qiita.com/arta-crypt/items/5fdd492161392060e1ad) <--- 今回の内容**

##  C++開発環境構築(MSYS2) - 002

Windows上で実行可能なexeファイルを作成可能にする。



[前回](https://qiita.com/arta-crypt/items/7717faf51ad581a8af98)はMSYS2上で実行可能なexeファイルを作成した。

https://qiita.com/arta-crypt/items/7717faf51ad581a8af98

今回はwindows上で実行可能なファイルを作成するのが目的です。

前回作成したプログラムを実行すると下記のようなエラーが発生しました。

![error_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/43273cbf-adb7-4e4f-00f4-7569dfce1d4d.png)

今回はこのエラーを回避する方法を調べました。



## DLLの依存関係を調べる

まず、DLLの依存関係を調べます。

[siunのメモ](https://siuncyclone.hatenablog.com/entry/2018/07/21/194629)を参考にしました。

https://siuncyclone.hatenablog.com/entry/2018/07/21/194629

lld(list dynamic dependecies)というコマンドを使用して、ダイナミックライブラリの依存関係を調べます。

```
$ ldd ./hello.exe
        ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffcd27f0000)
        KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffcd0ab0000)
        KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ffcd03c0000)
        msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ffcd21c0000)
        libstdc++-6.dll => /mingw64/bin/libstdc++-6.dll (0x7ffc75520000)
        libwinpthread-1.dll => /mingw64/bin/libwinpthread-1.dll (0x7ffcb2620000)
        libgcc_s_seh-1.dll => /mingw64/bin/libgcc_s_seh-1.dll (0x7ffca45b0000)
```

このうち以下3種（mingw64/bin/以下にあるDLL）は、windows上でPATHが通っていないため、エクスプローラーから直接起動した時にエラーの原因になります。

- libstdc++-6.dll

- libwinpthread-1.dll

- libgcc_s_seh-1.dll



## 静的にリンクする

前項で調べたエラーの原因となるDLLを静的にリンクします。

windows側でPATHを通すという手もあるのですが、それだと既に同名のDLLを別のPATHで通していた場合におかしくなるそうです。
また、DLLをexeと同じディレクトリに置くという手もあります。[^1]

windowsとmsys2の環境を分けておきたいという好みの問題もあるため、今回は静的にリンクするという手段をとります。

静的リンクには`-static`と`-l`のオプションを使用します。


| 処理|オプション|
| :---------------------------------- | :----------------- |
| 静的にリンクする C++ ライブラリを指定する。| `-staticlib=`llst |
| リンカーのライブラリ検索リストに `lib`*lib*`.a` または `lib`*lib*`.so` を追加する。 | `-l`lib           |

[C++ コンパイラオプション](https://docs.oracle.com/cd/E19957-01/806-4837/Rev.html)を参考にコンパイラオプションを調べました。

https://docs.oracle.com/cd/E19957-01/806-4837/Rev.html

上記サイトの`-l`オプションの説明がサッパリわからなかったため[gcc/g++の"-l"オプションの意味](https://www.koikikukan.com/archives/2018/03/06-000300.php)を参考にしました。

https://www.koikikukan.com/archives/2018/03/06-000300.php

追加するオプションは以下のようになります。

```
-static -lgcc -lstdc++ -lwinpthread
```



*Sample source : hello.cpp*

```c++
#include <iostream>

int main()
{
        std::cout << "hello";
}
```



上記コードをコンパイルします。

```
$ g++ -o hello.exe ./hello.cpp -static -lgcc -lstdc++ -lwinpthread
```



## 結果を確認する

DLLの依存関係を調べます。

```
$ ldd ./hello.exe
        ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffcd27f0000)
        KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffcd0ab0000)
        KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ffcd03c0000)
        msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ffcd21c0000)
```

今回はDLLの問題が解決できていそうです。実際にwindows上で実行してみます。

![console_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/94b416e7-f7d8-f16b-8abd-15c854468f1d.png)

コマンドプロンプト上で実行できました。`hello`と表示されています。



## まとめ

- msys2で作成したプログラムはwindows上で実行できないことがある。
- 少なくとも今回はDLLが問題となっていた。
- 解決方法は３つ。(1)windows上でPATHを通す。(2)DLLをexeと同じディレクトリに置く[^1]。(3)コンパイル時に静的リンクする。

[^1]: [@yumetodo様](https://qiita.com/yumetodo)のコメントを受けて追記