見出し画像

WindowsでAtcoderのC++環境を構築する


AtCoderを始めようとしたきっかけ

最近は仕事やプライベートで、Python、C#、Javascript(GAS)、VB(VBA)あたりのプログラミング言語を使用することが多かったのですが、仕事でC++をしっかり目に使う必要が出てきました。C++は社会人になってからはたまにマイコンを使うときに簡単に書く程度で、ほとんど書いていませんでした。
そこで、C++の復習と合わせて、いつか思考トレーニングのためにやりたいと思っていた競技プログラミングを始めようと思いました。
ChatGPTの登場によりプログラミングの仕方は変わっていくとは思いますが、個人的には、コピペをうまくするためにもある程度自力でプログラムを書く力や、アルゴリズム力は必要かと考えます。

競技プログラミングは、特にアルゴリズムの勉強とかもほとんどせずに高校生の時に情報オリンピックの予選などに参加した程度でほぼ素人です。
競技プログラミングを始めるにあたっては、基礎を学ぶために以下の「競技プログラミングの鉄則」という本を読み進めています。
(32歳になった今の自分にどこまでついていけるか…)

競プロのサイトとしては、日本語で簡単にできて、本書でも進められており、書籍の練習問題のテスト環境も提供しているAtCoderで始めることにしました。

環境構築の方針

AtCoder向けのC++環境を構築するにあたり、まずはインターネットで他の人の情報を参考してみたところ、Linux(Windowsの人はWSL2でLinux)で環境を構築するのが王道のようです。
ただ、私は普段はWindowsで開発しており、仕事でのC++もWindowsでの開発となる予定です。また、AtCoderのためだけにWSL2を使うのものな…ということで、元々自分のPCに入っていたVisual Studio向けC++環境を使えないかと考えました。
エディタ・統合開発環境としては、AtCoderはmain.cppを問題ごとに作成する必要があり、ソリューションやプロジェクトといった単位でビルドとなるVisual Studioでは少々使いづらいです(※1)。
そのため、Visual Studio Codeを使用することにしました。

※1 調べるとやっている人もいるようですが、毎回対象以外のファイルをビルド対象外とする必要がありそうです

環境構築方法

環境の前提

私は以下環境で試しています。

  • Windows 11 Home

  • Visual Studio 2022 Professional
    ※Communityでも一部パスが変わるのみで同じはずです

  • Python 3.9.7

cl.exeのPath通し

まずはVisual Studio用のC++コンパイラ(cl.exe)のPathを通します。Visual StudioのC++環境がない人は、Visual Studioインストール時に同時に入るVisual Studio Installerから追加で入れてください。
Visual Studio2022 Communityをデフォルトのまま、全ユーザー向けにインストールした場合、cl.exeは以下に入っているはずです。

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\[バージョン番号]\bin\Hostx64\x64

Windowsキーを押して”env”と打つと「環境変数を編集」が出てくるのでクリックします。

[ユーザー名]のユーザー環境変数のPathをクリックし、編集から上記のcl.exeの入ったフォルダのパスを追加します。その後、OKをクリックします。

x64向け設定を適用(2024/6/8追記)

違うPCをこの記事の通りにセットアップしようとすると以下エラーが出てしまいました。

