Visual Studio+Cygwinでコマンドライン開発環境の構築

Copyright (c) 2017 Mamoru Kaminaga
[mkaminaga](https://github.com/mkaminaga)

# 対象読者
* Microsoft Visual Studio のコンパイラ・リンカを Cygwin から叩きいた方
* C++ Windows プログラミングのコマンドライン開発環境について調べている方

# はじめに
コマンドライン開発には, お気に入りのエディタで編集できる, ビルドの流れに対する理解が深まるなどの利点があります.
この記事では Microsoft Visual Studio Community の最新版である "Microsoft Visual Studio Community 2017" (以下 Visual Studio) と "Cygwin" を導入し, Windows アプリケーションの C++ によるコマンドライン開発環境を構築します. そして, 実際にプロジェクトのビルドを行います.

以下の点についてご了承ください.

* この記事を参考にしたことによって生じたすべての障害・損失・不具合などに関しては, 著作権者である私と私の関係者および私の所属するいかなる団体・組織とも一切の責任を負いません. 各自の責任において参考にして下さい.
* 筆者はプロではありません. 内容は自己流です.
* 環境変数を弄ります.
* Visual Studio はバージョンアップで導入方法が大きく変わる可能性があります.
* (筆者の初投稿記事です)

_環境変数の設定は不要です. 追記をお読みください (2017/04/15)_

# 記事の検証について
この記事の内容は以下のスペックの PC で検証しました.

* OS: Windows 7 Home Premium
* プロセッサ: Intel(R) Core(TM) i5 CPU M 560 @2.67GHz 2.67GHz
* 実装メモリ: 4.00 GB (3.80GB使用可能)
* システムの種類: 64ビットオペレーティングシステム
* ペンとタッチ: 利用不可

# まずはツールのインストールだ!
Visual Studio と Cygwin のインストールを行います.
両者はフリーで利用できます.

## Cygwin の導入

### インストール
[Cygwin](https://cygwin.com/index.html) の導入方法についてはすでに多くの丁寧な記事がネットに上がっているので, 説明はそれらの記事に譲ります.
[Cygwin インストール](http://www.sw.it.aoyama.ac.jp/2011/CP1/cygwin/) などが参考になるかと思います.

### 文字コードの設定
コンパイラのエラー・警告メッセージの文字化け対策として, Cygwin の文字コードを設定します. 画面上で右クリックで `Options` を選択し, リストから` Text` の設定画面を開きます. `Locale` を `ja_JP`, `Charactor set` を `SJIS` にします.

## Visual Studio の導入
Visual Studio の導入には少々注意が必要です.

### インストーラのダウンロード
Microsoft の web ページから Visual Studio のインストーラをダウンロードします.
[Visual Studio Community](https://www.microsoft.com/ja-jp/dev/products/community.aspx)

<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEcnF3a0dzYkVMaXc" width="320px" "ms_web">

### インストーラの起動
インストーラを起動し, 「続行」を押選択します.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmETHF5bjVEcVdmdDA" width="320px" "vs_inst01">

### インストール項目のチェック
以下の項目に追加でチェックを入れておく必要があります.

* 「ワークロード」の「C++ によるデスクトップ開発」
* 「個別のコンポーネント」の「MFCとALTのサポート (x86とx64)」
* 「個別のコンポーネント」の「WIndows 8.1 SDK」
* 「個別のコンポーネント」の「Windows Universal CRT SDK」
* 「個別のコンポーネント」の「標準ライブラリモジュール」

ここがポイントです. 実は検証時に 「個別のコンポーネント」の4箇所にチェックを入ていなかったためコンパイラ・リンカなどがインストールされませんでした. 再度インストーラを起動し, チェックを入れてインストールを「変更」したところ, うまく導入できました. 忘れずにチェックを入れてください.

この設定は以下の記事を参考にしました.
[Visual Studio 2017 Community をインストール](http://blog.kondoumh.com/entry/2017/03/08/062526)

### インストールの開始
右下の方にある「インストール」を押します.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEQU9kOXNJYTlRVFU" width="320px" "vs_inst02">

### インストール完了まで待機
インストールにはまとまった時間が必要です.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmETVRQdXNmMFk3eEU" width="320px" "vs_inst03">

### PC の再起動
インストールが完了すると, 「セットアップに失敗しました」というダイアログが表示されますが, とりあえず「OK」を押してください. そして「再起動」を押すと, PC が再起動されます.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmESWVsY1ZobExWaW8" width="320px" "vs_inst04">

### Visual Studio の起動
PCが再起動したら, すべてのプログラムなどから Visual Studio を起動してください.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmESTNzbEt3NUJXUEU" width="320px" "vs_setup01">

### サインイン
マイクロソフトアカウントがなけば「サインアップ」してください.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEeXdVTEN0QVkyNzg" width="320px" "vs_setup02">
メールアドレスとパスワードを聞かれます.
入力後, 「サインイン」を押してください.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEbUFLNlNMZHlfZUU" width="320px" "vs_setup03">
パスワードを聞かれます.
パスワードを入力後, 「サインイン」を押してください.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEMmpmYVVPeUJxQnc" width="320px" "vs_setup04">

### 起動
「Visual Studio の開始」を押します.
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmENUZ4LXhSdW40Zzg" width="320px" "vs_setup05">

これで Visual Studio の導入も完了です.
ここからが勝負です!

# 環境変数を弄るぞ!

_環境変数の手動設定は不要です. 追記をお読みください (2017/04/15)_

@javacommons さんが `vcvarsall.bat` で指定された環境変数 `LIB` `LIBPATH` `INCLUDE` を自動で追加, 削除するBATファイル `vc2017-env.bat` を公開されました.
[Visual C++ 実行に必要な環境変数をいつでも使えるように予め設定しておく方法 (vcvarsall.bat で設定される変数をユーザー環境変数に自動反映するツールを作りました！【完璧バージョン】)](http://qiita.com/javacommons/items/9c97d68218c9c5831846)
この章の方法で手動で設定するよりも, `vc2017-env.bat` を使わせていただく方が早いです.(2017/04/30)

環境変数は多くのプロセスが参照しており, 誤った変更をするとPCの動作が不安定になる危険性があります. 環境変数を復旧できるよう, 変更履歴を記録することを勧めします.
環境変数自体の扱い方についても多くの丁寧な記事がネットに上がっているので, 説明はそれらの記事に譲ります.
以下のページなどが参考になるかと思います.
[環境変数の設定方法](http://www.k-cube.co.jp/wakaba/server/environ.html)

また, ここに書いていあるパスは検証環境でのものです. バージョンや環境による違いがある可能性があります. ここに書いてあるパスをコピーアンドペーストするのではなく, それに相当するパスを必ず自分で探してください.

## 実行可能ファイル (\*.exe) にパスを通す
ビルドの際に直接必要となる実行可能ファイルは以下の4つです. これらは経験的にビルド過程で必要と判明しているだけで, 同じフォルダにある他のEXEを内部で呼び出しているかもしれません. そのためフォルダごと `PATH` に追加してしまいます.

コンパイラ (cl.exe):
`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\cl.exe`

リンカ (link.exe):
`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\link.exe`

メイク (nmake.exe):
`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\nmake.exe`

リソースコンパイラ (rc.exe):
`C:\Program Files (x86)\Windows Kits\8.1\bin\x86\rc.exe`

また, スタティックリンクライブラリの作成時には以下の実行可能ファイルが必要です.

ライブラリマネージャー (lib.exe):
`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\lib.exe`

重複を省き, 環境変数 `PATH` に以下の2フォルダを追加します.

* `C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86`

* `C:\Program Files (x86)\Windows Kits\8.1\bin\x86`

## ヘッダファイル (\*.h) にパスを通す
Windows プログラミングに必要となるヘッダファイルは以下のフォルダに分かれて存在します. 環境変数 `INCLUDE` にこれらを追加します.
(ここで不足があるとコンパイラエラーに苦しむことになります)

ユーザモードとカーネルモードで使われるヘッダ:
`C:\Program Files (x86)\Windows Kits\8.1\Include\shared`

Windows プログラミングのヘッダ:
`C:\Program Files (x86)\Windows Kits\8.1\Include\um`

C++11 標準ライブラリのヘッダ:
`C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\include`

C 標準ライブラリのヘッダ:
`C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt`

WinRT API のヘッダ:

* `C:\Program Files (x86)\Windows Kits\8.1\Include\winrt`
* `C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\wrl`
* `C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\xaml`

## スタティックリンクライブラリ (\*.lib) にパスを通す
必要なすべてのスタティックリンクライブラリにパスを通す必要があります.
以下のフォルダを環境変数 `LIB` と `LIBPATH` に追加します.
(ここで不足があるとリンカエラーに苦しむことになります)

* `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`
* `C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x86`
* `C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\lib\x86`
* `C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\lib\x86\store`

以上で環境変数の設定は完了です, お疲れ様でした.
PCを再起動してこれらの変更を反映させてください.

# コマンドライン開発, やるぞー!
設定がうまくできているかを確認するために, 簡単な仕事をいくつかこなしてみましょう.

## 単ファイルで "Hello World!"
お約束の "Hello World" です.
以下の一連のコマンドを Cygwin のターミナル上で実行してください.

```
mkdir level1
cd level1/
cygstart notepad main.cc
cl /W4 /D"UNICODE" /D"_UNICODE" /EHsc main.cc
./main.exe
```

notepad とはメモ帳のことです. `cygstart notepad main.cc` ではメモ帳で以下の内容をコピーして保存ください.

``` php:main.cc
#include <wchar.h>
#include <windows.h>
#include <string>
int wmain(int argc, const wchar_t* argv[]) {
  std::wstring hello(L"Hello World!");  // C++ STL compilation and link check.
  wprintf(L"%ls", hello.c_str());  // STL compilation and link check.
  return 1;
}
```

実行結果:
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEUkc3UlZ4MDUwem8" width="320px" "level1">

"Hello World!" ができた方, 環境構築は成功です. おめでとうございます!

もしもコンパイルエラーやビルドエラーが発生してしまった場合は, 環境変数の設定方法が誤っている可能性があります. もう一度よく確認してみてください.

## 複数ファイルで "Hello World!"
実際のプロジェクトでファイルが1つだけしか扱えないのは不便です.
複数のソースファイルをまとめてビルドする方法を確認します.
以下の一連のコマンドを Cygwin のターミナル上で実行してください.

```
mkdir level2
cd level2/
cygstart notepad main.cc
cygstart notepad hello.cc
cl /c /W4 /D"UNICODE" /D"_UNICODE" /EHsc main.cc
cl /c /W4 /D"UNICODE" /D"_UNICODE" /EHsc hello.cc
"/cygdrive/c/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.10.25017/bin/HostX86/x86/link.exe" /SUBSYSTEM:CONSOLE main.obj hello.obj
./main.exe
```

`cygstart notepad main.cc` ではメモ帳で以下の内容をコピーして保存ください.

``` php:main.cc
#include <wchar.h>
#include <windows.h>
void say_hello_world();  // Function decleration
int wmain(int argc, const wchar_t* argv[]) {
  say_hello_world();
  return 1;
}
```

`cygstart notepad hello.cc` ではメモ帳で以下の内容をコピーして保存ください.

``` php:hello.cc
#include <wchar.h>
#include <windows.h>
#include <string>
void say_hello_world() {  // Function definition
  std::wstring hello(L"Hello World!");  // C++ STL compilation and link check.
  wprintf(L"%ls", hello.c_str());  // STL compilation and link check.
}
```

なお, `link.exe` をフルパスで呼び出しているのは Cygwin のパッケージに含まれる GNU の `link.exe` と名前が衝突してしまうためです.

実行結果:
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmETjUyMjZSNkF0RnM" width="320px" "level2">
これで複数ファイルのビルドもできるようになりました!

## makefile による自動化
先の例で複数ファイルをビルドする際, コンパイラ・リンカのコマンドを3回叩きました.
これだと, ファイルが増えるたびにコマンドをたたかなければなりません.
腱鞘炎になりそうです...
一連のビルドコマンドを自動化するために, makefileを作りましょう.
`level2\` に `makefile` という名前のファイルを作成し, 以下の内容をコピーしてください.

``` makefile
CC = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\cl.exe"
LINK = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\link.exe"

TARGET = main.exe
SRC = main.cc hello.cc
OBJS = main.obj hello.obj

CPPFLAGS = /W4 /Zi /O2 /MT /D"UNICODE" /D"_UNICODE" /EHsc
LFLAGS = /SUBSYSTEM:CONSOLE

ALL: $(TARGET)

$(TARGET): $(OBJS)
	$(LINK) $(LFLAGS) /OUT:$(TARGET) $(OBJS)

.cc.obj:
	$(CC) $(CPPFLAGS) /c $<
```

そして `main.obj`, `hello.obj` と `main.exe` を一度削除し, Cygwin のターミナル上で `nmake` と叩いてみてください.

実行結果:
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEVzZCM0hhY3lOZEk" width="320px" "level2_1">
これで複数ファイルのビルドが自動化されました.

## スタティックリンクライブラリの作成と使用
先の例ではソースファイル `hello.cc` から オブジェクトファイル `hello.obj` を作成し, それをオブジェクトファイル `main.obj` とリンクしました.
ここではオブジェクトファイル `hello.obj` からスタティックリンクライブラリ `hello.lib` を作成し, `main.obj` とリンクします.

ソースコードは先ほどの `hello.cc` と `main.cc` を使いまわします.
以下の一連のコマンドをCygwin のターミナル上で実行してください.

```
mkdir level3
cp level2/*.cc level3
cd level3
cl /c /W4 /D"UNICODE" /D"_UNICODE" /EHsc main.cc
cl /c /W4 /D"UNICODE" /D"_UNICODE" /EHsc hello.cc
lib hello.obj
"/cygdrive/c/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.10.25017/bin/HostX86/x86/link.exe" /SUBSYSTEM:CONSOLE main.obj hello.lib
./main.exe
```

実行結果:
<img src="https://drive.google.com/uc?export=view&id=0B_DfuskgFwmEWURheUNQclFuOU0" width="320px" "level3">

"Hello World!" が実行できました!

## 実際にプロジェクトをビルドしてみる
これは整備した開発環境で実際にプロジェクトをビルドするといオマケです.
筆者の公開しているモールス信号生成ソフトウェアをビルドします (ステマです).
モールス信号で "Hello World!" しようというわけです.

以下のリリースページから v_1.1.1 のソースコードをダウンロードします.
[「cwconv」リリースページ](https://github.com/mkaminaga/cwconv/releases)

以下の手順でビルドします.

1. ダウンロードしたアーカイブを解凍します
2. Cygwin で展開先の makefile のあるディレクトリに侵入します.
3. `build` というフォルダを一時ファイル生成用に作成します.
4. `makefile` の `CC={cl.exeのフルパス}` と `LINK={link.exeのフルパス}`を環境に合わせて書き換えます.
5. `nmake` を実行し `cwconv.exe` を作成します.

`cwconv.exe -s Hello world` を実行すると, PC のスピーカーからモールス信号で "Hello World!" が再生できました!

# 最後に
ここで紹介した開発環境は, あくまで最低限のビルドをサポートするものです.
Cygwin で様々なパッケージをインストールすることで, スペシャルな開発環境を育て上げることができます.
つたない記事でしたが, 少しでもお役に立てれば幸いです.

[サンプルプログラム](https://github.com/mkaminaga/Test4Qiita/tree/master/visual_studio_plus_cygwin_environment_for_windows)

# 追記
## 環境変数を用いないベターな方法 (2017/04/15)
コメントで nmake ですべてできるのではないのかというご指摘を頂いたので確認しました.
設定した環境変数 `PATH`, `INCLUDE`, `LIB`, `LIBPATH` を一旦削除します.
「makefile による自動化」で使用した makefile にて, 環境変数 `INCLUDE` で指定していたパスをコンパイラオプションの `/I` で指定し, 環境変数 `LIB`, `LIBPATH` で指定していたパスをリンカ―オプション `/LIBPATH` で指定します.
変更後の makefile は以下のようになります.

``` php:makefile
CC = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\cl.exe"
LINK = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\link.exe"

TARGET = main.exe
SRC = main.cc hello.cc
OBJS = main.obj hello.obj

CPPFLAGS = /W4 /Zi /O2 /MT /D"UNICODE" /D"_UNICODE" /EHsc\
/I"C:\Program Files (x86)\Windows Kits\8.1\Include\shared"\
/I"C:\Program Files (x86)\Windows Kits\8.1\Include\um"\
/I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\include"\
/I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt"\
/I"C:\Program Files (x86)\Windows Kits\8.1\Include\winrt"\
/I"C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\wrl"\
/I"C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\xaml"

LFLAGS = /SUBSYSTEM:CONSOLE\
/LIBPATH:"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86"\
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x86"\
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\lib\x86"\
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\lib\x86\store"

ALL: $(TARGET)

$(TARGET): $(OBJS)
	$(LINK) $(LFLAGS) /OUT:$(TARGET) $(OBJS)

.cc.obj:
	$(CC) $(CPPFLAGS) /c $<
```

この makefile を用いて `hello.cc` と `main.cc` からのビルドに成功しました.
環境変数 を弄らずともビルド環境は容易に構築できました...

nmake を用いずに直打ちでコンパイルする際などのために, `/I` オプションと `/LIBPATH` オプションをデフォルトで追加するようなエイリアスをきっておくと便利かもしれません.

## `vcvarsall.bat` を用いたより良い方法 (2017/04/15)
`vcvarsall.bat` を実行してシェルを立ち上げる以下のバッチファイルを利用すれば, makefile でいちいちパスを追加せずともビルドできる環境を構築することができました.

``` php:cygwin_for_VS.bat
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 8.1
start C:\cygwin64\bin\bash.exe --login
```

このバッチファイルの作成にあたっては以下のサイトを参考にしました.
[「Cygwin Terminal に Visual Studio の環境設定を追加する方法」](https://kwakita.blog/2015/03/14/cygwin-terminal-%E3%81%AE%E5%88%9D%E6%9C%9F%E8%A8%AD%E5%AE%9A%E3%82%92%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA)

このバッチファイルをダブルクリックでターミナルを起動します.
「makefile による自動化」で使用した makefile を使用したところ, 簡単にビルド環境が構築できました.

STL などのプログラム共通で使用するライブラリはこの方法で勝手に参照されるようにしておき, よそから持ってきた一部のプロジェクトでしか使用しないライブラリは makefile で指定するなどの使い分けができるかと思います.

# 参考
[Cygwin](https://cygwin.com/index.html)
[Cygwin インストール](http://www.sw.it.aoyama.ac.jp/2011/CP1/cygwin/)
[Visual Studio 2017 Community をインストール](http://blog.kondoumh.com/entry/2017/03/08/062526)
[環境変数の設定方法](http://www.k-cube.co.jp/wakaba/server/environ.html)
[Windows 8 SDK: Include files in "shared", "um", and "winrt" directories. What's the difference?](https://social.msdn.microsoft.com/Forums/vstudio/en-US/24b9c784-d642-423e-a407-8bbee14e19ab/windows-8-sdk-include-files-in-shared-um-and-winrt-directories-whats-the-difference?forum=vcgeneral)
[コンパイラ オプション](https://msdn.microsoft.com/ja-jp/library/9s7c9wdw.aspx)
[リンカー オプション](https://msdn.microsoft.com/ja-jp/library/y0zzbyt4.aspx)
[LIB の実行](https://msdn.microsoft.com/ja-jp/library/h34w59b3.aspx)
[Cygwin Terminal に Visual Studio の環境設定を追加する方法](https://kwakita.blog/2015/03/14/cygwin-terminal-%E3%81%AE%E5%88%9D%E6%9C%9F%E8%A8%AD%E5%AE%9A%E3%82%92%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA)
[Visual C++ 実行に必要な環境変数をいつでも使えるように予め設定しておく方法 (vcvarsall.bat で設定される変数をユーザー環境変数に自動反映するツールを作りました！【完璧バージョン】)](http://qiita.com/javacommons/items/9c97d68218c9c5831846)

# 変更履歴
2017/04/11 初版投稿
2017/04/11 ↑の数分後, フォーマット整形してあげ直し
2017/04/12 スタティックリンクライブラリ, プロジェクトのビルドについて掲載
2017/04/12 タイトルの誤字修正. VisauStudio -> Visual Studio, その他誤字修正
2017/04/15 makefile ですべてこなす方法を追記, vcvarsall.bat を用いた方法を追加
2017/04/30 @javacommons さんの `vc2017-env.bat` を紹介
2017/05/02 編集リクエストを頂いた誤字の修正