C++初心者Advent Calendar 2015
この記事はC++初心者Advent Calendar 2015 9日目の記事です
<< 8日目 | C++のポインタ渡しと参照渡しの使い分け](http://cocodrips.hateblo.jp/entry/2015/12/08/221722) || [10日目 | テンプレートでコケた話 >>
17日目 | C99からC++14を駆け抜けるC++講座 >>
個人的には、歌舞伎座.tech #8 「C++初心者会」とか見て以降、「初心者」が怖くなってしまっていますが(初心者がBoost.asioをつかえるもんか!)、ここまでは初心者向けでものすごくホッとしています。初日の
初心者が C++ を勉強するときに最低限押さえておいたほうがよい C++11/14 の機能
を除いてですが(最近の初心者は継承が使えるのか・・・怖い)
8日目 | C++のポインタ渡しと参照渡しの使い分けとかはさっぱりしていてわかりやすいのではないでしょうか。なので見ろ(ぇ)。
以下、4日目のC++を始めよう for windows - Qiitaを見ている前提で話が進みます。見てない方は先にどうぞ。
追記
現在、Clang with Microsoft CodeGenのclangのバージョンが3.8のままな気がします。最新のclangのほうが絶対良いと思われるので、 @kazatsuyu さんのfafnir
というツールを使うことをおすすめします。詳細は
はじめに
先日Clang with Microsoft CodeGenなるものが出た。なのでこれはなにかという話と、そもそもコンパイラって?というお話から書いていこうと思います。
で、MSの名前が出た時点で察しですが、for Windowsな記事となっています。え?Linux?Mac?おめーら、優秀なコンパイラあんだろーが。
目的
- Clangの存在を世に広める
- 最近はMSも頑張ってることを伝える
- おのれMS
・・・いやですね、
C++を始めよう for windows | Qiita
で、Visual Studioの紹介自体はあったので。これは書かねばなるまいということで。
だって、gccの扱いが
gccはLinux等でよく使われるコンパイラですが、今は忘れてもかまいません。
でclangに至っては記述なしですからね、これは宣伝せざるを得ません(謎の使命感)
コンパイラとは
コンパイラとは特定言語で書かれたコードを機械言語、ないしもとより下位の言語(中間言語)に翻訳するものです。
有名なコンパイラとしては
- gcc/g++
- clang/clang++
- Visual Studio付属のcl.exe
- icc
などでしょうか。(bcc32.exeなんてなかった)
この後話すClang with Microsoft CodeGenとは細かい話を抜けば、Visual StudioをIDEとしてつかいつつ、コンパイラだけClangに差し替える、というものです。
Clang(クラン)とは
もともと、iPhoneで有名なAppleがLLVMという中間言語を経由してC/C++のコードをコンパイルするプロジェクトを立ち上げたものです。gccとちがいマルチスレッドで動作も高速、LLVMを使うことによりgccより最適化がし易いなどなどの特徴があります。なおgccがGPLv3というライセンスなのに対し、ClangはUniversity of Illinois/NCSA Open Source Licenseというライセンスで、コピーレフト絶対主義者の自由ソフトウェア主義者からは妬まれています。パルパル。
- Clang - Wikipedia
- LLVM Clang の Windows へのインストールと使い方 | プログラマーズ雑記帳
- LLVM/Clangがぜってーサポートしねーと宣言しているLinuxカーネルに多用されているGCC拡張 | 本の虫
C++に関しては、後発のコンパイラにもかかわらず、もっともC++規格準拠がはやいコンパイラとなっています。まあ細かいバグはあるんですが。
これまでのWindowsでClangを利用する方法
msys2 mingw clangをつかう
多分これが一番はやいと思います。今でも。
- 7-Zipを落とす
https://sevenzip.osdn.jp/
より64bit版もしくは32bit版を
既に入っている人も、2015/11/19に随分久しぶりに最新版が出たのでバージョンを上げるといいです - 7zipをインストール
ダブルクリックして実行すればいいです。 - msys2を落とす
http://sourceforge.net/projects/msys2/files/Base/
よりお使いのアーキテクチャ(おそらくはx86_64)をクリックしmsys2-base-[アーキテクチャ]-[日付].tar.xz
を。exeの方は1回も使ったこと無いのでわかりません。
4. 7-zipで解凍
5. msys2_shell.cmd
をダブルクリック、Close Window
と言われたらばってんを押して閉じる
6. 再びmsys2_shell.cmd
をダブルクリック、pacman -Syuu
と打ち実行、また閉じる
7. 再びmsys2_shell.cmd
をダブルクリック、pacman -S mingw-w64-i686-clang mingw-w64-x86_64-clang
とと打ち実行、また閉じる
8. コマンドプロンプトでmsys2_shell.cmd
のあるパスに移動し、call msys2_shell.cmd -mingw64
(64bit向けのコンパイル)またはcall msys2_shell.cmd -mingw32
(32bit向けのコンパイル)を実行mingw64
(64bit向けのコンパイル)またはmingw32.exe
(32bit向けのコンパイル)を実行
9. clangコマンドが使える!
mingwを自力で入れてさらにclangを入れる
Cドライブ直下にmingwを置かないといけなくて、シンボリックリンクではダメだったので私はやっていません
Visual Studioを導入してからClangを入れる
VSが入っている状態で
http://llvm.org/releases/download.html
Clangを入れるとVisual StudioからもClang-clが使えるようになる
Clang with Microsoft CodeGen
- Clang with Microsoft CodeGen(clang 3.7)(preview 1)
- Clang with Microsoft CodeGen(clang 3.7)(January 2016)
- Clang with Microsoft CodeGen(clang 3.7)(February 2016)(Update2 previewにあったぽい?)
- Clang with Microsoft CodeGen(clang 3.7)(March 2016)
- Clang with Microsoft CodeGen(clang 3.8)(May 2016)
- Clang with Microsoft CodeGen(clang 3.8)(July 2016)
なぜClang with Microsoft CodeGenか
こうした方法があったわけですがどれもいまいちでした。最初のmsys2を使うものは、ついでにgccも入って便利ではあるんですが、コンパイルはコマンドラインなので、makefileを書かねばならず、んなもん初心者に書けるか、というお話です。かと言ってVSをいれてからClangを入れる方法ははっきり言って実験段階というか、VSとの連携が不十分でした
そして、最大のメリットは、Visual Studioの唯一の利点、優秀なデバッグ機能がフルに使えるということです。あのデバッグ機能がなければ、誰ひとりとしてあんな糞コンパイラ使ってないでしょう。
Clang with Microsoft CodeGenの仕組み
ではこのClang with Microsoft CodeGenはどのようにコンパイルがなされるのでしょうか。
コンパイラ名 | flow |
---|---|
mingw clang | ソースコード→LLVM IR→実行ファイル |
VS default | ソースコード→MS独自の中間言語→実行ファイル |
Clang with Microsoft CodeGen | ソースコード→LLVM IR→MS独自の中間言語→実行ファイル |
こんな感じです。(だれか図をください)
なお
Visual StudioにClangフロントエンドがやってくる
http://cpplover.blogspot.jp/2015/10/visual-studioclang.html
MS独自のプロプライエタリなTwo-phase lookupすらまともにできない規格違反のクソC++コンパイラーの開発も続行されるらしい。
某友人はこれを聞いて思わずFワードを吐いていました。大丈夫だ、気持ちはわかる。
以下の内容を動画化した
ぶっちゃけわかりにくいので、動画にしました。
【ゆっくり実況】Clang with Microsoft CodeGenの導入実況 - ニコニコ動画:GINZA
どうぞ御覧ください。(宣伝乙とか言わない)
じゃあ導入するか
-
https://www.visualstudio.com/ja-jp/downloads/download-visual-studio-vs.aspx
に行き、
ダウンロードする
そして実行する
カスタムインストールか否かが出たらカスタムインストールに。 -
選択画面が出たら
クロスプラットフォームモバイル開発
→Visual C++モバイル開発
→Clang with Microsoft CodeGen(2016年1月)
にチェックをつける
プログラミング言語
→Visual C++
にチェックが付いているか確認する
-
インストール。気長に待つ
どうやって使うか
新しいプロジェクト→インストール済み→Visual C++→クロスプラットフォーム
にstatic/dynamic libraryをClangで作れるものがありますが、そんなもの初心者はお世話にならないので
http://qiita.com/cpp_maid_BOT/items/13eab3a134e3f6794f07
「新しいプロジェクト > Visual C++ > Win32コンソールアプリケーション」で名前を適当に
アプリケーションの種類を「コンソールアプリケーション」追加のオプションを「空のプロジェクト」にチェックを入れ完了します
そして「ソリューションエクスプローラーからソースファイルを選び右クリック > 追加 > 新しい項目 > C++ファイル名前mainで追加」
でいいです(ちなみに[Ctrl]+[Shift]+[A]なんて便利なショートカットもあるんやで。)
ここからが大事です
- プロジェクト→xxxのプロパティ→構成マネージャを開く
- アクティブソリューション構成→新規作成で、設定のコピー元が空の状態で適当な名前をつけて構成を作成します。私は
clang_Debug
とclang_Release
の2つを追加しています。 - 構成マネージャを閉じます
- そのままプロパティページが開いていると思うので、プラットフォームを
x64すべてのプラットフォームに、構成→複数の構成で先ほど作った構成のみチェックをつけます - 構成プロパティ→全般
にある
プラットフォームツールセット
を
Clang 3.7 with Microsoft CodeGen (v140_clang_3_7)
Visual Studio 2015 - Clang with Microsoft CodeGen (v140_clang_c2)
にします - ~~構成プロパティ→C/C++→コード生成→C++の例外を有効にする を「はい」に。(テーブルをアンウィンドってなんだ)~~Clang with Microsoft CodeGen (January 2016) でデフォルトで有効になりましたね
- 構成プロパティ→C/C++→全般→デバッグ情報の形式で
完全なデバッグ情報 (DWARF2) (-g2 -gdwarf-2)
を選択
あとはコード書くだけです。
コードは
http://faithandbrave.hateblo.jp/entry/20131119/1384837618
より。
constexpr void square(int& x)
{
x *= x;
}
constexpr int f(int x)
{
square(x);
return x;
}
こんなコードももちろん動きます。あとは
https://gist.github.com/yumetodo/dad352ffdc27c19cf825
こんなコードとか。
注意
IntelliSense
IntelliSenseは対応していません。いっその事IntelliSenseを切ってもいいかもしれません。
Windows.hについて
追記:いつの間にやら修正されました。
多分7月版からだと思うんだけど、Windows.hをincludeすると
Windows Kits\8.1\Include\um\combaseapi.h(229,21): error : unknown type name 'IUnknown'
static_cast<IUnknown*>(*pp); // make sure everyone derives from IUnknown
とか怒られるようになりました。というわけで使うときは
#if !defined(CINTERFACE) && defined(__c2__) && __clang_major__ == 3 && __clang_minor__ == 8
//To avoid compile error
//C:\Program Files (x86)\Windows Kits\8.1\Include\um\combaseapi.h(229,21): error : unknown type name 'IUnknown'
// static_cast<IUnknown*>(*pp); // make sure everyone derives from IUnknown
struct IUnknown;
#endif
#include <Windows.h>
としましょう。
詳細
Clang with Microsoft CodeGen(2016/07版)でWindows.hを使うときに注意すべきこと
http://qiita.com/yumetodo/items/a8c408078766a5c81e31
asm
https://blogs.msdn.microsoft.com/vcblog/2015/12/04/clang-with-microsoft-codegen-in-vs-2015-update-1/#known-issues-in-the-first-preview
No inline asm on any architecture. You will get a diagnostic that says “Inline assembly is not supported” or “GNU-style inline assembly is disabled”
アセンブリ使えません。全滅です。SIMDとかは試してないけど手動ではできないんじゃね?今後に期待。
試しましたが、そもそも__cpuid
が使えないです。
ちゃんとc:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\Clang 3.7\include\Intrin.h
に
static __inline__
void __cpuid(int[4], int);
static __inline__
void __cpuidex(int[4], int, int);
とかいてあるにもかかわらず
error LNK2019: 未解決の外部シンボル "void __cdecl __cpuid(int * const,int)" (?__cpuid@@YAXQAHH@Z) が関数 "struct regs_t __cdecl get_cpuid(unsigned int)" (?get_cpuid@@YA?AUregs_t@@I@Z) で参照されました。
おい、どういうことだ、Link errorにするくらいなら最初っからヘッダーつけんなばーか。しかもヘッダーでは
#ifdef __cplusplus
extern "C" {
#endif
されてんのにlink error messageが?__cpuid@@YAXQAHH@Z
ってお前何を探してやがるんだ
と言った状況からはClangが3.8にあがった5月版から改善したようで、例えば__cpuid
は使えるようになりました(GNU Styleの5引数の__get_cpuid
のみで__cpuid
はただのalias)。
SIMD Intrinsic は相変わらず使えません。というのも、コンパイラにIntrinsic not yet implemented
とか言われます
ヘッダー見てる感じVS-Style、GNU-styleどっちも使えそうだったから(例えば_rdrand32_step
と__builtin_ia32_rdrand32_step
)行けるのかとおもいきやダメでした。-msse2
とか-mrdrnd
とか-march=native
も効きませんでしたとさ。
tchar
Clang with Microsoft CodeGenを使う際、tchar.hをWindows.hより先にincludeしてはならない
なぜかというと、
C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\tchar.h
がincludeされるのだが、
#ifndef _TCHAR_DEFINED
#if !__STDC__
typedef wchar_t TCHAR;
#endif /* !__STDC__ */
#define _TCHAR_DEFINED
#endif /* _TCHAR_DEFINED */
#ifndef _TCHAR_DEFINED
#if !__STDC__
typedef char TCHAR;
#endif /* !__STDC__ */
#define _TCHAR_DEFINED
#endif /* _TCHAR_DEFINED */
#ifndef _TCHAR_DEFINED
#if !__STDC__
typedef char TCHAR;
#endif /* !__STDC__ */
#define _TCHAR_DEFINED
#endif /* _TCHAR_DEFINED */
のようになっていて、TCHAR型が使えない。なぜならClang with Microsoft CodeGenでは__STDC__
マクロがdefineされるからだ。逆に言えば、MSVCは
https://msdn.microsoft.com/ja-jp/library/b0084kay.aspx
ANSI/ISO C99 規格への準拠を示します。 /Za コンパイラ オプションが指定され、C++ コードをコンパイルしていない場合のみ、整数リテラルの定数 1 として定義されます。それ以外の場合は、定義されません。
と、定義されていないので使えるのである。しかも
#define _TCHAR_DEFINED
の一文のせいで、例えばWindows.hをincludeした時にこっちのTCHAR型まで無効化するのである。おのれMS。
コメントで、コンパイラオプションでマクロ__STDC__
を0にdefineするといった方法が紹介されています。
https://connect.microsoft.com/VisualStudio/Feedback
http://blogs.msdn.com/b/vcblog/archive/2015/12/04/introducing-clang-with-microsoft-codegen-in-vs-2015-update-1.aspx
どっちにバグレポ投げればいいの?
https://connect.microsoft.com/VisualStudio/feedback/details/2122400
(いつの間にかMSのバグ報告の場所が変わってしかもURL死にやがったのでWeb Archiveでどうぞー)
MSにバグレポ投げました。この英語力のなさ、どうにかしたい。
追記
投稿者: James [MSFT]、投稿日時: 2016/01/12 6:06
Hello,
Thank you for reporting this issue. We've fixed this; the fix will appear in a future release of the Windows SDK.
Sincerely,
James McNellis
Visual C++ Libraries
james.mcnellis@microsoft.com
ほう、fixされるらしいぞ。やったね。でもWindows SDKの更新ってそれいつよ。
Debug
ちゃんとステップ実行もできます。できるんですが!逆アセンブルウィンドウも使えますが!何故にや知らん、スタックトレースしてくれません。辛い。-g
つけてコンパイルしてませんでした、ちゃんと動きます
例外
http://blogs.msdn.com/b/vcblog/archive/2015/12/04/introducing-clang-with-microsoft-codegen-in-vs-2015-update-1.aspx
When changing from MSVC toolset, exception handling is currently off-by-default even though exception handling works. The developer can override this switch manually. The default will change in the next release.
例外を使うコードはデフォルト設定では使えない。上にも書いたとおり、構成プロパティ→C/C++→コード生成→C++の例外を有効にする を「はい」にする必要がある。次のリリースではデフォルトで有効になるようですが。
またx86(Win32)アーキテクチャの例外処理はバグが多いと誰かが言っていたので避けたほうが賢明かもしれない。
'_Ty' does not refer to a value
Visual Studio 2017(_MSC_VER
が1911
らへん)の場合、
In file included from C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\exception:7:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\type_traits(898,47): error : '_Ty' does not refer to a value
: bool_constant<__is_trivially_destructible(_Ty)>
^
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\type_traits(896,16) : note: declared here
template<class _Ty>
^
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\type_traits(899,2): error : expected class name
{ // determine whether _Ty has a trivial destructor
^
2 errors generated.
のようなエラーが出ます。
これはClang with Microsoft CodeGenのclangがVSのコンパイラ拡張の__is_trivially_destructible
に対応していないため。新しいclangを自力で入れて使えば大丈夫っぽいです。
- https://bugzilla.mozilla.org/show_bug.cgi?id=1423307
- https://stackoverflow.com/questions/47680258/clang-c2-on-visual-studio-15-5-bool-constant-is-trivially-destructible-ty-e
Breaking Change
プラットフォームツールセットの名前がClang 3.7 with Microsoft CodeGen (v140_clang_3_7)
からVisual Studio 2015 - Clang with Microsoft CodeGen (v140_clang_c2)
に変更になっています。プロジェクトの設定を変えないとコンパイルできなくなっていますのでご注意。
結論
- Clang with Microsoft CodeGenの導入に成功し、それを記事にしたことでClangの存在を世に広める事ができた(?)
- Clang with Microsoft CodeGenという取り組みを伝えることで、最近はMSも頑張ってることを伝えることができた
- おのれMS
- __cpuid使わせろ
C++初心者Advent Calendar 2015
この記事はC++初心者Advent Calendar 2015 9日目の記事です
<< 8日目 | C++のポインタ渡しと参照渡しの使い分け](http://cocodrips.hateblo.jp/entry/2015/12/08/221722) || [10日目 | テンプレートでコケた話 >>
17日目 | C99からC++14を駆け抜けるC++講座 >>
次はringoh72さんのテンプレートでコケた話ですね。今日も私はtemplateには苦しめられたので楽しみです。よろしくお願いします。