競プロ用の環境構築覚書 C++&VSCode(&WSL2)

## はじめに

やると快適になるけれど、何かと面倒な環境構築。
私は環境構築への苦手意識が強くあったのですが、3回くらいやって少しは慣れた気がするので今のうちにメモをしておきます。
もし記事内容に明らかな誤りがあれば、コメント等でご指摘いただけると幸いです。

当記事では以下の内容を扱います。
+ **C++20**[^1]の導入
+ **AtCoder Library**の導入
+ `<bits/stdc++.h>`ヘッダの**プリコンパイル**
+ コンパイルと実行のコマンド(ShellScript)

Linuxについての知識が一切ない人でも大丈夫だと思います。

なお、想定環境としてはWindows11+WSL2でVSCodeを利用する形ですが、Windows10でも概ね同様だと思います。
LinuxユーザでもWSL関連以外の内容は共通しています。MacOSはわかりかねます…

最終的にはこのようなディレクトリ[^2]構成になります。
~~`ac-library`ディレクトリを作業ディレクトリ下に置くかはお好みで分かれると思いますが、今回の記事では外に置きます。~~
私の環境では`ac-library`ディレクトリを作業ディレクトリ直下に置いていないと動作しないことを確認したので、作業ディレクトリ直下に置く方針へ記事を修正しました。[2024/07/01 追記]

また、`main.cpp`以外のcppファイルも同様に使用できます。`a.cpp`など。
```:ディレクトリ構成
competitive/
    ├ ac-library/
    │   ├ atcoder/
    │   └ expandar.py
    ├ .vscode/
    │   ├ c_cpp_properties.json
    │   └ settings.json
    ├ sh/
    │   ├ build.sh
    │   └ io.sh
    ├ a.out
    ├ in.txt
    ├ main.cpp
    └ out.txt
```

## 目次

