Visual studio codeで競プロ環境構築[mac OS]


MacOS上で競技プログラミング環境構築したので、
ちょこちょこ詰まったとこを中心にメモります。

12/28更新:Atcoderテスト自動化ツール

実現すること

  • Mac上でgcc動作環境を整え、visual studio codeからコンパイル&実行を行う。
  • 競プロで役立つライブラリ(bits/std++.h)を使えるようにする。

動作環境について

  • macOS Mojave
  • Visual Studio Code

コンパイラについては後述

前提(C++のコンパイラについて)

競技プログラミングのC++のコンパイラはClang系かgcc系の二つが用意されている。


(Atcoder コードテスト画面)

しかし、MacOSではC++のコンパイラとして、Clang系のみ標準搭載されている(/usr/bin/g++にある。)

terminal
$ /usr/bin/g++ --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Clang vs gcc

競技プログラミング的な視点では、Clangとgccどっちが良いのだろうか?

実はgccにのみ、stdc++.hというC++の標準ライブラリの集合体が入っており、
#include <bits/stdc++.h>一行書くと、必要なライブラリがだいたい揃う。

よって本記事では、
Mac(XOS)上に、gcc系のC++コンパイラを入れ、
#include <bits/stdc++.h>を使えるビルド環境を構築することを目標とします。

環境構築(gcc)

本題。gccで環境構築するのでちょっと面倒です。
単にコンパイルできれば良いよ〜という方はもっと楽にできるかと思います。

1.準備(03/25追記)

Visual Studio Codeを開き、
左のExtensionss(四角のアイコン)から下記の拡張機能を入れておく。
- C/C++ : コード整形、タグジャンプ、自動補完を行ってくれる。IntelliSence機能とも。
- Visual Studio IntelliCode :上に同じ。
- code-runner : VScode上でのショートカット操作で外部のshell scriptを実行できる

2.gccをインストール

Macのターミナルを開き、
Macのパッケージ管理システムhomebrewを使って、コンパイラgccをインストールします。

terminal
$ brew install gcc

※9/11追記
homebrewの設定が出来ていない(上記のコマンドが通らない)場合はまず↓から。

https://qiita.com/Naggi-Goishi/items/391b374305bc41b0d9f3

インストール後、/usr/local/下に、g++-9みたいなのが作られているハズ

3.pathの設定

2.が終わると、mac上に2種のコンパイラ(clang, gcc)が同居している状態になる。

  • /usr/bin/g++ (clang)
  • /usr/local/bin/g++-9 (gccの実体)

ただこの状態でg++コマンドを打っても、/usr/bin/g++(clang)の方が呼び出される。

terminal
$ which g++
/usr/bin/g++

clangではなくgccの方を呼び出したいので、下記の処理を行う。
/usr/local/bin/にg++(gcc)のシンボリックリンクを作成する。

terminal
$ ln -s /usr/local/bin/g++-9 /usr/local/bin/g++

このようにすることで、g++コマンドで/usr/local/bin/g++が呼び出されるようになった。
これで、先ほどインストールしたg++-9(gcc)が実行されるようになった。

terminal
$ which g++
/usr/local/bin/g++

元に戻したい場合は、
先ほどのシンボリックリンク(/usr/local/bin/g++)を削除すればOK。

(余談:環境変数の優先順位について)
今回のようにg++コマンドに対して/usr/bin/g++と/usr/local/bin/g++の双方が存在する場合、
環境変数の設定順序によってコマンドがどう呼び出されるかが決まる。

terminal
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

上記のように、/usr/local/binが/usr/binの先にあるので、
/usr/bin/g++より、/usr/local/bin/g++が優先的に呼び出される。

4. コンパイル

コンパイラの設定が終わったので、実際にcode-runnerを使ってC++のコンパイルを行う。
code-runnerは、プログラミング言語ごとに実行するスクリプトを設定することが出来る。
(Runnerでも同様なことができる?)

4.1 code-runnerの設定(20/12/4修正)

(最新版のcode-runnerでは設定が簡単になりました。)

左側のExtensionタブを選択し、install済のCode Runnerを探す。
Code Runnerの歯車のマークをクリックし、Extension Settingsを選択。

右画面に設定画面が出てくるので
Code-Runner: Run In Terminalのチェックボックスを入れる。

4.2 動作確認

実際に適当なソースを書いて実行してみる。
ソースファイル上でcontrol + option + nを入力すると、コンパイル+実行される。
(このショートカットキー割り当てはcommand+k command+tから変更できる。)

test.cpp
#include <iostream>
using namespace std;

int main(){
    int i;
    cin >> i;
    cout << i * 2 + 1 << endl;
} 

Code-runnerでは各言語(拡張子)に対してどのような処理を行うかが規定されている。
4.1の設定画面からCode-runner: Executor Mapを見ると、
cppに対応する処理が記載されている。

{
    "code-runner.runInTerminal": true,
    "code-runner.executorMap": {
        "javascript": "node",
        "java": "cd $dir && javac $fileName && java $fileNameWithoutExt",
        "c": "cd $dir && gcc $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt",
        "cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt",
        ~省略~
    }
}

