以前こちらの記事で Mac(Linux でも行ける)での環境構築を行い、各種不都合な点があったと書きました。これらの点について進捗が(無限小で)存在するのでこちらに書きます。適宜追記するかも。
ライブラリのコピーにWindowsが必要になる件
「printf 系のライブラリを用いるのに Windows が必須だよ」と書いたわけですが(そこまで言ってないが、そういう意図があった)、実際色々やってみたら Windows なしで出来ました。どうして必要だと言ったかというと、実は別の問題でソフトウェアが上手く動かず、それを Windows じゃないせいだと思いこんでいたことが原因としてあります。ですので Windows は窓から投げ捨てても OK です。
では以前の記事で公開されているプロジェクトを脱 Windows するにはどうすればいいかというと、とりあえず HardwareDebug
のなんちゃら.a というファイルを消してください。そして MakeFile にて 該当する -l
オプションを削除します。
続いて newlib の標準ライブラリを使うために以下を --start-group
から --end-group
の間に追加してください。
-lg -lc
これだけで脱 Windows できます。ですが、このままだと sci.c 等にある vsprintf
が上手く動かない...なので次の項を見てください。
sbrk.c がバカ
ルネサス公式のファイルをそのままパクっといてアレですが、sbrk.c (ヒープ領域処理用の関数がある)のメモリ構造がバカです。問題の箇所はこちら。御覧ください。
union HEAP_TYPE {
_SDWORD dummy ; /* Dummy for 4-byte boundary */
_SBYTE heap[HEAPSIZE]; /* Declaration of the area managed by sbrk */
};
上の構造体は上に述べたようにヒープ領域およびその前にあるダミー領域をまとめて定義しているものです。この時点でお気づきの方は多いでしょうが、そう、何故か union
になっています。union
は1つ目のメモリ要素を2つ目以降の項目で分割して扱うものですから(すみません説明下手で)、これではダメダメです。解決策は簡単で、union
を struct
に変えるだけです。定義部も同様に直しておいてください。
2018/3/23 追記:
コメントよりご指摘頂きました。こちらはC言語の仕様の範囲でヒープ領域をワード境界に配置するためのテクニックだそうです。存じ上げませんでした。ありがとうございます。そして何よりこの sbrk.c を書いた方、バカとか言って申し訳ありません。。。
尤も、この sbrk.c を使わない という方法もあります。代わりに libnosys.a というものがあるので、こちらで代用することが可能です。
これを用いる方法は以下のようにします。
- sbrk.c を削除または拡張子を
.old
等に変える --start-group
から--end-group
の間に-lnosys
を入れるUSER_OBJS
に-L"/usr/local/rx-elf/rx-elf/lib"
を追加
これで再度 make
してもらえばいいと思います。
newlibによるprintf系関数の挙動が微妙
追記(2018/5/2): **
**続報があります。原因が判明し解決法も分かりました。
こちらも脱 Windows したことで生まれる不具合です。この現象は僕は vsprintf
を使っている時に遭遇し苦労しました。実際のコードをお見せしましょう。以下は UART での書式指定用に作った printf っぽい関数です。
void uart_printf(const char *format, ...) {
va_list arg;
va_start(arg, format);
char buf[128];
vsprintf(buf, format, arg);
char *p = buf;
while( *p != '\0' ) {
uart_send(*p);
p++;
}
va_end(arg);
}
脱 Windows した環境ではこれ、動きません。vsprintf
実行時に止まってしまいます。
ではどうするかです。原因未解決ですが、とりあえず work around を示しておきましょう。
bufの要素数を減らす
要素数を 64 にした所、動き始めました。よくわからないですが。
buf の定義を変える
つまり char buf[128];
と記述しない、ということです。ではどうするか...
第一に malloc()
を使ってしまうというものがあります。組み込みで malloc()
なんて本当は使いたくないですが、とりあえずこれで要素数128は余裕でできているみたいです。もしこれを使うのなら、速度の観点で static
にすることをお勧めします。
static char *buf = (char *)malloc(sizeof(char) * 128);
第二にグローバル領域に定義しておくというものです。こちらが一番のおすすめですね。そしてこの変数はグローバル用途には使わないと思うので、上と同様に static
にしてしまいましょう。
newlibによるprintf系関数の%f
が使えない
使えないです。フリーズします。ということなので、皆さん浮動小数用の代替関数作りましょうね!!!!!
コメント
初めまして。
興味深い記事を多く書かれているのでRSSリーダに登録させていただきました。
ところで、sbrk.c がバカの件ですが、HEAP_TYPE の dummy はヒープ領域のレイアウトをワード境界に配置するよう強制するためのテクニックです。
今の時代コンパイラやリンカの機能で整列させてもいいのですが、C言語の仕様の範囲で確実に機能するので割と使われています。
dummy 自体参照されないので領域を割り当てる必要はありません。
union で間違いではないです。
RSS登録、ありがとうございます!!
ここで配置が行われているとは、、、存じ上げませんでした〜
ご指摘大変ありがたいです。勉強させていただきました。
今年からちょっと忙しくなるかもということで更新頻度が落ちる可能性がありますが、今後とも是非!よろしくお願いいたします。