OpenSiv3Dプロジェクトにおいて、VSCode(Windows)だけで補完&ビルドを完結させる

**このページ上での記法についての注意**

```json:記法
"ファイル生成時にすでに値が設定されているとき変更しない": {
 "ex" : "%{default}"
}
"入力するべき文字列Aは環境や設定によって変化する": {
 "ex"   : ["writed","replaced"],
 "ex.1" : ["&{A}","something"],
 "ex.2" : ["I like &{A}.", "I like something."]
}
"一部VSCode側などで置換されるものもある。":{
 "ex": ["${workspaceFolder}","${workspaceFolderBasename}","${SIV3D_0_4_2}"]
}
```

# 前提(あると望ましい)
- 環境がWindowsであること。また、それがOpenSiv3Dの動作環境を満たすこと。

>Macでは既に専用エディタ以外で開発する方法が示されている。(なお、今回はこちらの方法を参考にしている。)
 Xcodeを開かずにOpenSiv3Dを使いたい
[https://qiita.com/makia/items/3188b08670f178104f6d]

>LinuxでもVimにて開発するための手法が明示されている。
 OpenSiv3D Linux版をVimで
[https://qiita.com/higashi000/items/fcdf0af788e54acdc179]

- Visual StudioおよびVisual Studio Codeがインストールされていること。
- Visual Studio Codeの拡張機能`C/C++`が導入されていること(IntelliSenseに必要)。

- (`C/C++`のIntelliSenseの基本的な使い方が分かっていること。)
- (Visual Studio Code内の概念「タスク」の基本的な使い方をわかっていること。)
- (batファイルの使用方法、作成方法を理解していること。)

# 実行環境
- Windows 10 Home 1903
- Visual Studio 2019 16.4.2
- OpenSiv3D 0.4.2

# やることを端的に換言すると
- 任意の場所に**Visual Studio上で**OpenSiv3Dテンプレートからプロジェクトを生成する。
- C/C++ IntelliSenseで適切に設定する。
- ビルドタスクを設定する。

OpenSiv3Dの製作者である@Reputlessさんが今回のものを簡潔にまとめています。必要なファイルや記述内容が一通りまとまっています。
https://gist.github.com/Reputeless/9cad2d052c6602d442d37d88c820a13a#file-vsdevcmd-debug-bat-L4

## 任意の場所にVisual Studio上でOpenSiv3Dテンプレートからプロジェクトを生成する。
**Visual Studio上で**OpenSiv3Dテンプレートを選択しプロジェクトを自分の好きなフォルダに生成する。[^1]



## C/C++のIntelliSenseを適切に設定する。
この作業で、VSCode上でOpenSiv3Dの補完機能を効かすことができる。

この生成したプロジェクトのフォルダにある、プロジェクト名の(拡張子がvcxprojであるファイルを含む)フォルダをワークスペースとしてVSCodeで開く。

コマンドパレット(Ctrl+Shift+P)にて`C/C++ Edit Configurations (JSON)`を実行する。

すると、ワークスペースでは`.vscode\c_cpp_properties.json`という「C/C++のIntelliSense」に対する設定用のjsonが生成される。
ここで、`configurations`オブジェクトに対して以下のように設定する。
>`%{default}`
ここにある値はファイル生成時のデフォルトのままで(もともとなければそのままで)
`&{VERSION}`
OpenSiv3Dのバージョン番号のピリオド(.)をアンダーバーに置換したもの。
今回の場合であれば、0.4.2であるから0_4_2となる。

```json:c_cpp_properties.json
 {
	"configurations": [
          {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**",
                "${SIV3D_&{VERSION}}/include",
                "${SIV3D_&{VERSION}}/include/ThirdParty"
            ],
            "defines": [
                "${default}"
            ],
            "windowsSdkVersion": %{default},
            "compilerPath": %{default},
            "cStandard": %{default},
            "cppStandard": %{default},
            "intelliSenseMode": "msvc-x64"
         }
  ],
    "version": %{default}
 }
```
```json:(例示)c_cpp_properties.json
 {
	"configurations": [
          {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**",
                "${SIV3D_0_4_2}/include",
                "${SIV3D_0_4_2}/include/ThirdParty"
            ],
            "defines": [
                "${default}"
            ],
            "windowsSdkVersion": "10.0.18362.0",
            "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "msvc-x64"
         }
  ],
   "version": 4
 }
```
<details>
<summary>**IncludePathのプロパティについて**</summary>
<div>
ここは、Visual Studioで生成したOpenSiv3Dプロジェクトのプロパティ>VC++ ディレクトリ>インクルードディレクトリを覗いてもらえば分かると思う。

```VC++ディレクトリ/インクルードディレクトリ
 $(SIV3D_&{VERSION})\include
 $(SIV3D_&{VERSION})\include\ThirdParty
```
と追加でインクルードするディレクトリが定義されている。
`”${SIV3D_&{VERSION}}/include"`だけを指定するといくつかのヘッダーファイルが発見できないと怒られる(一敗)

ちなみに、`SIV3D_&{VERSION}`は環境変数である。これはOpenSiv3Dのインストール時に定義されている。これを使えば短く書くことが出来る。
> 引用
[https://twitter.com/Osmium_1008/status/1218811718568005632?s=20]


</div>
</details>

<details>
<summary>**せっかくVSCodeでやるんだからVisual Studioから完全に独立してgccコンパイラでなんとかできないの？**</summary>
<div>
**出来ない**。

C/C++ IntelliSenseにて使用するコンパイラをgccにしてコーディングしてみよう。
すると殆どのヘッダーファイルに含まれる関数は補完機能やコードの静的解析に認識されているのだが、一部**直接システムに関わってくるようなヘッダーファイルなど**、つまりSystem.hppやMouse.hppなどが認識されていないことが分かる。(エラーに叱られるから)

一番肝心なSystem::Update()すら補完機能や静的解析に反応されず、コーディング中にエラーとして報告される始末。一応ヘッダーファイルを直接VSCodeで開くと認識されるようになるのだが、毎回このように開くのは面倒くさくてやってられない。

また、コンパイル,ビルドするので、各ファイルの関係を記述するためにMakefileなどを打ち立てなければならない。DxLibなどでは必要なライブラリやヘッダを指定すればよかった。
しかし、OpenSiv3Dは違い、インクルードディレクトリ,ライブラリ走査対象を指定してやるだけではうまくいかない。Resourcesとして大量の画像やアイコンやengineが含まれている。これらのものを読み込むために依存関係を書かなくてはならないのだ。(しかもResourcesを毎回コピーしてくる必要がある。)(しかしこれはまだ簡単に解決できそう)

出来ないと断言したのは決してコーディング環境を立てるのが面倒くさいということだけが理由ではない。
**gccではどう頑張ってもOpenSiv3D(Windows)プロジェクトをビルドできないのだ。**
Platform.hppに含まれるマクロを見てもらえればわかるのだが、「コンパイラがMSVCであり、2019以上のバージョン」でなければエラーが発生して落ちるようになっている。
こうされているのは、一部のOpenSiv3Dの実装がVisual Studio SDKに依存しているためだ。つまり**Windowsにおいては**Visual Studioと関わるものでなければビルドできないことを意味する。完全にVisual Studioから独立することはできない。
gccでの補完機能や静的解析がうまく機能しなかったのはそのヘッダがVisual Studio SDKに依存している部分だからなのだろうか…？
>引用
[https://twitter.com/Reputeless/status/1208297249039503363]
[https://twitter.com/Reputeless/status/1110176034731655168]

</div>
</details>

## プロジェクトをDebugビルドする。
バッチファイル`vsdevcmd-debug.bat`をワークスペース内のパスの指定しやすい場所に作成する。
ここではワークスペース内で一番上層の場所に配置した。
`vsdevcmd-debug.bat`はこのようにする。

>`&{PathToVcvars64.bat}`
「x64 Native Tools Command Prompt for VS 2019」ショートカットのプロパティを開き、そこのリンク先を確認すると
	`%comspec% /k &{PathToVcvars64.bat}`
と定義されている。(上記の文字列中にある変数の場所がパスに該当しているはずだ。)

```vsdevcmd-debug.bat
call "&{PathToVcvars64.bat}"
msbuild ".\\"%1".vcxproj"
cd App
".\\"%1"(debug).exe"
```

```(例示)vsdevcmd-debug.bat
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
msbuild ".\\"%1".vcxproj"
cd App
".\\"%1"(debug).exe"
```

これで、コンソールにて
>`&{BaseName}`
このワークスペースの名前

```console:VSCode上のターミナル
> vsdevcmd-debug.bat &{BaseName}
```
```console:(例示)
> vsdevcmd-debug.bat OpenSiv3DProject
```
と入力すればしっかりと**Debugビルド**が行われる。
<details>
<summary>**Command Prompt for VS 2019について**</summary>
<div>

ここで、妙な記述がある。「x64 Native Tools Command Prompt for VS 2019」のショートカットのプロパティまで開いていることについて解説する。
Developer Command Prompt for VS 2019やx64 Native Tools Command Prompt for VS 2019はいわゆるVisual Studioでやっているビルドだとかのものをそのままコマンドプロンプト上で実行できるようにしたものである。(ここ怪しい)(Power Shell版もあるよ！)

x64 Native Tools Command Prompt for VS 2019などで実行できるMsbuildなど様々なコマンドは、普通に起動しただけのコマンドラインでは実行できない(定義されていない)。
ここから、この二つのコンパイラは根本から違うものとして考えてしまいそうだが、実際はそうでもなく、x64 Native Tools Command Prompt for VS 2019などのショートカットでは**コマンドプロンプトを普通に起動して別のところに配置されているバッチファイルを実行しているに過ぎない。**このバッチファイルのパスは`&{PathToVcvars64.bat}`に該当する。
**つまりこのバッチファイルがただのCommand Promptをfor VS 2019たらしめている(?)**

じつはショートカットのプロパティの「リンク先」では、コマンド文字列を入力することでそのコマンドをしっかりと実行できるのだ。(つまりリンク先にパスを入力された状態でショトカをクリックすることは、ターミナルでパスを書いて実行するといったことと似ている?)

`%comspec% /k &{PathToVcvars64.bat}`
`%comspec%`というのは環境変数で、コマンドプロンプトまでの絶対パスに置換される。
`/k`というのはこののちに来るバッチファイルなどの実行可能ファイルの動作後、ターミナルを終了させずにそのまま続けて実行するためのオプションだ。

>Programming Field: Cmd - DOS コマンド一覧
[https://www.pg-fl.jp/program/dos/doscmd/cmd.htm]

こういったことから、for VS 2019専用のコマンドが普通のコマンドプロンプト上で使えるのだ。
なお、Developer Command Prompt for VS 2019ではなく、x64 Native Tools Command Prompt for VS 2019を選択したことには訳がある。
前者でOpenSiv3Dプロジェクトをビルドしようとすると32bit環境はもうサポートしないよと諭されるのだ。どうやらDeveloper Command Prompt for VS 2019はx86環境らしい…？
</div>
</details>

<details>
<summary>**%1ってなんぞや？**</summary>
<div>
今回定義したバッチファイルvsdevcmd.batは、引数をとる。
コマンドプロンプト上での文法について考えてみる。
このように「%n」とすることでバッチファイルがn番目の引数を取れる。(0<=n<=9,nは自然数)

> AdminWeb: バッチファイル実行時に引数を渡す
[https://www.adminweb.jp/command/bat/index6.html]

文字列の結合には、他言語みたく演算子は特に必要ない。

> CX's Memo（Windows関連）: Windowsコマンドプロンプト基礎文法最速マスター
[https://windows.g.hatena.ne.jp/cx20/20100203/p1]

また、その引数は、タスク側(バッチファイル呼び出し側)で`${workspaceFolderBasename}`としてある。これはVisual Studioで生成されたプロジェクトのファイル構成を見てもらえればなんとなく分かってもらえるのではないだろうか。
そうなると、指定の仕方としては`msbuild ".\\"%1".vcxproj"`となる。
これは実際には`".\\${workspaceFolderBasename}.vcxproj"`に該当する。
なぜわざわざ引数を使ってこのような遠回りなことをしたのかというと、この置換変数`${workspaceFolderBasename}`は`tasks.jsons`などの一部jsonファイルの中にあるものでしか直接置換されないためだ。
自分が置いたバッチファイルまでは置換の走査対象とはならないのだ。
</div>
</details>

<details>
<summary>**msbuildとvcxprojについて**</summary>
<div>

```(一部抜粋)vsdevcmd-debug.bat
msbuild ".\\"%1".vcxproj"
```
**拡張子vcxprojのファイルには、(これをテキストエディタなどで開いてみればわかるのだが)それぞれのビルド時の設定、Resource Filesのインクルード設定等も全部まとまってXML形式で記述されている。**
これを引数にしてやる必要があるのだ。

>Microsoft Visual Studioのドキュメント: MSBuild
[https://docs.microsoft.com/ja-jp/visualstudio/msbuild/msbuild?view=vs-2019]

</div>
</deatils>

<details>
<summary>画像フォルダを追加する際プロジェクトに自動で追加されない問題</summary>
<div>
カレントディレクトリが App ではないことは、`cd`どそれに伴うパスの変更で解決できる。

```(一部抜粋)vsdevcmd-debug.bat
cd App
".\\"%1"(debug).exe"
```
</div>
</details>
## プロジェクトをReleaseビルドする。
同様にバッチファイル`vsdevcmd-release.bat`を制作する。そして以下のように編集をするとよい。

```vsdevcmd-release.bat
call "&{PathToVcvars64.bat}"
msbuild ".\\"%1".vcxproj" /p:configuration=release
cd App
".\\"%1".exe"
```

```(例示)vsdevcmd-release.bat
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
msbuild ".\\"%1".vcxproj" /p:configuration=release
cd App
".\\"%1".exe"
```

実行する際には以下の様に

```console:VSCode上のターミナル
> vsdevcmd-release.bat &{BaseName}
```
```console:(例示)
> vsdevcmd-release.bat OpenSiv3DProject
```
と入力すればしっかりと**Releaseビルド**が行われる。
<details><summary>MSBuildとRelease</summary>
<div>
`/p:configuration=release`をMSBuildのオプションとして記述するとReleaseビルドとして行われる。

> 引用
[https://twitter.com/Osmium_1008/status/1218790630563823617?s=20]
チュートリアル: MSBuild の使用
[https://docs.microsoft.com/ja-jp/visualstudio/msbuild/walkthrough-using-msbuild?view=vs-2019]
</div>
</details>

## ビルドタスクとして設定する。
コマンドパレットにて`Tasks: Configure task`を実行する。
すると、`.vscode/tasks.json`が生成される。
配列tasksに対し以下のオブジェクトを追加する。

> `&{MSBuild}`
任意の文字列。ここでは実行するタスクを選択する際に出てくるタスクの名前が要求されている。私はMSBuildとしている。

```json:tasks.json
 {
     "tasks": [
    		...
         {
             "label": "&{MSBuild}-debug",
             "type": "process",
             "command": "vsdevcmd-debug.bat",
             "args": ["${workspaceFolderBasename}"],
             "group": "build",
             "presentation": {
                   "reveal": "always"
             },
             "problemMatcher": "$msCompile"
         },
         {
             "label": "&{MSBuild}-release",
             "type": "process",
             "command": "vsdevcmd-release.bat",
             "args": ["${workspaceFolderBasename}"],
             "group": "build",
             "presentation": {
                   "reveal": "always"
             },
             "problemMatcher": "$msCompile"
         },
         ...
     ]
 }
```

Ctrl+Shift+Bを押すなどして、「実行するビルドタスクを選択」を表示させると、`&{MSBuild}-debug`,`&{MSBuild}-release`が表示されているはずなので、これをそのままタスクとして実行させると…
[![Image from Gyazo](https://i.gyazo.com/4e20a6e90c6e3b1b43d9f0e827d3a807.png)](https://gyazo.com/4e20a6e90c6e3b1b43d9f0e827d3a807)
見事ビルドタスクとしてOpenSiv3Dプロジェクトをビルドすることに成功した。

# 今後の課題
- [ ] 任意の場所にVisual Studio上でOpenSiv3Dテンプレートからプロジェクトを生成する。->Visual Studio外でこれを実行できないか？
- [×] ~~Releaseビルドに対応できていない~~

# 引用,参考文献
- 修正
 - (画像フォルダでプロジェクトに自動で追加されない問題について)
[https://twitter.com/Osmium_1008/status/1218820716788760576]
 - (SIV3D_(VERSION)環境変数)
[https://twitter.com/Osmium_1008/status/1218811718568005632]
 - (Releaseビルドについて)
[https://twitter.com/Osmium_1008/status/1218790630563823617]
 - (Windowsにおいてgccコンパイラではコンパイルが出来ない)
[https://twitter.com/Reputeless/status/1208297249039503363]
[https://twitter.com/Reputeless/status/1110176034731655168]
- Microsoft Visual Studioのドキュメント: MSBuild
[https://docs.microsoft.com/ja-jp/visualstudio/msbuild/msbuild?view=vs-2019]
- チュートリアル: MSBuild の使用
[https://docs.microsoft.com/ja-jp/visualstudio/msbuild/walkthrough-using-msbuild?view=vs-2019]
- Visual Studio Code Docs: c_cpp_properties.json reference
[https://code.visualstudio.com/docs/cpp/c-cpp-properties-schema-reference]
- Visual Studio Code Docs: Customizing default settings
[https://code.visualstudio.com/docs/cpp/customize-default-settings-cpp]
- Visual Studio Code Docs: Configure VS Code for Microsoft C++
[https://code.visualstudio.com/docs/cpp/config-msvc]
- Visual Studio Code Docs: Integrate with External Tools via Tasks
[https://code.visualstudio.com/docs/editor/tasks]
- WGGの活動log: Visual Studio Code で DxLibの開発をする
[http://wgg.hatenablog.jp/entry/20170920/1505919082]
- stack overflow: What's the difference between process and shell in vscode tasks.json
[https://stackoverflow.com/questions/54306943/whats-the-difference-between-process-and-shell-in-vscode-tasks-json]
- Qiita: VS Codeの設定をキレイに変数置換
[https://qiita.com/ShortArrow/items/dc0c8cacd696154510f1]
- AdminWeb: バッチファイル実行時に引数を渡す
[https://www.adminweb.jp/command/bat/index6.html]
- CX's Memo（Windows関連）: Windowsコマンドプロンプト基礎文法最速マスター
[https://windows.g.hatena.ne.jp/cx20/20100203/p1]

### ここまでのみちのり
1. https://scrapbox.io/appbirdNotebook/2019%2F12%2F20-2019%2F12%2F21の試み
2. https://scrapbox.io/appbirdNotebook/2019%2F12%2F26の試み
3. https://scrapbox.io/appbirdNotebook/2020%2F01%2F13の試み
4. 公開
https://scrapbox.io/appbirdNotebook/VSCode(Windows)%E3%81%AB%E3%81%A6%E3%80%81OpenSiv3D%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E4%B8%8A%E3%81%A7%E3%81%AE%E8%A3%9C%E5%AE%8C%E6%A9%9F%E8%83%BD%E3%81%AE%E8%A8%AD%E5%AE%9A&(MSBuild%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F)%E3%83%93%E3%83%AB%E3%83%89%E3%82%92%E8%A1%8C%E3%81%86

5. https://scrapbox.io/appbirdNotebook/VSCode(Windows)%E3%81%AB%E3%81%A6%E3%80%81OpenSiv3D%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E4%B8%8A%E3%81%A7%E3%81%AE%E8%A3%9C%E5%AE%8C%E6%A9%9F%E8%83%BD%E3%81%AE%E8%A8%AD%E5%AE%9A&(MSBuild%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F)%E3%83%93%E3%83%AB%E3%83%89%E3%82%92%E8%A1%8C%E3%81%86%E3%81%93%E3%81%A8%E3%81%AE%E8%A7%A3%E8%AA%AC

[@Reputeless](https://twitter.com/Reputeless?s=20)さん,[@Beat7501](https://twitter.com/Beat7501?s=20)さん,[@Osmium_1008](https://twitter.com/Osmium_1008?s=20)さんなどその他の人々のおかげで、ものすごく時間がかかりつつもなんとかここまでたどり着くことが出来ました。
感謝しかありません。本当にありがとうございました。


[^1]: 正直ここも、特定のvsdevcmdコマンドをVSCodeのタスクに登録してしまって、VSを開かずとも生成するみたいなことができそうな気もするけど…(今のところ分かっていない)