Vidual Studio C++のコマンドプロンプトでコンパイル

#0.はじめに
　半分自分のメモ用ですが、初心者から上級者まで役立つ内容にしたつもりです。上級者というのはあれです。規格書読み漁っているような人の事ではなく、プログラムをデバッグできる程度の人です。それでも十分上級者だと思います。最近やり始めたばかりのことなので間違ったことも書いているかもしれません。そういった場合は指摘していただければ幸いです。
　この記事では、Vidual Studio 2017をインストールすると勝手にインストールされるコマンドプロンプトを使ってC++コードをコンパイル、およびその他諸々をすることを目的とします。統合開発環境のありがたみをガン無視して、こんな古典的な手法でコンパイルすることに何の意味があるんだ、と思う方もいるかもしれませんが、、、はい、僕もその通りだと思います。ただ、コンパイル自体に詳しくなりたい人とかCUI大好きな人にはおすすめ。
　OS環境はWindows10です。
#1.コンパイル基礎編
##a.ヘルプメニュー

~~~
C:[filepath]>cl /HELP
C:[filepath]>cl /?
~~~

　上の二つのうちどちらを入力しても良い。ヘルプを見れる。この記事より優秀。

##b.通常のコンパイル

~~~
C:[filepath]>cl test.cpp
~~~

　これをやると.objファイルと.exeファイルが生成される。ファイル名は拡張子の前が.cppのものと同じになる。つまりこの例だとtest.obj及びtest.exeができる。

##c.リンク無しでコンパイル

~~~
C:[filepath]>cl test.cpp /c
C:[filepath]>cl /c test.cpp
~~~

　上二つは同義。Windowsなのでオプションは'/'をつける。Linuxにおける'-'にあたるもの。/cがリンク無しのオプション。.objファイルが生成される。エントリポイントとなるmain関数が無くても良い。ヘッダの実装をコンパイルする時などに使う。

##d.リンク

~~~
C:[filepath]>link test.obj hoge.obj
C:[filepath]>link test.obj hoge1.obj hoge2.obj
~~~

　.objファイルをリンクして一つの.exeファイルを吐く。通常エントリポイントのmain関数があるものを先に書く。そうでなくてもリンクできるがファイル名は最初の.objファイルと同じになる。

##e.リンク付きコンパイル

~~~
C:[filepath]>cl test.cpp hoge.obj
C:[filepath]>cl test.cpp hoge1.obj hoge2.obj
~~~

　.objファイルを引数に加えると勝手にリンクしてコンパイルしてくれる。分割コンパイル時は必須の手法。.exeファイルを生成する。その過程で.objファイルも産まれる。

##f.最適化

~~~
C:[filepath]>cl test.cpp /O1
C:[filepath]>cl test.cpp /O2
C:[filepath]>cl test.cpp /Ox
~~~

　まあ一度は見たことがあるであろう最適化オプションである。Visual Studioでは/O1がプログラムサイズ最小化、/O2が実行速度最大化であり、/Oxは/O2と少し異なった手法で実行速度最大化するらしい。両方試すといいかもしれない。

#2.コンパイル応用編

##a.C++バージョン指定

~~~
C:[filepath]>cl test.cpp /std:C++14
C:[filepath]>cl test.cpp /std:C++17
C:[filepath]>cl test.cpp /std:C++latest
~~~

　C++の言語バージョン指定を行える。/stdのあとにオプション引数を加える。C++latestはC++最新バージョン。正確にはIOS標準の最終草案。これを使うと3年毎にオプションを変えなくて良くなるわけだが、Vidual Studioをアップデートするとコンパイルエラーやバグの元になる可能性もある。デフォルトでは/std:C++14らしい。最初バージョン指定を知らずに、constexpr ifを含んだソースファイルが何故かコンパイルできないなーって思ってたらC++14の指定になっていた。/std:c++20もじきに追加される。

##b.例外処理機構の指定

~~~
C:[filepath]>cl test.cpp /EHsc
C:[filepath]>cl test.cpp /EHa
C:[filepath]>cl test.cpp /EHr
~~~

