GitHub Actions Raspberry Pi Pico SDKビルド

RP2040(Raspberry Pi Pico SDK)のプロジェクトをGitHub上で自動ビルドすることを考えてみます。

この例ではWindows上で開発する説明ですが、今回は実行するためのコストが低いUbuntu(GitHub Action上)でのビルド例です。

 

GitHub Actionsの使い方

対象のリポジトリの .github/workflows/ フォルダにYAMLで記述されたファイルを配置すれば使用できます。

複数のファイルが設置可能で、注意点としては同じトリガー条件が書かれたファイルが複数あると全部並列に処理されます。

 

GitHub ActionsでPico SDKをセットアップしビルドを行いArtifactsにアップロードする

.github/workflows/pico-sdk-build.yml として以下のファイルを配置しました。

name: Pico SDK Build
on: push

env:
  TZ: "Asia/Tokyo"
  PROJECT_DIR: "RP2040"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:

    - name: Create Directory
      run: |
        mkdir code sdk        

    - name: Install Toolchain
      run: |
        sudo apt update
        sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential        

    - name: Setup SDK
      working-directory: sdk
      run: |
        git clone https://github.com/raspberrypi/pico-sdk.git --branch master --depth 1
        git -C pico-sdk submodule update --init
        echo "PICO_SDK_PATH=$(pwd)/pico-sdk/" >> $GITHUB_ENV        

    - name: Checkout
      uses: actions/checkout@v4
      with:
        path: code

    - name: CMake
      working-directory: code
      run: |
        mkdir -p ${PROJECT_DIR}/build
        cd ${PROJECT_DIR}/build
        cmake .. -DCMAKE_BUILD_TYPE=Debug        

    - name: Build
      working-directory: code
      run:  |
        cd ${PROJECT_DIR}/build
        make -j2        

    - name: Upload
      uses: actions/upload-artifact@v4
      with:
        name: Build
        path: code/${{ env.PROJECT_DIR }}/build/*.uf2

いくつかのジョブに分かれています。

最初の「Create Directory」ではフォルダを作成しています。

プロジェクトのコードを格納する「code」フォルダ、Pico SDKを格納するための「sdk」フォルダを作ります。

 

次に「Install Toolchain」です。

これはRaspberry Pi Pico SDKの説明にある通りで、必要なソフトウェアをインストールしています。

 

次に「Setup SDK」です。

これはRaspberry Pi Pico SDKの説明にある通りで、必要なSDKをgit cloneで配置しています。

「working-directory: sdk」指定で、sdkフォルダ以下で作業を行っています。

GitHub Actionsではステップごとにカレントディレクトリの位置が戻るようです。

サブディレクトリに配置して作業する場合には、最初にフォルダを作成することと、それ以降の各ステップで明示的にサブディレクトリを指定する必要があります。

SDKディレクトリでpwdコマンドを実行し、「PICO_SDK_PATH」環境変数を追加して次のステップに備えます。

 

次に「Checkout」です。

今のリポジトリを配置するだけなので、特に認証情報等もありません。

最初に配置した「code」サブディレクトリで作業をしたいのでpath指定だけ追加しています。

このアクションの詳細については、以下を参照してください。

 

次に「CMake」です。

先程「code」サブディレクトリに配置したソースコードでCMakeを走らせます。

これはRaspberry Pi Pico SDKの説明にある通りです。

「working-directory: code」で「code」サブディレクトリを指定していることと、デバッグビルドを指定していることがポイントです。

「PROJECT_DIR」環境変数ではプロジェクトのパスを指定しています。

プロジェクトのファイル配置によって適宜書き換えてください。

トップにCMakeLists.txtが存在する環境であれば、パス指定は必要なくなると思います。

 

次に「Build」です。

makeコマンドでビルドを行います。

先ほどと同様に「working-directory: code」で「code」サブディレクトリを指定しています。

この仮想マシン自体2コアなのでmakeコマンドにj2を指定しています。

速度差は測っていないので不明です。

 

最後に「Upload」です。

GitHub Actionsの実行結果のページに、「Artifact」というファイルをアップロードできる機能があります。

今回はそこにビルドしたバイナリファイルをアップロードすることにします。

ログローテーションと同じ扱いで、デフォルト設定では90日で消えます。

パブリックリポジトリの場合は最大90日、プライベートリポジトリの場合は最大400日保存できるようです。

このアクションの詳細については、以下を参照してください。

永続的にビルド結果を公開したい場合は、別の方法で保存するほうが良さそうです。

 

GitHub ActionsでPico SDKをセットアップしビルドを行い別リポジトリにPushする

2つのリポジトリが存在、ソースコードを管理するプライベートな非公開リポジトリと、ビルドしたバイナリデータを公開するための公開リポジトリがある想定です。

ログローテーションで消えてしまう「Artifact」ではなく、別リポジトリにコミットする例です。

ソースコードを管理する非公開リポジトリのほうに、GitHub Actionsの設定をします。

公開リポジトリのほうは何かしらコミットされていないとチェックアウト時にエラーが出ると思います。

.github/workflows/pico-sdk-build-release.yml として以下のファイルを配置しました。

name: Pico SDK Build Release
on: push

env:
  TZ: "Asia/Tokyo"
  PROJECT_DIR: "RP2040"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:

    - name: Create Directory
      run: |
        mkdir code sdk release        

    - name: Install Toolchain
      run: |
        sudo apt update
        sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential        

    - name: Setup SDK
      working-directory: sdk
      run: |
        git clone https://github.com/raspberrypi/pico-sdk.git --branch master --depth 1
        git -C pico-sdk submodule update --init
        echo "PICO_SDK_PATH=$(pwd)/pico-sdk/" >> $GITHUB_ENV        

    - name: Checkout Code Repo
      uses: actions/checkout@v4
      with:
        path: code

    - name: CMake
      working-directory: code
      run: |
        mkdir -p ${PROJECT_DIR}/build
        cd ${PROJECT_DIR}/build
        cmake ..        

    - name: Build
      working-directory: code
      run:  |
        cd ${PROJECT_DIR}/build
        make -j2
        echo "BUILD_PATH=$(pwd)/" >> $GITHUB_ENV         

    - name: Checkout Bin Repo
      uses: actions/checkout@v4
      with:
        repository: htlabnet/バイナリ公開用リポジトリ名
        path: release
        ssh-key: ${{ secrets.BIN_REPO_SSH_KEY }}

    - name: Commit Push
      working-directory: release
      run: |
        cp -f ${BUILD_PATH}*.uf2 ./
        git config user.name "GitHub Actions"
        git config user.email "github-actions@github.com"
        git add *.uf2
        git commit -m "Add Firmware"
        git push        

バイナリ公開用リポジトリを操作するために、最初の時点で「release」サブディレクトリを生成しています。

CMakeでデバッグビルドを指定していない点も除けば、「Build」までは先程と同じです。

使いやすいように最後にビルドしたディレクトリを「BUILD_PATH」環境変数に入れてます。

 

「Checkout Bin Repo」では別リポジトリをチェックアウトするために、repository指定、またアクセスするためにssh-keyを指定しています。

これは、GitHub Actionsのファイルが配置されているリポジトリしか権限がないためで、同じユーザーが所有していてもパブリック・プライベート問わず別リポジトリにアクセスするには認証情報が必要になります。

この例では「Deploy keys」という仕組みを使用するために、ssh-keyを指定し、シークレットに設定したBIN_REPO_SSH_KEY変数を参照しています。

詳細については後述します。

なお、path指定で「release」サブディレクトリ中で作業をしています。

 

最後に「Commit Push」です。

先ほどビルドしたバイナリファイルを「release」サブディレクトリにコピーしています。

git addで追加・更新されたバイナリファイルをGitに追加し、コミットを行っています。

先程のssh-key指定でgit pushまで動作すると思いますが、明示的に認証情報を追加する方法については後述します。

 

GitHub Actionsで別リポジトリにアクセスするための認証について

GitHub Actionsでは実行されたリポジトリに関する権限しか許可されていません。

同じ所有者でもリポジトリが違えば、権限不足でPushすることは不可能です。

ではどのように権限を得るのか?

  • Fine-grained personal access token
  • Personal access tokens (classic)
  • Deploy keys

のような方法があります。

 

「Fine-grained personal access token」は一番推奨されているものです。

リポジトリを選択し権限を与えることが出来るので安全ですが、有効期限を最長1年間にしか設定できません。

毎年トークンを生成しなおし、設定することが必要になります。

 

「Personal access tokens (classic)」は無期限を設定できますが、リポジトリを選択することができず、全ての読み書きが可能な権限が付いてしまいます。

万が一、トークンが流出した場合には、自分が読み書き出来るリポジトリ全てが操作される恐れがあります。

 

「Deploy keys」は公開鍵を登録する方法です。

秘密鍵と公開鍵のペアを利用して、リポジトリにアクセスする方法です。

事前に鍵を生成して登録しておく必要がありますが、登録したリポジトリしかアクセス出来ないので安全と考えています。

ED25519アルゴリズムにて鍵を生成する必要があるようです。

上記ドキュメントでは、「ssh-keygen」コマンドを使用するように指示されていますが、Windows環境なので「Tera Term」を使用しました。

Tera Termを起動し、「設定」「SSH鍵生成」の順にクリックすると「TTSSH: 鍵生成」というウィンドウが開きます。

鍵の種類を「ED25519」にして「生成」ボタンをクリック。

パスフレーズは無しで、コメントに自分のGitHubアカウントのメールアドレスを入れます。

公開鍵ファイル「id_ed25519.pub」と秘密鍵ファイル「id_ed25519」をそれぞれ保存し、適当なテキストエディタで開きます。

 

ビルドしたバイナリデータを公開するための公開リポジトリのほうに公開鍵を設定します。

これは公開するリポジトリなので公開鍵という意味ではなく、操作される対象に公開鍵を設定します。

そのため、2つのリポジトリがどちらも非公開だったとしても、ビルドしたバイナリデータを公開するためのリポジトリに公開鍵を設定するのです。

リポジトリの「Settings」から「Deploy keys」を開き、「Add deploy key」ボタンを押します。

Titleには適当な名前を入れます。分かれば良いので「GitHub Actions Key」とでも入れておきます。

Keyには先程の公開鍵ファイル「id_ed25519.pub」の中身を貼り付けます。

「Allow write access」にチェックを入れてから、「Add key」で追加します。

なお、このキーは重複できないので、複数のリポジトリに同じキーを登録することは出来ないと思われます。

 

秘密鍵はソースコードを管理するプライベートな非公開リポジトリのほうに設定します。

リポジトリの「Settings」から「Secrets and variables」「Actions」と開き、「Actions secrets and variables」のページを表示します。

「New repository secret」ボタンをクリックして秘密鍵を登録します。

Nameには参照するための名前を入れます。「BIN_REPO_SSH_KEY」にしました。

Secretには先程の秘密鍵ファイル「id_ed25519」の中身を貼り付けます。

「Add secret」で追加します。

 

Gitコマンド使用時に明示的に秘密鍵を指定する

以上ようにシークレットの設定がされていれば、ビルドしたバイナリデータを公開するためのリポジトリはPublicでもPrivateでも機能するはずです。

もし、最後のPushでエラーが出る場合には、以下のように追記して秘密鍵を使用するようにしてみると確実に動作するでしょう。

- name: Commit Push
  working-directory: release
  env:
    GIT_SSH_COMMAND: ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no -F /dev/null
  run: |
    cp -f ${BUILD_PATH}*.uf2 ./
    mkdir ~/.ssh
    echo "${{ secrets.BIN_REPO_SSH_KEY }}" > ~/.ssh/id_ed25519
    chmod 600 ~/.ssh/id_ed25519
    git config user.name "GitHub Actions"

 

他のGitHub Actionsから呼び出して使用する

他のGitHub Actionsから呼び出したい場合は、onに書かれているトリガー条件を以下のように変更します。

on: workflow_call 

workflow_dispatchにすれば手動実行もできますが、変更がなければコミットでエラーを吐いて止まると思われます。

この例ではシークレット情報を使用していますが、他のGitHub Actionsから呼び出す場合にはデフォルトでシークレットが引き継がれず参照できないので注意してください。

こちらに書きましたが「secrets: inherit」を忘れずに指定してください。

上記ページではバージョンナンバーの自動生成と組み合わせる例を紹介しています。

 

使用したアクション