52266


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 を追加

◆サンプルコード

[code]

    #include <U8g2lib.h> //あってもなくても異常終了する
    void setup() {
      Serial.begin(115200);
      Serial.println("START");
    }
    void loop() {
    }
    
[/code]


CC BY-SA 4.0
2019-01-02T14:28:31.470
51664
2019-01-23T16:52:11.763
2019-01-02T14:30:09.000
76
31644
question
arduino spresense
ArduinoIDE環境でライブラリ使用時の未使用関数等の削除について


そのオプションはどこからも参照されない関数や変数を生成しないというものなので、割り込みハンドラ関数などは軒並み削除対象となってしまいます  
必要な割り込みハンドラは削除しないように指定する必要がありますね


CC BY-SA 4.0
2019-01-03T07:30:45.790
51676
2019-01-03T07:30:45.790
27481
51664
answer


gc-sections オプションによる関数・データ単位の削除が使えそうにないので、オブジェクト単位で削除するしかなさそうです。

library.properties に

[code]

     dot_a_linkage=true
    
[/code]

を追加して.aファイル化すれば、不要な.oファイルはリンクされなくなるのでコードサイズが削減できるかもしれません。

私も U8g2 ライブラリで同じ問題にハマりました。。

dot_a_linkage=true 追加で、自分のアプリはビルドできるようになりましたが、U8g2.a
アーカイブ化しても未使用フォントデータがすべてリンクされてしまうので、かなりのメモリサイズを無駄に喰っています。

やっぱり必要な font だけ抜き出して使うしかなさそうです。

以下は少々手順が複雑ですが、fontごとにファイルを分割してみた例です。

[code]

    ### 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
    
[/code]

ここまでしてからビルドすれば未使用フォントもリンク時に削除されてプログラムサイズも妥当な値になりました。

**(追記)**  
U8g2 ライブラリ本体を変更するのでない限り、上記の方法で一回作成した U8g2.a を取っておいて、precompiled オプション(Arduino
IDE 1.8.6 以降)を使うのもアリかもしれません。

U8g2/library.properties から dot_a_linkage を削除して、precompiled=trueを追加。

[code]

    precompiled=true
    
[/code]

作成済みの U8g2.a を U8g2/src/spresense へコピー

[code]

    ### コピー
    $ mkdir src/spresense
    $ cp your/U8g2.a src/spresense
    
    ### .cpp や .c ファイルをバッサリ削除
    $ rm src/*.cpp src/clib/*.c
    
[/code]

この状態でスケッチをビルドすれば、U8g2.a はリンクするだけになって快適に使えます。


CC BY-SA 4.0
2019-01-23T01:51:48.923
52225
2019-01-23T01:58:19.437
2019-01-23T01:58:19.437
31378
31378
51664
answer


改めて gc-sections オプションが使えない理由を調べてみました。

> ◆"platform.txt" 変更内容  
>  compiler.c.flags : -ffunction-sections -fdata-sections を追加  
>  compiler.cpp.flags : -ffunction-sections -fdata-sections を追加  
>  compiler.c.elf.flags : -Wl,--gc-sections を追加

を付けたときに、グローバルコンストラクタのテーブルが削除されてしまい、それに起因して実行時にエラーが発生していたようです。

リンクスクリプトファイル  
Arduino15/packages/SPRESENSE/tools/spresense-
sdk/1.x.x/spresense/release/prebuilt/build/ramconfig.ld  
Arduino15/packages/SPRESENSE/tools/spresense-
sdk/1.x.x/spresense/debug/prebuilt/build/ramconfig.ld  
の .init_array を KEEP()で囲むことで、

[code]

    *(.init_array .init_array.*) → KEEP (*(.init_array .init_array.*))
    
[/code]

実行時のエラーがなくなりました。

解決方法としてこちらの方が良さそうです。


CC BY-SA 4.0
2019-01-23T16:52:11.763
52266
2019-01-23T16:52:11.763
31378
51664
answer