質問: Spresense を ArduinoIDE で使用しています。 未使用関数等が多いライブラリを使用時のプログラムサイズ削減の方法について質問します。 U8g2 などの未使用のフォントデータ等が多いライブラリを使用する際、プログラムサイズを超過することがありました。そのため、コンパイル・リンカオプションで未使用関数等の削除を行うよう設定したところ、実行時に異常終了してしまいます。ライブラリを使用しないシリアル出力だけのコードでも異常終了するため、オプションでの削除は不可能のようです。 ライブラリから必要なコードだけ抜き出して使用する以外で、なにか解決方法はありませんでしょうか? ◆"platform.txt" 変更内容 compiler.c.flags : -ffunction-sections -fdata-sections を追加 compiler.cpp.flags : -ffunction-sections -fdata-sections を追加 compiler.c.elf.flags : -Wl,--gc-sections を追加 ◆サンプルコード ``` #include //あってもなくても異常終了する void setup() { Serial.begin(115200); Serial.println("START"); } void loop() { } ```
回答: gc-sections オプションによる関数・データ単位の削除が使えそうにないので、オブジェクト単位で削除するしかなさそうです。 library.properties に ``` dot_a_linkage=true ``` を追加して.aファイル化すれば、不要な.oファイルはリンクされなくなるのでコードサイズが削減できるかもしれません。 私も U8g2 ライブラリで同じ問題にハマりました。。 dot_a_linkage=true 追加で、自分のアプリはビルドできるようになりましたが、U8g2.a アーカイブ化しても未使用フォントデータがすべてリンクされてしまうので、かなりのメモリサイズを無駄に喰っています。 やっぱり必要な font だけ抜き出して使うしかなさそうです。 以下は少々手順が複雑ですが、fontごとにファイルを分割してみた例です。 ``` ### src/clib ディレクトリ下で作業 $ cd src/clib ### u8g2_fonts.cファイルを分割するスクリプト(かなりやっつけですが^^; $ cat split_u8g2_fonts.awk { if(NR>5){ if(/^\/\*/) { fn=sprintf("u8g2_font_%04d.c",++num); print "#include \"u8g2.h\"" >> fn } print >> fn; } } ### u8x8_fonts.c も $ cat split_u8x8_fonts.awk { if(NR>5){ if(/^\/\*/) { fn=sprintf("u8x8_font_%04d.c",++num); print "#include \"u8x8.h\"" >> fn } print >> fn; } } ### ファイル分割 $ awk -f split_u8g2_fonts.awk u8g2_fonts.c $ awk -f split_u8x8_fonts.awk u8x8_fonts.c ### オリジナルファイルを削除 $ rm u8g2_fonts.c u8x8_fonts.c ``` ここまでしてからビルドすれば未使用フォントもリンク時に削除されてプログラムサイズも妥当な値になりました。 **(追記)** U8g2 ライブラリ本体を変更するのでない限り、上記の方法で一回作成した U8g2.a を取っておいて、precompiled オプション(Arduino IDE 1.8.6 以降)を使うのもアリかもしれません。 U8g2/library.properties から dot_a_linkage を削除して、precompiled=trueを追加。 ``` precompiled=true ``` 作成済みの U8g2.a を U8g2/src/spresense へコピー ``` ### コピー $ mkdir src/spresense $ cp your/U8g2.a src/spresense ### .cpp や .c ファイルをバッサリ削除 $ rm src/*.cpp src/clib/*.c ``` この状態でスケッチをビルドすれば、U8g2.a はリンクするだけになって快適に使えます。