ei1333の日記

ぺこい

GitHubを用いた自作ライブラリ管理

競プロ Advent Calendar 2022 - Adventar の 12 日目の記事です。

ei1333 の日記(いつもの)ではないです。

概要

GitHub - luzhiled1333/comp-library でやっていることの説明です。

verify

ライブラリの verify はしたほうがよいです。バグっていると困るからです。実際には、他の人が使った時にバグっていたのでWAしてくれるのでうれしいとかがあります。GitHub - ei1333/library: CompetitiveProgramming C++ Library は verify をしていても 5000 箇所くらいバグっているので意味がないですが・・・

自動で verify をしてくれるものとして Online Judge Verification Helper があります。使い方は公式のリファレンスを読むかなどをするとよいです(丸投げ)。

gist.github.com

main ブランチに push されるたびに、Verification Helper の oj-verify all を実行するワークフローです。(更新があれば)verify の結果を .verify-helper/timestamps.remote.json に push する仕組みになっています。同時にドキュメントの生成も行って gh-pages ブランチに push します。

ブランチを切って PR を生やすといった運用にする場合、main ブランチに対しては verify 済みのコードのみが入るようにしたいです。git push origin main 以外知らねえという人はこのあとの説明は飛ばして大丈夫です。

そのためには PR をマージできる条件(main ブランチに対するbranch protection rule) にすべての CI に合格することにチェックを入れることにして、verify が通っていないコードがマージされることを禁止するべきです。

しかし、PR に対して oj-verify all を動かすのは微妙な部分があります。この場合、PR に対して push があるたびに CI が回って Verification Helper によって timestamps.remote.json を更新する push が起こります。これが微妙で、別 PR が先にマージされた結果、ソースコードのコンフリクトは問題なくても timestamps.remote.json がコンフリクトしてカスという問題が起こります。

おまけですが、図に示したチェックマークが消えます。最後の更新が CI からの push になってしまうためです(CI からの push に対して CI を回しているわけではないため)。

したがって、PR に対しては push を行わずに、エラーだけを検出したいです。そこで、fork してそれをするコマンド oj-verify check を実装しました。

github.com

gist.github.com

verify-check.yml では PR 時に oj-verify check を動かしています。

document

ドキュメントはあった方が良いです。使い方を忘れたり、他の人が使い方がわからなかったりするからです。なくても良い派閥の人はこの章を飛ばしてください。実際、ドキュメントを書くのは面倒なので、コードだけ書いてドキュメントを書くのは後回しにすることが多々あります。

Verification Helper では、適当な場所に Markdown ファイルを置いておくと、それが GitHub Pages にページが自動生成される機能があります。

仕様は以下に書かれています。

online-judge-tools.github.io

ドキュメントの書き方にはこだわりがないので、ACLのドキュメントを参考にしています。計算量と制約が書かれていることが利点だと思っています。

github.com

formatter

コーディングスタイルは揃っていたほうが良いです。特に複数人が関わるライブラリでは、コーディングスタイルが定義されていることで一貫性を保つことができます。揃っていないほうが良い派閥の人はこの章を飛ばしてください。

C++ の formatter として clang-format があります。

formatter の使い方として、フォーマットのエラーを検出することと、自動フォーマットするの 2 通りがあります。自動フォーマットの例として、push 後に CI を動かすことにより、フォーマットしたコードを push させるというのがあります。

これはどちらでもよい気がしますが、今回はフォーマットのエラーを検出することのみにとどめる運用を考えます(PRの commit のログを汚したくないなどの理由があり、verify の運用と合わせました)。手元で clang-format をかける手間が増えますが、フォーマットのエラーがある状態で PR をマージすることはできません。

運用方針が決まればあとは、フォーマットの設定を記述したファイル .clang_format を用意し、.github/workflows にワークフローを書いたファイルを置くだけです。実際には、ワークフローの書き方が分からず置くだけではありませんでした。

gist.github.com

いくつかベースとなるフォーマットが用意されていて、BasedOnStyle: で指定できます。今回は Google C++ Style Guide をベースに、ちょこまかと設定をしています。このあたりはそれぞれの好みの設定でよい気がします。

gist.github.com

普通に apt-get install clang-format をすると、旧石器時代のバージョンのものがインストールされます。一部のオプションに対応していなかったり、バグがあったりするので、新しいバージョンの clang-format を入れるようにしています。

インストール後に、すべての cpphpp ファイルに対して clang-format-16 コマンドを叩いて、フォーマットのエラーを検出しています。--dry-run は前述した通りフォーマットの修正は行わないため、--Werror は フォーマットの warnings を error として検出することで CI を失敗させるため(フォーマットのエラーはデフォルトでは warnings)のオプションです。

linter

formatter と似たものに linter があります。似てはないかもしれません。linter は静的解析ツールとも呼ばれ、ソースコードを解析してありがちなミスや曖昧な記述に対する指摘を行ってくれるツールです。

C++ の linter として clang-tiny ←びーと☆をつけるな clang-tidy があります。

ここまで書いておいて申し訳ないのですが、よくわかっていないので linter の設定をしていません。どなたか設定ファイルをPRしてください。

まとめ

よく考えたらライブラリの更新をするためにissueやPRをたてるのは業務を思い出すので、もっと適当に管理するべきです(実際にライブラリの更新が滞っています)。

そもそも自作ライブラリを作るのは面倒なので、誰かが作ったライブラリを使えばよいですね。