C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\ostream(787): warning C4530: C++ 例外処理を使っていますが、アンワインド セマンティクスは有効にはなりません。/EHsc を指定してください。
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\include\ostream(787): note: テンプ レートインスタンス化コンテキスト (最初に最も古いもの) は
.\test.cpp(8): note: コンパイル対象の関数 テンプレート インスタンス化 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)' のリファレンスを確認してください
Microsoft (R) Incremental Linker Version 14.40.33811.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj
test.obj : error LNK2001: 外部シンボル _purecall は未解決です
test.obj : error LNK2019: 未解決の外部シンボル "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) が関数 "public: static void * __cdecl std::_Default_allocate_traits::_Allocate(unsigned __int64)" (?_Allocate@_Default_allocate_traits@std@@SAPEAX_K@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "void __cdecl operator delete(void *,unsigned __int64)" (??3@YAXPEAX_K@Z) が関数 "void __cdecl std::_Deallocate<16>(void *,unsigned __int64)" (??$_Deallocate@$0BA@@std@@YAXPEAX_K@Z) で参照され ました
test.obj : error LNK2019: 未解決の外部シンボル "void __cdecl operator delete[](void *)" (??_V@YAXPEAX@Z) が関数 "protected: void __cdecl std::ctype<char>::_Tidy(void)" (?_Tidy@?$ctype@D@std@@IEAAXXZ) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル _invalid_parameter_noinfo_noreturn が関数 "void * __cdecl std::_Allocate_manually_vector_aligned<struct std::_Default_allocate_traits>(unsigned __int64)" (??$_Allocate_manually_vector_aligned@U_Default_allocate_traits@std@@@std@@YAPEAX_K@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "public: __cdecl std::_Lockit::_Lockit(int)" (??0_Lockit@std@@QEAA@H@Z)  が関数 "class std::ctype<char> const & __cdecl std::use_facet<class std::ctype<char> >(class std::locale const &)" (??$use_facet@V?$ctype@D@std@@@std@@YAAEBV?$ctype@D@0@AEBVlocale@0@@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "public: __cdecl std::_Lockit::~_Lockit(void)" (??1_Lockit@std@@QEAA@XZ) が関数 "class std::ctype<char> const & __cdecl std::use_facet<class std::ctype<char> >(class std::locale const &)" (??$use_facet@V?$ctype@D@std@@@std@@YAAEBV?$ctype@D@0@AEBVlocale@0@@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル free が関数 "private: void __cdecl std::_Yarn<char>::_Tidy(void)" (?_Tidy@?$_Yarn@D@std@@AEAAXXZ) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル memcpy が関数 "private: void __cdecl std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::_Take_contents(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?_Take_contents@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAAXAEAV12@@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル memmove が関数 "public: static char * __cdecl std::_Char_traits<char,int>::move(char * const,char const * const,unsigned __int64)" (?move@?$_Char_traits@DH@std@@SAPEADQEADQEBD_K@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル strlen が関数 "public: static unsigned __int64 __cdecl std::_Narrow_char_traits<char,int>::length(char const * const)" (?length@?$_Narrow_char_traits@DH@std@@SA_KQEBD@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "void __cdecl std::_Xlength_error(char const *)" (?_Xlength_error@std@@YAXPEBD@Z) が関数 "void __cdecl std::_Xlen_string(void)" (?_Xlen_string@std@@YAXXZ) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "void __cdecl std::_Xruntime_error(char const *)" (?_Xruntime_error@std@@YAXPEBD@Z) が関数 "public: __cdecl std::_Locinfo::_Locinfo(char const *)" (??0_Locinfo@std@@QEAA@PEBD@Z) で参照されまし た
test.obj : error LNK2019: 未解決の外部シンボル "bool __cdecl std::uncaught_exception(void)" (?uncaught_exception@std@@YA_NXZ) が関数 "public: __cdecl std::basic_ostream<char,struct std::char_traits<char> >::sentry::~sentry(void)" (??1sentry@?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAA@XZ) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル __std_exception_copy が関数 "public: __cdecl std::exception::exception(class std::exception const &)" (??0exception@std@@QEAA@AEBV01@@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル __std_exception_destroy が関数 "public: virtual __cdecl std::exception::~exception(void)" (??1exception@std@@UEAA@XZ) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "char const * __cdecl std::_Syserror_map(int)" (?_Syserror_map@std@@YAPEBDH@Z) が関数 "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::_Iostream_error_category2::message(int)const " (?message@_Iostream_error_category2@std@@UEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@H@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "void __cdecl std::_Facet_Register(class std::_Facet_base *)" (?_Facet_Register@std@@YAXPEAV_Facet_base@1@@Z) が関数 "class std::ctype<char> const & __cdecl std::use_facet<class std::ctype<char> >(class std::locale const &)" (??$use_facet@V?$ctype@D@std@@@std@@YAAEBV?$ctype@D@0@AEBVlocale@0@@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル _Getctype が関数 "public: struct _Ctypevec __cdecl std::_Locinfo::_Getctype(void)const " (?_Getctype@_Locinfo@std@@QEBA?AU_Ctypevec@@XZ) で参照されました
  定義済みの一致する可能性があるシンボルに関するヒント:
    "public: struct _Ctypevec __cdecl std::_Locinfo::_Getctype(void)const " (?_Getctype@_Locinfo@std@@QEBA?AU_Ctypevec@@XZ)
test.obj : error LNK2019: 未解決の外部シンボル _Tolower が関数 "protected: virtual char __cdecl std::ctype<char>::do_tolower(char)const " (?do_tolower@?$ctype@D@std@@MEBADD@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル _Toupper が関数 "protected: virtual char __cdecl std::ctype<char>::do_toupper(char)const " (?do_toupper@?$ctype@D@std@@MEBADD@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "public: static void __cdecl std::_Locinfo::_Locinfo_ctor(class std::_Locinfo *,char const *)" (?_Locinfo_ctor@_Locinfo@std@@SAXPEAV12@PEBD@Z) が関数 "public: __cdecl std::_Locinfo::_Locinfo(char const *)" (??0_Locinfo@std@@QEAA@PEBD@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "public: static void __cdecl std::_Locinfo::_Locinfo_dtor(class std::_Locinfo *)" (?_Locinfo_dtor@_Locinfo@std@@SAXPEAV12@@Z) が関数 "public: __cdecl std::_Locinfo::~_Locinfo(void)" (??1_Locinfo@std@@QEAA@XZ) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "private: static class std::locale::_Locimp * __cdecl std::locale::_Getgloballocale(void)" (?_Getgloballocale@locale@std@@CAPEAV_Locimp@12@XZ) が関数 "public: class std::locale::facet const * __cdecl std::locale::_Getfacet(unsigned __int64)const " (?_Getfacet@locale@std@@QEBAPEBVfacet@12@_K@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル _CxxThrowException が関数 "void __cdecl std::_Throw_bad_array_new_length(void)" (?_Throw_bad_array_new_length@std@@YAXXZ) で参照されました
test.obj : error LNK2001: 外部シンボル __CxxFrameHandler4 は未解決です
test.obj : error LNK2001: 外部シンボル __GSHandlerCheck は未解決です
test.obj : error LNK2019: 未解決の外部シンボル __security_check_cookie が関数 main で参照されました
test.obj : error LNK2001: 外部シンボル "const type_info::`vftable'" (??_7type_info@@6B@) は未解決です
test.obj : error LNK2019: 未解決の外部シンボル "private: static int std::locale::id::_Id_cnt" (?_Id_cnt@id@locale@std@@0HA) が関数 "public: __cdecl std::locale::id::operator unsigned __int64(void)" (??Bid@locale@std@@QEAA_KXZ) で参照されま した
test.obj : error LNK2019: 未解決の外部シンボル "public: static class std::locale::id std::ctype<char>::id" (?id@?$ctype@D@std@@2V0locale@2@A) が関数 "class std::ctype<char> const & __cdecl std::use_facet<class std::ctype<char> >(class std::locale const &)" (??$use_facet@V?$ctype@D@std@@@std@@YAAEBV?$ctype@D@0@AEBVlocale@0@@Z) で参照されました
test.obj : error LNK2019: 未解決の外部シンボル "class std::basic_ostream<char,struct std::char_traits<char> > std::cout" (?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A) が関数 main で参照されました
test.obj : error LNK2019: 未解決の外部シンボル __security_cookie が関数 main で参照されました
LINK : error LNK2001: 外部シンボル mainCRTStartup は未解決です
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\lib\x86\libcpmt.lib : warning LNK4272: ライブラリのコンピューターの種類 'x86' がターゲットのコンピューターの種類' x64' と競合しています
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.40.33807\lib\x86\LIBCMT.lib : warning LNK4272: ライブラリのコンピューターの種類 'x86' がターゲットのコンピューターの種類' x64' と競合しています
test.exe : fatal error LNK1120: 34 件の未解決の外部参照

ChatGPTにも聞きながら試してみたところ、以下をDeveloper Command Prompt for VS2022から実行することでこの問題が出なくなりました。

"C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat"

include, libの環境変数設定

以下のサイトを参考にINCLUDE、LIB、LIBPATHの環境変数を設定します。

WindowsキーからDeveloper Command Prompt for VS2022を起動し、
※Developer Powershell for VS2022ではうまくいかないためご注意ください。

以下コマンドでcl.exe用の環境変数を出力して、そのまま環境変数に貼り付けていきます。

>echo %INCLUDE%
>echo %LIB%
>echo %LIBPATH%
出力した結果
環境変数設定後

/EHscオプションのためのPowerShellでの独自関数設定

cl.exeのままコンパイルすると、毎回例外補足のために/EHscオプションをつけるように警告が出ます。しかし、毎回このオプションを打つのが面倒なため、PowerShellに独自関数として登録します。
今回は以下のようにコンパイルできるように関数名をcloとして登録します。

>clo main.cpp

まず初期状態ではセキュリティでPowerShellの独自関数が使用できないため、使用できるようにするために以下を実行します。実行するためのPowerShellは管理者モードで起動します。
※詳細を知りたい方はMicrosoft公式を参照

>Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

PowerShellのプロファイルに独自関数を定義していきます。PowerShellで以下コマンドを実行し、プロファイルファイルを作成します。その後、プロファイルファイルに独自関数を定義するためにメモ帳(notepad)でプロファイルファイルを開きます。

>New-Item -Type File -Path $PROFILE -Forc
>notepad $PROFILE

以下を書き込んで保存して、メモ帳を閉じます。

function Cl-WithEHsc {
    param(
        [string]$filename
    )
    
    & "cl.exe" "/EHsc" $filename
}
Set-Alias -Name "clo" Cl-WithEHsc
メモ帳で書いている様子

以下コマンドで、プロファイルファイルを読み込みます。次回以降はPowerShell起動時に自動で読み込まれるため、実行は不要です。

>.$PROFILE

atcoder-toolsの準備

atcoder-toolsというローカル環境での自動テストやAtCoderへのソースコード提出をしてくれるとても便利なツールを作ってくれている方がいます。
基本的にGitHubページの通りセットアップしていくだけですが、以下手順を簡単に説明します。

まず、atcoder-roolsをインストールします。pipで簡単にインストールできます。

>pip install atcoder-tools

コンテスト用の環境を構築します。今回は「競技プログラミングの鉄則」のテスト用のページを例に実行します。
※初めて実行する際またはログインセッションが切れている場合には、AtCoderへのサインインがコマンド上で求められます。

>atcoder-tools gen tessoku-book

ホームフォルダ(C:\Users\{Username})に「atcoder-workspace」というフォルダが作られ、その中にコンテストごとのフォルダが作られます(上記の場合には「tessoku-book」)。
「C:\Users\{Username}\atcoder-workspace」フォルダをVSCodeで開きます。

問題ごとにフォルダが作られ、その中にmain.cppというファイルがあるため、問題に合わせて回答を作成します。

A01の問題を解いた様子

コンパイルして実行ファイル(.exe)を作成します。

>clo main.cpp
clo関数でコンパイルした様子

提出前にテストします。

>atcoder-tools test
テストが無事通った様子

AtCoderへ提出します。一度提出済みの場合に再度提出する場合には、-uオプションを付けます。

>atcoder-tools submit
atcoder-roolsから提出した様子
AtCoder側で提出されたことを確認した様子

最後に

同様の環境構築をしている人の記事が見当たらなかったため、同じことをしたいと思った人が楽にできるように、今回記事にしてみました。
まずはある程度書籍を読み進めていきたいともいます。AtCoderへの本格参加はいつになるかわかりませんが、今回作った環境も使用しながら、地道に勉強を進めていきたいと思います。

この記事が気に入ったらサポートをしてみませんか?