競プロで C++ と Python を使っていて,Windows での実行環境が欲しかったので作ってみました.
開発用ではないので必要最低限の設定になっています.
2020/1/11: VSCode 上で C++ 17 の文法を使えるようにする「C++ Standard の設定」を追加しました
対象
- C++ や Python の簡単な実行環境を作りたい方
- Windows ユーザ
- Docker 導入済み
- VSCode を使っている方
使用環境 / ツール
- GitHub
- Windows 10 + WSL2
- Docker Desktop for Windows (v3.0.0)
- VSCode (v1.52.1)
この記事で作れる実行環境のサンプルリポジトリ : https://github.com/e5pe0n/algo-training-sample
GitHub にリポジトリを作る
コードを管理しやすいように GitHub にリポジトリを作ります.
適当な Repository Name を入力し,Add a README file
にチェックを入れて Create Repository をクリックします.
.gitignore はあとから作るのでここではチェックしません.
Dev Container の作成
いま作ったリポジトリを,実行環境となる Docker コンテナにクローンします.
VSCode に Remote Development を入れる
まずは VSCode からコンテナに接続できるように, VSCode を開いて拡張機能 Remote Development (ms-vscode-remote.vscode-remote-extensionpack) をインストールします.
VSCode と GitHub を紐づける
インストールが完了すると,エディタの一番左下に Remote Development の機能が使える緑色のボタンが表示されるので,それをクリックします.
出てきたメニューの中から Remote-Containers: Clone Repository in Container Volume
をクリックします.
リポジトリの URL を入力してエンターを押します.
初回では,VSCode で GitHub アカウントにサインインするかのダイアログが表示されたり,ブラウザに飛んで VSCode が GitHub にアクセスすることを許可するか聞かれたりするので,それぞれ Yes や Continue をクリックします.
クローンするブランチ
VSCode と GitHub が紐づけられると,クローンするブランチを聞かれるので main
を選択します.
ボリュームの種類
ほかのリポジトリと併用しないので今回は Create a unique volume
を選択します.
コンテナの種類
コンテナの種類は Ubuntu
にしましょう.
続いてバージョンを聞かれますが focal
にします.
これでひとまずリポジトリに紐づいたコンテナを作ることができました.
ここからは C++ や Python が実行できるようにコンテナの設定を整えていきます.
コンテナの設定
初めてコンテナが作られたときは以下のようなディレクトリ構成になっていると思います.
ここから設定ファイルを編集したり,新しく設定ファイルを追加したりしていきます.
/workspaces/<repo-name>
├── .devcontainer
│ ├── devcontainer.json
│ └── Dockerfile
├── .git
└── README.md
最終的なディレクトリ構成はこんな感じです.
/workspaces/<repo-name>
├── .clang-format
├── .devcontainer
│ ├── devcontainer.json
│ └── Dockerfile
├── .git
├── .gitignore
├── README.md
└── requirements.txt
.gitignore の作成
リポジトリのディレクトリ直下で touch .gitignore
を実行して空のファイルを作っておきます.
gitignore.io で vscode
,C++
,Python
を入力して Create をクリックします.
表示された内容を全部先ほど作成した .gitignore にコピーして完成です.
必要があれば編集してください.
Dockerfile の編集
Dockerfile の # [Optional] Uncomment this ...
以下の部分に,コンテナが作られるときに実行されるコマンドを追加していきます.
apt-get
でインストールする build-essential は C++ のコンパイラ g++ が入っていて,clang-format は C++ ファイルのフォーマット用です.
また,デフォルトでは Python 3.8.2 が入っていますが,Python のパッケージインストーラ pip が入っていないので python3-pip をインストールします.
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.154.0/containers/ubuntu/.devcontainer/base.Dockerfile
# [Choice] Ubuntu version: bionic, focal
ARG VARIANT="focal"
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
build-essential \
clang-format \
python3-pip
.clang-format の作成
C++ ファイルのフォーマットの設定ファイルとして .clang-format を用意します.
VSCode のオートフォーマットを on にして C++ のフォーマッターを Clang-Format に設定することで,.clang-format の設定通り自動的にコードをフォーマットできます.
設定できる項目はめっちゃいっぱいある( https://clang.llvm.org/docs/ClangFormatStyleOptions.html )のでお好みで.
自分は正直よくわかってないのでとりあえず気になったものだけ設定しています.
ColumnLimit: 110
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: true
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
ConstructorInitializerAllOnOneLineOrOnePerLine: true
IndentWidth: 2
requirements.txt の作成
requirements.txt は Python のパッケージ管理に使うファイルです.
ここにパッケージを列挙しておき,pip3 install -r requirements.txt
を実行することで必要なパッケージを 1 コマンドでインストールすることができます.
導入するのは次のパッケージです.
パッケージ | 説明 |
---|---|
numpy | 行列演算・数値計算とか用 |
flake8 | リンター |
autopep8 | フォーマッター |
これらを pip3 install
でインストールしたあと,インストールしたパッケージの一覧を pip3 freeze
で requirements.txt に書き出します.
$ pwd
/workspaces/<repo-name>
$ pip3 install numpy flake8 autopep8
$ pip3 freeze > requirements.txt
依存しているパッケージも合わせると requirements.txt は次のようになっていると思います.
autopep8==1.5.4
flake8==3.8.4
mccabe==0.6.1
numpy==1.19.4
pycodestyle==2.6.0
pyflakes==2.2.0
toml==0.10.2
devcontainer.json の編集
コンテナの設定ファイルです.
この中に VSCode の設定やコンテナが作られたあとのコマンドなどを書いておくことで,コンテナを作成したとき設定が自動的に反映されます.
オプション | 説明 |
---|---|
settings | コンテナ独自の VSCode の設定 |
extensions | コンテナで使う VSCode の拡張機能 |
postCreatedCommand | コンテナが作られたあとに実行したいコマンド |
settings
VSCode の設定を書く部分です.
オプション | 説明 |
---|---|
editor.formatOnSave |
true でファイル保存時に自動フォーマット |
python.languageServer | Python IntelliCode のサーバ |
python.pythonPath | 使用する Python インタプリタのパス |
python.linting.flake8Args | flake8 の引数 |
python.formatting.provider | Python のフォーマッタを選択 |
[cpp]->editor.tabSize | C++ ファイルでのインデントの文字数 |
[cpp]->editor.defaultFormatter | C++ のフォーマッタを選択 |
extensions
インストールしたい VSCode の拡張機能を列挙するところです.
自分はとりあえず以下のものを書いています.
拡張機能 | ID | 説明 |
---|---|---|
Visual Studio IntelliCode | visualstudioexptteam.vscodeintellicode | AI アシスタントがコード補完を提示してくれる |
C/C++ | ms-vscode.cpptools | C++ 用 |
Clang-Format | xaver.clang-format | C++ ファイル用フォーマッタ |
Git Extension Pack | donjayamanne.git-extension-pack | Git 用 |
Python | ms-python.python | Python 用 |
Pylance | ms-python.vscode-pylance | Python 用 |
Bracket Pair Colorizer 2 | coenraads.bracket-pair-colorizer-2 | 対応する括弧をカラーリングしてくれる |
Trailing Spaces | shardulm94.trailing-spaces | 余分なスペースをハイライト・除去 |
Vim | vscodevim.vim | VSCode 用 Vim エミュレータ |
postCreateCommand
コンテナ作成後に実行されるコマンドを書くところです.
pip3 install -r requirements.txt
をここに書いておくことで,先ほど書いた requirements.txt のパッケージを自動的にインストールしてくれます.
remoteUser
root でコンテナに接続したいときは以下のようにコメントアウトします.
パーミッションまわりがいろいろ面倒なので自分は基本 root で使っています.
// "remoteUser": "vscode"
これらを設定すると devcontainer.json はこんな感じになります.
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.154.0/containers/ubuntu
{
"name": "Ubuntu",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick an Ubuntu version: focal, bionic
"args": {
"VARIANT": "focal"
}
},
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"editor.formatOnSave": true,
"python.languageServer": "Pylance",
"python.pythonPath": "/usr/bin/python3",
"python.linting.flake8Args": [
"--max-line-length", // 1 行あたりの文字数を 110 に設定
"110"
],
"python.formatting.provider": "autopep8",
"python.formatting.autopep8Args": [
"--max-line-length", // 1 行あたりの文字数を 110 に設定
"110"
],
"[cpp]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "xaver.clang-format" // 拡張機能 Clang-Format を選択
},
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"visualstudioexptteam.vscodeintellicode",
"ms-vscode.cpptools",
"xaver.clang-format",
"donjayamanne.git-extension-pack",
"ms-python.python",
"ms-python.vscode-pylance",
"coenraads.bracket-pair-colorizer-2",
"shardulm94.trailing-spaces",
"vscodevim.vim"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip3 install -r requirements.txt",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}
以上でコンテナの設定は完了です.
コンテナのリビルド
仕上げとして,設定に基づいてコンテナをリビルドします.
左下の緑色の Dev Container: Ubuntu
をクリックし,Remote-Containers: Rebuild Container
を選択します.
これで C++ と Python の実行環境ができました.
リビルドが完了したあと,例えば次の hello.cpp,hello.py をコンテナ内で実行できます.
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << "I'm C++!" << endl;
}
# g++ -o hello hello.cpp
# ./hello
I'm C++!
print("I'm Python!!")
# python3 hello.py
I'm Python!!
あとはこれをリモートのリポジトリにプッシュしておけば,同じ環境をすぐに作ることができます.
C++ Standard の設定
入れたままだと拡張機能 C/C++ が C++ 17 の文法を書くとエラーメッセージが表示されてしまうので,C++ Standard の設定をします.
Ctrl
+ Shift
+ P
でコマンドパレットを開き,C/C++: Edit Configurations (JSON)
を選択します.
すると,/workspaces
直下にディレクトリ .vscode
が作られ,その中に c_cpp_properties.json
が作られます.
この中の cppStandard
を "gnu++17"
に設定します.
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"cppStandard": "gnu++17",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}
例えば構造化束縛を使った以下のコードでもエラーメッセージが表示されなくなります.
おまけ
自分は新しくディレクトリを作るとき C++ と Python のディレクトリを分けたいので,テンプレートとして次のディレクトリをリポジトリに入れています.
template
├── cpp
│ ├── build // C++ の実行ファイル置き場
│ │ └── .gitkeep
│ ├── .gitkeep
│ └── run.sh // C++ ファイル実行用スクリプト
└── python
└── .gitkeep
f=`echo $1 | sed -e 's/\(.*\).cpp/\1/'`
current_dir=$(eval pwd)
g++ -std=c++17 -g -o ${current_dir}/build/${f}.out $1
eval ${current_dir}/build/${f}.out
run.sh は C++ ファイルをコンパイル + 実行するスクリプトで, sh run.sh A.cpp
みたいに使います.
競プロをやっていく上でもっといい運用方法があればぜひ教えてほしいです!