1. [VSCodeの導入](#vscodeの導入)
2. [WSLの導入 (Windowsユーザのみ)](#wslの導入-windowsユーザのみ)
3. [C++の導入、バージョン設定](#cの導入バージョン設定)
4. [VSCode側の設定](#vscode側の設定)
    - [WSLとの接続](#wslとの接続)
    - [C++の設定](#cの設定)
5. [AtCoder Libraryの導入](#atcoder-libraryの導入)
6. [\<bits/stdc++.h>ヘッダのプリコンパイル](#bitsstdchヘッダのプリコンパイル)
7. [実行用ShellScriptの作成](#実行用shellscriptの作成)
8. [おわり](#おわり)

## VSCodeの導入

VSCodeを使用するので、まずはVSCodeをインストールしておきましょう。

https://code.visualstudio.com/download

こちらのリンク先ページに飛び、現在使用しているOSに合わせてダウンロードボタンを押下します。
想定読者となるWindowsユーザの方は「Windows」でよいです。

## WSLの導入 (Windowsユーザのみ)

WSL (Windows Subsystem for Linux)を利用して、実行環境をLinux上に移します。
一見回りくどいようですが、Windows上でやるよりも色々と都合がよいためです。

なお、Windows以外のユーザはこの項を飛ばして構いません。

https://learn.microsoft.com/ja-jp/windows/wsl/install

https://qiita.com/zakoken/items/61141df6aeae9e3f8e36

これらの記事を参考に進めればよいと思います(特に二つ目の記事)。

具体的には、以下の手順を行えばよいです。
Windows PowerShellかコマンドプロンプトを「管理者として実行」で開いて、以下のコマンドを実行します。

```:Windows PowerShell (管理者として実行)
wsl --install
```

その後PCを再起動します。

Linux側のターミナル (既定ではUbuntu) を開き、こちらでLinux側のユーザー名とパスワードを設定します。

:::note warn
Linux側のユーザ名とパスワードは**半角英数字のみ**を用いるほうがよいです。
入力中のパスワードは一切表示されない仕様なので、正確に入力してください。
**パスワードは必ず忘れないでください。**
:::

ただし、バージョンが古いWindows10を利用している人は、[こちらの記事](https://learn.microsoft.com/ja-jp/windows/wsl/install-manual)に沿って進める必要があります(バージョン等の詳細は[一つ目の記事](https://learn.microsoft.com/ja-jp/windows/wsl/install)を参照のこと)。

## C++の導入、バージョン設定

ここからは、コマンドの実行はすべてLinux側のターミナルで行います。
既定のLinuxターミナルはUbuntuです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/b88a1f45-7898-3603-e37c-8fda1fa019eb.png)

https://zenn.dev/claustra01/articles/89da6c4fbaf2ed#c%E8%A8%80%E8%AA%9E%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%82%92%E5%B0%8E%E5%85%A5%E3%81%99%E3%82%8B

こちらの記事の「C言語のコンパイラを導入する」の項に沿って進めればよいです。
具体的には以下の手順でコマンドを実行します。

```:Ubuntu
sudo apt update
sudo apt upgrade
sudo apt install build-essential
```

これでC++自体は実行できるようになりましたが、バージョン関係の設定も必要です。

https://students-tech.blog/post/change-gcc.html

こちらの記事の手順に沿って、gcc及びg++の別バージョンをインストールし、`update-alternatives`コマンドの設定もしておきましょう。
これによりC++20環境を利用できます。

具体的には以下の手順を実行します。
12の部分は適宜最新のバージョンの数値に置き換えてください(詳しくは後述)。

```:Ubuntu
sudo apt install gcc-12
sudo apt install g++-12
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 12
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 12
```

AtCoderでは各コンテストページの下部に「ルール」と書かれたリンクが貼られており[(例: ARC178 - ルール)](https://atcoder.jp/contests/arc178/rules)、このページの「言語」の項から実行環境を確認することができます。
最新の実行環境に合わせて上記の設定をしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/c07718d3-59f9-e572-066c-0fd7573b846d.png)

## VSCode側の設定

VSCode側の設定も進めていきます。
まずはWSLをVSCodeと接続します。

### WSLとの接続

以下のコマンドを実行します。
実行後はLinuxのターミナルを一旦終了しておきましょう。

```:Ubuntu
sudo apt-get update
sudo apt-get install wget ca-certificates
```

次に、VSCodeを起動して「WSL」拡張機能をインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/134898e0-75ca-f6c6-b2ac-4416c11cbd0b.png)

一度VSCodeを終了します。
Linuxのターミナルを起動し、以下を実行して競プロ用のディレクトリを作成します。

```:Ubuntu
mkdir competitive
code competitive
```

作業ディレクトリ`competitive`を作成し、VSCodeで開きました。
`competitive`の部分は好きな名前でよいですが、以下では`cometitive`と仮定します。

VSCodeの左下に`WSL: Ubuntu`などと表示されていたらWSLとの接続は完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/d2e59112-19af-5f7e-138a-a1259352e878.png)

### C++の設定

VSCode上でC++を快適に書くための設定をしていきます。
「C/C++」「C/C++ Extension Pack」拡張機能をインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/fa278996-c619-4fc8-4f65-90fb378ff0ce.png)

インストールしたらVSCodeを再起動してください。

`Ctrl+Shift+P`でコマンドパレットを開き、「C/C++: Edit Configurations (JSON)」を押下します。
`.vscode`ディレクトリが作業ディレクトリ下に作成され、その中に`c_cpp_properties.json`が作成されます。

`c_cpp_properties.json`に以下の内容を記述します。
```json:c_cpp_properties.json
{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",             
                "~/competitive/ac-library"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c17",
            "cppStandard": "gnu++20",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}
```

<details><summary>初期状態とのDiff</summary>

```diff_json:c_cpp_properties.json
{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",             
+               "~/competitive/ac-library"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c17",
-           "cppStandard": "gnu++14",
+           "cppStandard": "gnu++20",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}
```

</details>


`includePath`の`"~/competitive/ac-library"`に赤波線が引かれていると思いますが、これは一旦無視して先に進みます。

:::note info
ついでに、画面左上の`File`>`Preferences`>`Settings`でVSCode全般の設定ができることを知っておきましょう。
設定に関しては人それぞれなので、使いながら適宜設定していけばよいです。基本的に`Workspace`の設定をいじるほうが良いと思います[^3]。

なお、今回の記事の構成に合わせる場合、`Files: Auto Save`は`onFocusChange`にしておくことを推奨します。
:::



## AtCoder Libraryの導入

AtCoder Libraryという便利なAtCoder公式ライブラリ集があります。
せっかく環境構築をするからにはこれも導入しておきましょう。

AtCoder Libraryを知らないという人は以下のリンク先の記事を参考にしてください。
ドキュメント: https://atcoder.github.io/ac-library/production/document_ja/
紹介いろいろ: https://atcoder.jp/posts/517

AtCoder Libraryの保存場所は`Linux > Ubuntu > home > [ユーザ名] > [作業ディレクトリ] > [AtCoder Libraryを入れるディレクトリ]`です[^4]。
以下では、[AtCoder Libraryを入れるディレクトリ]のディレクトリ名を`ac-library`にしたと仮定して話を進めます。

予め`ac-library`ディレクトリを作成しておきます。

```:Ubuntu
cd ~/competitive
mkdir ac-library
```

さて、AtCoder Libraryをダウンロードします。
こちらのGitHubから、画面中央-右上あたりの「Code」>「Download ZIP」を押下します。

https://github.com/atcoder/ac-library

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/6463cf3b-a4b6-ac07-94d2-511fd44eaddf.png)

ダウンロードしたzipファイルを展開し、Linux側に移します。
WSLであれば、Windows標準の「エクスプローラー」からLinux環境のファイルにも干渉できるので、普通にコピペなりドラッグアンドドロップなりをするとよいです。

:::note info
なお、展開したフォルダ(`ac-library-master`)内にはそこそこの数のファイルとフォルダが入っていたと思いますが、`ac-library`ディレクトリに移しておくべきなのは`atcoder`と`expander.py`くらいだと思います。
:::


あとは`c_cpp_properties.json`の`includePath`にac-libraryのパスを渡して、IntelliSenseに認識させておきます([この工程は既にやっています](#cの設定))。
`includePath`がこのようになっていればよいです。

```json
"includePath": [
    "${workspaceFolder}/**",
    "~/competitive/ac-library"
]
```

これでAtCoder Libraryの導入は完了です。

## \<bits/stdc++.h>ヘッダのプリコンパイル

参考:[^5]

https://www.ochappa.net/posts/pre-c-bs

:::note info
記事執筆時点とは使用すべきg++等のバージョンが変わっている可能性もあります。
ここで紹介する手順は適宜最新のバージョンに読み替えながら行ってください。
:::

ヘッダファイルのプリコンパイルをしておくと、コンパイルに要する時間を短縮することができます。
何回もコンパイルすることを考えると、一回あたりのコンパイル時間はできる限り短縮しておきたいところです。
ここでは`<bits/stdc++.h>`ヘッダをプリコンパイルします[^6]。

まずディレクトリを移行します。

```:Ubuntu
cd /usr/include/x86_64-linux-gnu/c++/12/bits
```

そして**普段使うコンパイルオプション**に合わせて以下のコマンドを実行、プリコンパイルヘッダを生成します。

```:Ubuntu
sudo g++ [オプション] stdc++.h
```

<INS>当記事では</INS>以下のコマンドを実行します。

```:Ubuntu
sudo g++ -std=gnu++20 -O2 -Wall -Wextra stdc++.h
```

こうすることで`.gch`ファイルが生成されているはずです。

```:Ubuntu
ls
```

を実行して`stdc++.h.gch`が表示されているか確認しましょう。

これでプリコンパイルは完了です。
`.gch`生成時と同じコンパイルオプションでコンパイルした場合、プリコンパイルヘッダが使用されて速くコンパイルされます。

<font color='gray'>(`<atcoder/all>`もプリコンパイルできたらいいんですが、たしかプリコンパイルヘッダは一つしか使えなかった…はずです。要出典。
まぁローカル環境ではヘッダファイルをまとめたものをプリコンパイルして使用、外部環境では個別に展開する…とか頑張ればいけると思うんですが、難しそうなので逃げています。
毎回ACLを使うことはないと思うので、ACL関連は適宜includeする形式をとっています。)</font>

## 実行用ShellScriptの作成

ここまで進めた時点で、すでにC++環境は完成しています。
ですが、これから毎回コンパイルをするたびに

```
g++ -std=gnu++20 -O2 -Wall -Wextra main.cpp
```

とは打ちたくない気持ちになります。
ここで、ショートカットのようなものを定義して楽をします。

ShellScriptという形式の(`.sh`)ファイルを作成していきます。
まず`.sh`ファイルをまとめる`sh`ディレクトリを`competitive`下に作成します。(任意)

```:Ubuntu
cd ~/competitive
mkdir sh
cd sh
```

コンパイルをするためのShellScript `build.sh`を作成します。

```:Ubuntu
code build.sh
```

`build.sh`に以下の内容を記述します。

```sh:build.sh
#!/bin/bash

cd ~/competitive/
# ソースファイルの決定
SOURCE_FILE="${1:-main.cpp}" # 引数が無い場合はmain.cppを使用

# "atcoder"の出現回数をカウント
ATCODER_COUNT=$(grep -o "atcoder" "$SOURCE_FILE" | wc -l)

# コンパイルオプションの決定
CXX_FLAGS="-std=gnu++20 -O2 -Wall -Wextra"
if [ "$ATCODER_COUNT" -ge 2 ]; then
    CXX_FLAGS+=" -I./ac-library"
fi

# コンパイル実行
g++ $CXX_FLAGS "$SOURCE_FILE"
```

以下の機能を実現しています。

+ 任意の`.cpp`ファイルをコンパイルする (初期値は`main.cpp`)
+ ソースファイル内に"atcoder"が2つ以上含まれているならAtCoder Libraryに対応したコンパイルオプションへ変更する

保存したら、

```:Ubuntu
chmod +x ./build.sh
```

で実行権限を与えておきましょう。すると (カレントディレクトリが./competitiveとして)

```
./sh/build.sh
```

で実行でき、`main.cpp`をコンパイルした実行ファイル`a.out`を生成してくれるはずです。

```bash:build.shの凡例
./sh/build.sh      # main.cppをコンパイル
./sh/build.sh a    # a.cppをコンパイル
```

`a.out`は

```
./a.out
```

で実行できますが、毎回これを打って入力を与えて、とするのはやや面倒です。
なので、`io.sh`で楽にできるようにします。

```:Ubuntu
code io.sh
chmod +x io.sh
```

`io.sh`の中身は以下の通りにします。

```sh:io.sh
#!/bin/bash

cd ~/competitive/
if [ $# -eq 0 ]; then
    ./a.out < in.txt > out.txt
elif [ "$1" == "term" ]; then
    ./a.out < in.txt
else
    ./a.out < in.txt > "$1.txt"
fi
```

`io.sh`は、`in.txt`の内容を標準入力として受け取って`a.out`を実行し、標準出力を`out.txt`に書き込みます(ファイル入出力)。
また、引数としてファイル名を渡せば標準出力を[ファイル名].txtに書き込みます。
`term`を引数にすると標準出力をターミナルに書き込みます(標準出力)。

```bash:io.shの凡例
./sh/io.sh             # out.txtに書き込み
./sh/io.sh memo        # memo.txtに書き込み
./sh/io.sh term        # ターミナルに出力
```

`in.txt`と`out.txt`を作成します。

```:Ubuntu
code in.txt
code out.txt
```

`in.txt`と`out.txt`は常に表示しているほうが便利なので、レイアウトを変えます。
`View > Editor Layout > Two Rows Right`を押下し、`in.txt`を右上のウィンドウに、`out.txt`を右下のウィンドウで開きます。

`./io.sh`を実行した例を以下に示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/a8e830cd-a4d6-11cc-40f1-d5f24c48fc3c.png)

これで定義完了…なのですが、`./build.sh`とか毎回打つのは結局面倒ですね？短縮します。

```:Ubuntu
code ~/.bashrc
```

`~/.bashrc`の一番下に、次の内容を追記します。

```bash:~/.bashrc
alias bd='/home/[ユーザ名]/competitive/sh/build.sh'
alias io='/home/[ユーザ名]/competitive/sh/io.sh'
```

私の場合は`/home/sora/competitive/sh/build.sh`などですね。

`alias ooo='xxx'`で`ooo`を`xxx`に置き換えます。
C++の`#define`マクロを想像するとよいです。
ちなみに、`bd`は`build`、`io`は`in/out`からとっています[^8]。

追記したら、以下を実行するかVSCodeを再起動して反映させます(再起動の方がよいかも?)。

```:Ubuntu
source ~/.bashrc
```

ここまで正常に進んでいれば、

```:Ubuntu
bd
io
```

でコンパイルと実行ができるはずです。楽ですね。

<details><summary>旧版のsh/</summary>

拙著のshファイルを一応残しておきます。
汚い見た目で、絶対これもっとうまく書けるんだろうとは思っていたんですが、ChatGPTに投げたら見事に綺麗になって帰ってきました。そんな…

```sh:build.sh
#! /bin/bash
cd ~/competitive/
if [ $# != 1 ]; then
    count_atcoder=$(grep -c "atcoder" main.cpp)
    if [ ${count_atcoder} -gt 1 ]; then
        g++ -std=gnu++20 -O2 -Wall -Wextra -I./ac-library/ main.cpp
    else
        g++ -std=gnu++20 -O2 -Wall -Wextra main.cpp
    fi
    exit 0
fi

FILE=$1
count_atcoder=$(grep -c "atcoder" ${FILE}.cpp)
if [ ${count_atcoder} -gt 1 ]; then
    g++ -std=gnu++20 -O2 -Wall -Wextra -I./ac-library ${FILE}.cpp
else
    g++ -std=gnu++20 -O2 -Wall -Wextra ${FILE}.cpp
fi
```

```sh:io.sh
#! /bin/bash
cd ~/competitive/
if [ $# == 0 ]; then
    ./a.out < in.txt > out.txt
    exit 0
fi
if [ $1 == "terminal" ]; then
    ./a.out < in.txt
    exit 0
fi
./a.out < in.txt > $1.txt
```
    
</details>

## おわり

これで当記事での環境構築は完了です。おつかれさまでした。

私はまだ導入していませんが、`online-judge-tools`や`atcoder-cli`など便利なコマンドラインツールもあるので、もっと利便性を高めたい人は調べてみると良いと思います。

昔`wsl --install`が使えない環境で初めてやったときは本当に大変で二度と触りたくないと思った記憶があるんですが、今回は結構楽でした。
この記事で次回以降はもっと楽になるとうれしいです。

---

これはただの余談なのですが、なんか現時点「競プロ　環境構築」でGoogle検索すると一番上にこの記事が出てくるらしいですね。「atcoder 環境構築」でも3番目に出てきています。
多分私が一番驚いてる。これそんなに上げてもらっていいのか？(困惑)
私用のメモ程度に書いた記事のつもりでしたが、ご愛読いただきありがたい限りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2902990/3513cd9a-ec48-7bda-d0da-a2eb84fe0ae0.png)


[^1]: 当記事執筆時点での、AtCoderで使用できるC++の最新バージョン (C++23も選択できますが、AtCoderの環境だと実質20なので…)
[^2]: 「ディレクトリ」はWindows等の「フォルダ」に相当する概念です
[^3]: というか優先度の都合などがあるのか、他の設定は反映されない? よくわかっていません…
[^4]: ~~「はじめに」の項で触れたとおり、別に作業ディレクトリ直下に置いても構いません。どっちのほうがいいのかは私にはわかりかねます。~~ 作業ディレクトリ直下に置きましょう
[^5]: サムネかわいいですね
[^6]: \<bits/stdc++.h>は元来プリコンパイルすることを前提に作られていたはずです
[^7]: とりあえずgrepより正規表現を用いた方がよさそうな気はしますが、どうなんでしょう
[^8]: `b`とか`i`とか、一文字にしたほうが早くなりますが、なんか一文字にまで踏み込む勇気は出ませんでした(?)