　例外処理モデルを指定する。オプション引数にs、c、a、rを取れる。sはC++同期的例外のみcatch構文で捕捉、処理して、aは構造化非同期的例外とC++同期的例外をcatch構文で捕捉する。cは基本sと同時に使い、externで宣言された関数が例外を吐かないことをコンパイラに伝え、最適化のヒントとする。sを付けた時にcを入れないと、externで宣言された関数は例外を吐きうるとコンパいrは判断する。rはnoexceptによる最適化を無効化し、noexcept付き関数が例外を吐かないか監視する。
　同時に何個でもオプション引数を取れるが、sとaは基本共存させない（コンパイラが警告を発し、後に書いた引数が優先される）。また、/EHcaと/EHaは同義。

##c.我らがconstexprの制御

~~~
C:[filepath]>cl test.cpp /constexpr:depth256
C:[filepath]>cl test.cpp /constexpr:backtrace12
C:[filepath]>cl test.cpp /constexpr:steps50000
~~~

　みんなが愛してやまないconstexprだが、CPUはその愛の重さゆえ悲鳴を上げるので、再帰の深さを制限しないといつまでもコンパイルが終わらなくなってCPUが熱にうなされ帰らぬ人になってしまう。いや、その前に強制シャットダウンやらなんやらが働くだろうが。
　depthは再帰深さ制限で後ろに制限数を書く。デフォルトは512。コンパイル時に再帰が深さ制限を上回ったとき、再帰関数の途中から関数を実行してくれるらしい。その再帰の最後から何まわし目からスタートするかを決めるのがbacktraceでデフォルトは10。constexprの規制緩和がなされたC++14の時代には両者とももうあまり使われないだろう。その代わり？として出てくるのがstepsでありconstexpr関数における実行ステップ数を制限する。デフォルトは100000。

#3.様々なファイル出力
##a.実行形式ファイルの名前変更

~~~
C:[filename]>cl test.cpp /FeEXE.exe
~~~

　出力される実行形式ファイルが/Feの直後の名前、今回の例だとEXE.exeに変更される。ファイル名ではなくファイルパスを入れてもいい。

##b.オブジェクトファイルの名前変更

~~~
C:[filename]>cl hoge.cpp /c /FoOBJ.obj
~~~

　出力されるオブジェクトファイルが/Foの直後の名前、今回の例だとOBJ.objに変更される。ファイル名ではなくファイルパスを入れてもいい。

##c.動的リンクライブラリ

~~~
C:[filename]>cl hoge.cpp /LD
C:[filename]>cl hoge.cpp /LDd
C:[filename]>cl hoge.cpp hoge2.obj /LD
C:[filename]>link hoge.obj /DLL
C:[filename]>link hoge1.obj hoge2.obj /DLL
~~~

　動的リンクライブラリ.dllファイルを生成する。/LDdはデバッグ版の.dllファイルを産み落とす。.exeファイル同様に.objファイルを引き数に一個または複数個追加しても平気。
　また、リンカでも.dllファイルをビルドできる。これも複数のファイルを引き数にとっても平気。コンパイルと違い、この場合は全て.objファイルなので注意。

##d.魔の領域アセンブリファイル

~~~
C:[filename]>cl test.cpp /FAs
C:[filename]>cl test.cpp /FAc
C:[filename]>cl test.cpp /FAs /FaASM.asm
C:[filename]>cl test.cpp /FAc /FaCOD.cod
~~~

　アセンブリファイルをファイル出力する。/FAsは通常の.asmファイル、/FAcはなんと機械語翻訳を追加した.codファイルを吐く。当然.exeファイルも同時に出てくる。アセンブリファイルに用のある人なんてほとんどいないに等しいであろうが、プログラマとして一度は見ておかざるを得まい。いや、そんなことは無いか。
　/Faによって出力ファイル名を変更できる。今回の例だとASM.asmやCOD.codが吐き出される。

#4参考文献
[カテゴリ別のコンパイラオプション｜Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/build/reference/compiler-options-listed-by-category?view=vs-2017)

　


　おしまい