はじめに
2020/3/6 追記
PlatformIOでframeworkをmbed
にすると必要のない機能のソースコードもコンパイルするため、
ビルド時間がかなり長くなってしまう。
| Mbed for STM32 compiles toooooo long | mbed + PlatformIO = too long compilation
これは度々話題に挙げられていて.mbedignore
で不要なソースをフィルタできると答えが出るのだが、
.mbedignore
は適切な場所に配置しないと効力を発揮しないことと、
適切な配置場所の具体的な例が乏しいため、実際のところ使いづらい。
いろいろ試した結果、.mbedignore
でビルド時間の短縮に成功した。しかし、毎回手でこれを行うが面倒なので
PlatformIOのextra_scriptsの機能を使用して、プロジェクト毎に簡単に使用できるようにしてみた。
.mbedignoreファイル
まず、.mbedignore
ファイルについて説明する。
mbed osのソースツリーに配置することで、使用しない機能のソースファイルをビルドから除外することができる。
ただしソースツリーのルート直下に配置された.mbedignore
は無視されてしまう。
.mbedignoreの内容を正しく適用するにはその一段下のディレクトリにそれぞれ配置する必要がある。
. ├── TESTS ├── TEST_APPS ├── UNITTESTS ├── cmsis ├── components ├── docs ├── drivers ├── events ├── features ├── hal ├── platform ├── platformio ├── rtos ├── targets └── tools
例えば、features/cellular/*
をビルド対象から外したい場合は、features
ディレクトリに次の内容で.mbedignore
を作成する必要がある。
cellular/*
extra_scripts
PlatformIOではmbedフレームワークのソースツリーは${HOME}/.platformio/packages/framework-mbed
に格納される。
framework-mbed
ディレクトリは、そのユーザーが使用するすべてのPlatformIOのプロジェクトから参照されるので、プロジェクト毎に毎回調整する必要が出てくる。
少なくとも使用するボードによってビルド対象から外したい機能やドライバは変わってくるはずなので、これを毎回設定するのは面倒くさい。
そこで、pio-mbedignore
というリポジトリに、ヘルパスクリプトを作成した。
使い方
ヘルパスクリプトの使い方の流れは次のようになる。
- リポジトリから適当な場所にダウンロードする
mbedignore.py
をPlatformIOの自分のプロジェクトのルートに配置するmbedignore
ディレクトリを作成し、その下にfeatures
やdrivers
などの名前でファイルを作成する- 作成したファイルに
.mbedignore
の記述ルールに従って、無視したいファイルのパスを指定する - platformio.iniを修正し、extra_scriptに設定する
具体的には次のようになる。
$ git clone https://github.com/mickey-happygolucky/pio-mbedignore.git $ cp pio-mbedignore/mbedignore.py /path/to/pio_project $ cd /path/to/pio_project $ mkdir mbedignore
先程の例のようにcellularを除外するにはmbedignore/features
を次の内容で作成する。
cellular/*
ビルド毎にmbedignore.pyが実行されるようにするために、platformio.ini
に次の内容を追加する。
2020/3/6 追記1
extra_scripts = pre:mbedignore.py post:mbedignore.py
extra_scripts = post:mbedignore.py
これで、pio run
毎に、必要に応じて、framework-mbed以下に.mbedignoreが配置され、指定したファイルをビルド対象から外すことができるようになる。
extra_scriptsのpost:
指定にも指定しているのはゴミが残らないようにするためだが、これについては後述する。
pre:
とpost:
の仕様を勘違いしていた。platformio.iniでのpre/post指定は、extra_scriptsの実行タイミングをPlatformIOのビルドシステムのメインスクリプトを実行する前にするか、後ろにするかという指定。
env.AddPreAction()/env.AddPostAction()
を使用するため、ターゲットシステムの情報が確定されてから実行したいのでpost:
のみの設定が正解。
2020/3/6 追記1 終了
仕組み
PlatformIOではplatformio.ini
のextra_scripts
にpythonスクリプトのファイルを指定すると、platformioコマンド実行時に既存の処理をカスタムしたり、任意の処理を追加したりすることができる。
今回作成したスクリプトはそれを利用して、pio run
毎に必要に応じてframework-mbed
ディレクトリに.mbedignore
を配置するようにしている。
実際には、実ファイルを作成するわけではなく、シンボリックリンクを作成している。
mbedignore.py
extra_scriptsではImport(env)
を使用することで、platformio実行時の環境変数にアクセスしたり、
任意のタイミングで実行されるアクションを登録できるようになっている。
Import("env") import os import glob srcs = glob.glob(os.getcwd() + '/mbedignore/*') print(srcs) dst_basedir = env.Split(env['PROJECT_PACKAGES_DIR'])[0] + '/framework-mbed' def clean_mbedignore(source, target, env): print('Clean .mbedignore') for src in srcs: dst_dir = dst_basedir + '/' + os.path.basename(src) dst = dst_dir +'/.mbedignore' if os.path.exists(dst) == True: os.remove(dst) print('symlink deleted : ' + dst) def mbedignore(): for src in srcs: dst_dir = dst_basedir + '/' + os.path.basename(src) dst = dst_dir +'/.mbedignore' if os.path.exists(dst) == True: os.remove(dst) print('symlink deleted : ' + dst) if os.path.exists(dst_dir) == True: os.symlink(src, dst) print('symlink created : src = ' + src + '->' + dst) mbedignore() env.AddPostAction("checkprogsize", clean_mbedignore)
PlatformIOが知っているディレクトリやファイルなどは環境変数のようにアクセスできるので、 必要な情報はそこから取り出すようにしている。
2020/3/6 追記2
env.AddPreAction("buildprog", clean_mbedignore)
の行で、このスクリプトによって作成されたシンボリックリンクを削除する処理を、
bulidprog
ターゲットの後に実行されるように登録している。
なぜかplatformio.ini
でpre:
指定した場合はここで設定した処理が実行されないので、このスクリプトをpost:
でも登録している。
ただし、このスクリプトの実行時にすでに.mbedignore
が存在している場合は、削除してから作り直すので
post:
の指定を忘れても実行に影響は無い。
修正前はenv.AddPreAction("buildprog", clean_mbedignore)
としていたが、ビルド済みだった場合実行されないので、
env.AddPostAction("checkprogsize", clean_mbedignore)
とした。修正後はcheckprogsize
ターゲットの後に、このスクリプトによって作成されたシンボリックリンクを削除している。
2020/3/6 追記2 終了
実行時間比較
リポジトリのテスト用のmbedignore
ファイルを使用して、
bluepill環境でpio run
の実行時間を比較した。
どちらも実行前にcleanしてある。
スクリプト未使用時
real 2m23.069s user 8m41.679s sys 1m38.485s
スクリプト使用時
real 0m23.076s user 1m56.642s sys 0m16.316s
体感でも違いがわかるくらいには差が出ている。
まとめ
PlatforIOでmbedを使用するとビルド時間が長い。
.mbedignoreを使えば不要なコンパイルを避けビルド時間を短縮できるが、 具体的な使い方がの情報が少ないことと、意外と不親切。
今回はmbedignore.py
を作成し、簡単に.mbedignore
の恩恵を受けられるようにした。