つまり、内部的には下記が実行されている。

cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt"

ここで、下記三つの処理を実行している。

  • ソースコードのあるディレクトリに移動
  • test.cppをコンパイルし、実行ファイルtestを生成する
  • 実行ファイルtestを実行する

また、4.1でterminalで実行するよう設定したため、上記はterminal上で実行される。
上のプログラムのように標準入力を受け取る場合は、terminalに入力することで動作する。

5. #include <bits/stdc++.h>を使えるようにする

stdc++.h はとても便利。
競プロで必要なライブラリのincludeをこのヘッダファイル一つで行える。
ただ現状では、
#include <bits/stdc++.h> を書くと下記のような破線で警告がでるハズ。(赤破線)

また手順4.で構築した方法でコンパイルしようとすると、stdc++.hが無いよ!と怒られてしまう。

5.1 stdc++.hの準備

実はgccをインストールした段階で、/usr/local/下の奥深くにstdc++.hに存在します。
(インストールのタイミング次第で、バージョンが違うことがあります。)

terminal
$ cd /usr/local/
$ find . -name "stdc++.h"
./Cellar/gcc/9.2.0/include/c++/9.2.0/x86_64-apple-darwin18/bits/stdc++.h

これをコンパイラが認識出来る場所/usr/local/下に配置する必要があります。
/usr/local/include/下にbitsディレクトリを作成しておき、
stdc++.hをコピーします。

terminal
$ mkdir /usr/local/include/bits
$ cp ./Cellar/gcc/9.2.0/include/c++/9.2.0/x86_64-apple-darwin18/bits/stdc++.h /usr/local/include/bits/

この時点で#include を付けてコンパイル出来るようになります。
しかし、vscodeのIntellisense機能がstdc++.hを認識出来ていないため、
まだ緑破線で警告が出るかと思います。

5.2 C/C++ Intellisenseの設定

1.でインストールしたC/C++ のIntellisense機能とは、
コード整形、タグジャンプ、自動補完を行ってくれる拡張機能。
ただ、これらの機能を正常に動作させるためにはある程度手動での設定が必要。
具体的には、
Intellisense機能に/usr/local/include/bits/stdc++.hの存在を教えてあげる必要がある。

Command+Shift+P でコマンドパレットを開き、
「C/Cpp: Edit configurations」 を選択する。

c_cpp_properties.json
{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/local/include/**"
            ],
            "defines": [],
            "macFrameworkPath": [
                "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks"
            ],
            "compilerPath": "/usr/local/bin/g++",
            "cStandard": "c11",
            "cppStandard": "c++14",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

ポイントは以下の4点
- "includePath" に "/usr/local/include/**"を追記する。
- "compilerPath": "/usr/local/bin/g++"
- "cppStandard": "c++14"
- "intelliSenseMode": "gcc-x64"

これで#include <bits/stdc++.h>が正常に認識されるハズ。
もしダメだったら、一旦vscode再起動とかすると反映されたりする。

6. 追記予定

  • debugについて (gdbとMac Mojaveの相性が悪いらしく苦戦中です。。lldbでもデバッグ出来る?)

参考

【翻訳】Visual Studio Code C/C++ Extension の設定ファイル c_cpp_properties.json のリファレンスガイド
https://qiita.com/yuki12/items/0296796c64dd077bd5c4

旧手順(昔の記事の設定手法)

古い環境における情報です。参考まで

4.1 code-runnerの設定

まず、code-runnerの設定ファイルを編集する。
command + ,で設定を開き、下部のタブから
Extension > Run Code configuration > Executor Map > Edit in settings.json
を選択すると、設定ファイルを編集できる。

settings.json
{
    "workbench.colorTheme": "Monokai Dimmed",
    "code-runner.runInTerminal": true,
    "workbench.sideBar.location": "left",
    "editor.suggestSelection": "first",
    "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
    "code-runner.executorMap": {
        "cpp": "/Users/[user名]/vsc_run/cpp.sh"
    }
}

これは「c++ファイルに対しては、/Users/[user名]/vsc_run/cpp.shのスクリプトを実行するよ!」
という設定を意味している。
C,python等他の言語に対して別途スクリプトを割り当てることも可能。

この段階で実行しようとしても、cpp.shが無いので何も起こらない。

4.2 スクリプト作成

4.1で定義したcpp.shを作成する。
このcpp.shでコンパイルおよび実行の処理を行う。

terminal
cd ~/
mkdir vsc_run
vim cpp.sh

cpp.shの中身はこんな感じ。

cpp.sh
#!/bin/sh
file = $1
objfile = `echo $file | sed 's/\.[^\.]*$//'`

g++ -g -o $objfile $file
./$objfile

シェルの実行時の引数$1にファイル名が入るように動作するので、
「abc121_d.cppをコンパイルし、実行ファイルabc121_dを作成して実行する」
ような処理になる。