today   2020-05-17

access_time  3 mins

Github ActionsでArduinoプロジェクトのビルドを行う

ビルド周りの不安解消の話

前置き

最近Wio Terminalを購入して遊んでいる。Twitterを見ていても多くのユーザが色々遊んでいてなんとなく流行に乗った気分になっている。

個人的購入したきっかけはLiPo内臓ではないこと、ATMEL社のARMマイコンを以前使っていたことあたり。(これとか)

ところで一昔前ならICEつないでArduino環境を取っ払って遊んでしまうのだが、最近は趣向が変わっていて他人が再現しやすい環境・想定された開発環境をできるだけ守るような試みに重きをおいている。 というわけでArduino IDEを使っていたのだが、色々と辛い部分があったので今回の話に移る。

気になる点

  1. hogehoge.inoだけを公開してもBSP,/Libraryはユーザ環境のVersion次第
  2. 1.に関連して、仮に別Projectのfugafuga.inoがLibraryのVersion依存を持っていると収集がつかない
  3. Arduino IDEがないとビルドができない(arm-none-eabi-gccを叩くにしてもオプションを毎回控えるのは手間)

ざっくりまとめると1.2.に関してはenv切り替えのないpythonと同じ問題、3.については…という具合

改善・やったこと

今回は作り途中の kamiyaowl/wfi_monitor - GitHub で試した内容である。

1.2. ライブラリの参照方法

2020/05/24修正

1.2.についてはライブラリをArduino IDEのパス解決に任せないことにした。 今日の多くのライブラリはgithubに公開されているものをzip DL, IDEに追加の流れを踏んでいたのでsubmoduleとしてリポジトリに追加している。

その際にlib以下にまとめてsubmoduleとして追加されるようにし、後ほどDockerコンテナ内にマウントしている。

$ cd lib
$ git submodule add <追加したいライブラリのrepo url>

今回の場合はTFT液晶制御のライブラリを追加している。

$ cd lib
$ git submodule add https://github.com/Bodmer/TFT_eSPI.git

後述するDocker上でビルドする際、libディレクトリをそのままArduino LibのおいてあるDirectoryにマウントして参照・ビルドしている。

これで通常のビルドと遜色なく運用できるようになった。

3. Arduino IDEに依存しないビルド環境

Arduino CLI なるものがあるらしい。これを使えばDocker上ですべて解決できるのでは…ということでやってみた。

Dockerfile作成

配布済を使っても良かったがビルドする際に、任意のBSP/Libraryを入れたかったので書いた。 正規の手順でArduino CLIを導入し、必要なパッケージ群をインストールしているだけである。

Dockerfile - kamiyaowl/wfh_monitor

FROM ubuntu:20.04

# install from apt package

RUN apt-get update && apt-get install -y curl

# install arduino-cli

RUN mkdir -p /tool
RUN curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/tool sh
ENV PATH $PATH:/tool/
RUN echo $PATH

# refresh platform indexes

RUN arduino-cli core update-index
RUN arduino-cli core update-index --additional-urls https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json

# add arduino core and libraries

RUN arduino-cli core install arduino:samd
RUN arduino-cli core install Seeeduino:samd --additional-urls https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
# RUN arduino-cli core list # for debug


# create work directory

RUN mkdir /work
WORKDIR /work

CMD ["/bin/sh"]

私はコマンドを打つのが面倒なタイプなのでdocker-composeを使う。 ただ、docker-compose.yamlにコマンド直書きするにはちょっと取り回しが面倒なので、実行するscriptは分離した(linux環境だったらそのまま使えますし)

build.sh - kamiyaowl/wfh_monitor

#!/bin/sh
arduino-cli compile -b Seeeduino:samd:seeed_wio_terminal ./wfh_monitor.ino --verbose --log-level trace

小テクだが、checkout時点でscriptに実行権限がないと積むのでchmod +xしている。

docker-compose.yml - kamiyaowl/wfh_monitor

version: "3"
services:
    build:
      build: .
      volumes:
        - ./:/work
        - ./lib:/root/Arduino/libraries:ro
      command: >
        bash -c "chmod +x ./build.sh && ./build.sh"

./libにcheckoutしてあるライブラリも、ここでRead Onlyでマウントしておくことで参照できる。

これでDocker/Docker Composeさえ入っていればArduino CLIでビルドできるようになった。めでたい。

$ docker-compose run build

おまけ: Github Actionでビルドさせる

やっとタイトル回収。Dockerでビルドできるなら、Github Actionでもすぐ動かせるはず。

注意点としてactions/checkoutではsubmoduleを引っ張ってきてくれないので自分であとから引っ張ってきている(git cloneも–recursiveオプションがないとだめなはず)

また、actions/upload-artifactで生成物を指定することでzipで固めてDL可能な状態にすることができる。

.github/workflows/build.yml - kamiyaowl/wfh_monitor

name: Build

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - run: git submodule update --init --recursive
    - run: docker-compose run build
    - uses: actions/upload-artifact@v2
      with:
        name: wfh_monitor.zip
        path: wfh_monitor.ino.Seeeduino.samd.seeed_wio_terminal.

これでpushするだけでビルド済バイナリを作れるようになった。

workflowにDockerfile相当を書いても行けるはずだが両方保守するのは面倒なのでこの方法が手軽で良い。

終わりに

全然関係ないけど、Rust+Arduinoをさっさと試したい人向けに作ったが需要がニッチ過ぎて微妙だった。興味があったら試してほしい。

手軽さのArduinoと堅牢さのRustってものすごく相性悪い気がしてきた…?私は堅牢なところだけRustで書くつもりだったのだが。