現在最新バージョンで gcc 9.1.0 がリリースされていますが、マイコンに関してはサポート状況がアーキテクチャによって異なるようです。
本記事では僕が現在(2019/7/15) PC に入っているマイコン用ツールチェインのバージョンやビルド方法について多少触れたいと思います。
「別に組込みで最新のコンパイラ使えなくてもいいじゃない」と思われるでしょう。
しかし、僕は新しいものがどうしても使いたいのです。だって C++2a したくないですか??
ということで、なるべく C++ が使えて、かつなるべく最新バージョンのツールチェインを使いたいという気持ちでこの記事を書いています。
ホスト環境
例によって Mac ですが、以下のような構成でビルドをします。gcc 等は Xcode に付いている clang
ではなく、GNU 生粋の gcc です。
- OS: macOS Mojave
- CC: GCC 9.1.0
- CXX: G++ 9.1.0
各環境のバージョン等
以下、特記無き場合は以下のツールチェインを用いています。
- binutils-2.32
- newlib-3.1.0
また、なるべく C++ の環境も欲しいので、極力ビルドするようにしています。本記事は基本的にすんなりビルドできたアーキテクチャでは説明はしません。苦労した点の記載となります。
各種 configure
コマンドは、以下のようで共通しています。
# binutils
$ ../configure --target=(対象アーキテクチャ) --prefix=/usr/local/cross/(対象アーキテクチャ名) --disable-werror --disable-nls --disable-bootstrap
# gcc(1回目)
$ ../configure --target=(対象アーキテクチャ) --prefix=/usr/local/cross/(対象アーキテクチャ名) --disable-werror --disable-nls --disable-bootstrap --disable-libssp --enable-languages=c,c++ --with-newlib
# newlib
$ ../configure --target=(対象アーキテクチャ) --prefix=/usr/local/cross/(対象アーキテクチャ名) --disable-werror --disable-bootstrap --disable-newlib-supplied-syscalls --enable-newlib-reent-small --disable-newlib-fvwrite-in-streamio --disable-newlib-fseek-optimization --disable-newlib-wide-orient --enable-newlib-nano-malloc --disable-newlib-unbuf-stream-opt --enable-lite-exit --enable-newlib-global-atexit --enable-newlib-nano-formatted-io --enable-target-optspace --disable-nls
# gcc(2回目)
$../configure --target=(対象アーキテクチャ) --prefix=/usr/local/cross/(対象アーキテクチャ名) --disable-werror --disable-nls --disable-bootstrap --disable-libssp --enable-languages=c,c++ --with-newlib --disable-libstdcxx-pch
また、ひょっとしたら newlib のビルド中に __attribute__((alias("hoge")))
関連で怒られるかもしれないので、その時は該当ソースコード開いて直接 __attribute__((weak, alias("hoge")))
と変更してください。
AVR
newlib ではなく、AVR ように最適化された独自の実装である AVR-libc を用いています。newlib に変えて、AVR-libcのビルドを行います。
$ ../configure --prefix=/usr/local/cross/avr --build=`../config.guess` --host=avr
これだと現状 g++
のビルドは出来ますが、libstdc++
のビルドはエラーで行えません(AVR-libc では公式に非サポートとされている)。ですが、8bit マイコンなのでそこまで必要ではないでしょうね。
近い内に newlib
での実装をビルドして libstdc++
を使えるようにしたいと思います。
(そういえば僕は AVR アセンブリばっかやってて、 C コンパイラ使ったこと殆ど無いんだった)
H8300
H8 マイコンのアーキテクチャです。こちらは2つのビルド状況を確認しています。
最新バージョン(Cのみ)
最新の gcc-9.1.0 を用いていますが、こちらは libstdc++ のビルドがうまくいかない ため、C言語のみの対応です。
ビット数を管理するソースファイルにて、std::size_t
の配列があるのですが、H8 アーキテクチャ上では std::size_t
のビット長が短いため、配列の要素が格納できないらしいです。
また、C++17 のメモリ管理機構において、コンパイル時の static_assert
に失敗します。これはもうどうしようもない。
8.3.0 (C & C++)
こちらのバージョンは現在最新の gcc 9.1.0 の1つ前のバージョンです。実はこれも libstdc++
のビルドで失敗します。
ですが、多少 Makefile
に手を加えることでビルドを完了することが出来ます。
具体的には、basic_string.h
で internal compiler error: unrecognizable insn
として怒られます。ヘッダが整っていないとか、環境がだめだとかじゃなくて、C++ 用ライブラリをビルドするための xgcc
で内部エラー(バグ?)が起きてしまっているのです。悲しい。
どのように回避するかと言うとそれは簡単で、エラーが起きたらh8300-elf/Makefile
の526行目にあるCXXFLAGS_FOR_TARGET
を-g -O0
に変えるだけです。最適化を切ることでこのエラーはなぜか起きなくなります。
最新バージョンではないですが、-std=c++17
が使えるのでまあいいでしょう。新しいからと言って C言語のためだけに 9.1.0 にする理由はありませんね。だって C は(おおむね)もう十分に枯れている言語ですから。
MSP430
TI の低消費電力マイコンに使われるアーキテクチャです。こちらは gcc 9.1.0 で問題なく C も C++ も利用できます。
M32C
このサブセットである、R8C を搭載したマイコンのために使っています。ルネサス的にはもう古いとみなしているようです。
gcc-6.4.0 で gcc が使えますが、ビルドに少々癖があります。
newlib ビルド時に、またしても internal compiler error で怒られるので、m32c_elf/Makefile
で CFLAGS_FOR_TARGET += -g -Os
とすればいいでしょう。
さらに、2回目の gcc ビルドで libstdc++-v3 を作るときにも internal compiler error になってしまいます。これについてはダメっぽいです。g++ はビルドできるのですが、libstdc++ができません。
RL78
RX の下位スペックを担うアーキテクチャです。gcc 9.1.0 で問題なく C も C++ も利用できます。
SH
古いマイコンである、SuperH です。皆さん知らないかもしれませんが、このマイコンは 32bit なんですよ。gcc 9.1.0 で問題なく C も C++ も利用できます。
ちなみに、32bit である証拠ですが...次のソースファイルをコンパイルします。
// b.c
int f(void) {
return sizeof(void *);
}
$ sh-elf-gcc -Os -c b.c
$ sh-elf-objdump -d b.o
中身はこんな感じになっています。確かに、4Bytes == 32bits ですね。
b.o: file format elf32-sh
Disassembly of section .text:
00000000 <_f>:
0: 00 0b rts
2: e0 04 mov #4,r0
RX
ルネサス主力のマイコンシリーズのうちの1つで、様々なモデルやアーキテクチャのバージョンが出ていて、今もなお版図を広げています。
gcc 9.1.0 で問題なく C も C++ も利用できますが、 gcc 公式のソースからビルドすると printf
系の関数を使うと %f
の処理でマイコンが止まってしまうという問題があります。
また、ビルド時に Fatal error: Infinite loop encountered whilst attempting to compute the addresses of symbols in section P と言われてエラーになることがあります。その時は rx-elf/libstdc++-v3/Makefile
の CXXFLAGS
, CXXFLAGS_FOR_TARGET
, CXXFLAGS_FOR_BUILD
に -mrelax
を追加してください。
こちらを参考にしました。
実際のところ、printf
の %f
をうまく処理させるためには GNU Tools から ななんと古代の gcc-4.9.4 をビルドするしか無いんですね〜〜
一応 C++ も使えますが、C++14 は一部のみの対応です。ですのでコンパイルオプションは -std=c++14
がサポートされておらず、-std=c++1y
とする必要があります。古代ですね。
ARM
arm-none-eabi
として使います。現在も続々と用いられているアーキテクチャのため、こちらも gcc 9.1.0 で問題なく C も C++ も利用できます。
MIPS
最近はあまり使われていませんかね。こちらも 32bit のアーキテクチャです。メジャーどころだと PIC32MX シリーズで用いられています。
gcc 9.1.0 で問題なく C も C++ も利用できます。
FT32
実は FTDI はマイコンも製造しているんですね。それ用のツールチェインです(ぶっちゃけよく分かっていない)。
gcc 9.1.0 で問題なく C も C++ も利用できます。
Xtensa
ESP32で利用されているコアです。ESP32 用のコンフィギュレーションで考えます(xtensa-esp32-elf)。
binutils と gcc のビルドはうまくいきます。一方で newlib でこのアーキテクチャはサポートされていないようで、configure
時に「そんなもの知らん」って怒られます。
ではどうするか?ですが、製造元の espressif が用意している newlib のアレンジ版を使うことになります(コメントありがとうございます!)。こちらが以下。
ビルド方法は本家のものと同一。ESP32 のメーカーページではすでにバイナリが配布されていますが、アレンジしたい!という方はこちらから是非どうぞ。
コメント
はじめまして。ESP32ではnewlib-esp32(ttps://github.com/espressif/newlib-esp32)を使用するとビルドに成功しました。
参考にnewlib-esp32を使って作ったgccの-vを示します。
Using built-in specs.
COLLECT_GCC=/usr/local/cross/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc
COLLECT_LTO_WRAPPER=/usr/local/cross/xtensa-esp32-elf/libexec/gcc/xtensa-esp32-elf/10.2.0/lto-wrapper
Target: xtensa-esp32-elf
Configured with: /home/username/xtensa-esp32-elf/gcc-10.2.0/configure --target=xtensa-esp32-elf --prefix=/usr/local/cross/xtensa-esp32-elf --disable-bootstrap --disable-libssp --disable-nls --enable-languages=c,c++ --enable-threads=posix --with-newlib --with-pkgversion='GCC:v10.2.0, newlib-esp32:esp_based_on_3_0_0-1590f7f, date:20200905'
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (GCC:v10.2.0, newlib-esp32:esp_based_on_3_0_0-1590f7f, date:20200905)
詳細に情報ありがとうございます。そうでした。メーカー独自のアレンジ版で出来たんですね。
記事本文に追記させていただきます。
ちなみに現状、本家のnewlib-3.3.0でもxtensaはビルドできないようです。こちらもご参考まで。
返信が遅れてしまいすみません。
こちらの環境でv3.1~3.3まで念の為一通り試しましたが、いずれも同様のエラーでした。
さて話は変わりますが、今現在8bit AVR用に本家newlibをビルドしようとしているのですが、avr-arの処理中にstdio/lib.aやstrlib/lib.aが見つからず(1>/dev/nullした限りでは一部のソースがコンパイルエラーしてlib.aが生成できず404になったと思われます)ビルドに失敗するようです。こちらの環境だけかはわかりませんが、参考までにしていただければと思います