組込み開発のスキル強化の目標をいくつか立てたので、しばらくC/C++を触ってみたい。
clangはコンパイラの一つである。LLVMのフロントエンドだ。C++の最新の言語仕様をいち早く実装していることでc++界隈では有名だ。C++erとしてこれは使ってみたいし、組込みにも使えたらうれしいと思っている。
C言語のコンパイラの定番といえば、WindowsならVisual Studio C++ Compiler、Linuxならgccであった。最近はgccに代わってclangが良く使われるようになってきている。しかし、IDEの完成度・デバッグの容易さといった総合的な開発環境はまだまだ前者の方が優れている気もする。
とはいえclangをローカル環境で使えたら勉強になるだろう。デバッガであるlldbだってコマンド操作を覚えればよい。IDEが欲しければ、Eclipseと連携させる方法がある。
ClangでコンパイルしたプログラムをWindows上で実行するにはWindows用のランタイムが必要だ。これはWindows SDKかに含まれているものを使うか、Windows向けGCCであるMinGWのランタイムを使うか、Cygwinレイヤを挟むかだ。
また、組込み用途の場合はクロスコンパイルが必要になる。すなわち、Windowsマシン上でLinux向け・ARM向けのバイナリを生成する環境を用意しないといけない。clang以前の問題だと感じるので、これはまたあとで対処したい。
LLVMをインストールした。1.1GBを消費する。
PS> clang -v
clang version 8.0.1 (tags/RELEASE_801/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
とりあえずコンパイルしてみる
適当なC++のコードをClangでコンパイルしてみた。
#include <iostream>
int main()
{
std::cout << "Hello clang" << std::endl;
return 0;
}
$ clang -o main.cpp main.exe
LINK : warning LNK4217: シンボル '__std_terminate' ('libvcruntime.lib(ehhelpers.obj)' で定義) が 'main-d95587.o' によって関数 '"int
`public: static unsigned __int64 __cdecl std::_Narrow_char_traits<char,int>::length(char const * const)'::`1'::dtor$2" (?dtor$2@?0??length@?$_Narrow_char_traits@DH@std@@SA_KQEBD@Z@4HA)' 内でインポー
トされています
LINK : warning LNK4217: シンボル '_CxxThrowException' ('libvcruntime.lib(throw.obj)' で定義) が 'main-d95587.o' によって関数 '"public: void __cdecl std::ios_base::clear(int,bool)" (?clear@ios_base@std@@QEAAXH_N@Z)' 内でインポートされています
このコマンドを使うとワーニングが消えた。
$ clang-cl -o main.cpp main.exe
あと次の省略形でもa.exe
が生成した。どういうコマンドが発行されているのだろうか。(-vで確認可能)
$ clang++ main.cpp
Visual Studio Codeと連携
折角なので、VSCodeと連携させてみたい。
VSCode側でC/C++のプロジェクト設定ファイルを作成すればよいのだが、clangを使った場合のincludePathが不明で困ってしまった。"Clang for Windows"は内部でMSVCを利用する。
情報が多いので、MinGW用のclangを導入することにした。MSYS2をインストールし、MinGWを使う。MinGWをそのままインストールしてMinGW-getしてもよかったが、多分MSYS2(cygwinみたいな)で取得したパッケージを使ってもいいと思う。
$ pacman -S mingw-w64-x86_64-clang --disable-download-timeout
MSYSでインストールしたパッケージはWindows上で直接呼び出すことができる。
PS C:\msys64\mingw64\bin> .\clang.exe -v
clang version 8.0.0 (tags/RELEASE_800/final)
Target: x86_64-w64-windows-gnu
Thread model: posix
InstalledDir: C:\msys64\mingw64\bin
他にもこの辺のパッケージを入れるとよさげ。
- mingw-w64-x86_64-make
- mingw-w64-x86_64-gcc
- mingw-w64-x86_64-gdb
- mingw-w64-x86_64-clang
- mingw-w64-x86_64-lldb
mingw-w64-x86_64-toolchainはada, object-c, fortranが入るので注意。
C:\msys64\mingw64\bin
にパスを通せば色々捗ると思うが、コマンドの衝突がちょっとだけ怖い。
インストールしたコンパイラへのパスをVSCodeから設定する。
VSCodeのc_cpp_properties.jsonを編集する。
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "\"C:/Program Files/LLVM/bin/clang.exe\"",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
変更後。
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "C:/msys64/mingw64/bin/clang.exe",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
compilerPath
を変更しただけなのだが、Intellisenseが働くようになった。これはどういう理由なのかよくわかっていない。Program
Files
以下にインストールした場合はパスにスペースが含まれているから、という可能性もありえる。
遊んでいて気付いたのだが、x86_64-w64-windows-gnu
とx86_64-w64-windows-msvc
は結構違う。MSVC版はclang
コマンドでcppファイルをビルドできる。Linuxだとclang++
を使わなければエラーになる。
VSCodeからClangを使ってビルドする
ビルド方法を設定するには
- clangコマンドを使う(普通使わない)
- makeファイルを書く
- cmakeファイルを記述する(クロスプラットフォーム向け)
がよさそう。