標準ドキュメント ジェネレーター:事後分析と私のオープンソースの未来

さかのぼる 2016 年に、私は C++ ドキュメント ジェネレーターである standardese を開始しました。

これで、プロジェクトを放棄して所有権を譲渡したことを正式に発表できます。このブログ投稿では、その理由を説明しています。

モチベーション

私の最初の大きなプロジェクトである foonathan/memory では、Doxygen を使用してドキュメントを生成しました。しかし、C++ は注意が必要です。ヘッダー ファイルに記述した内容が、ドキュメントに表示したいインターフェイスであるとは限りません。スタッフ:詳細な名前空間、隠したい未指定の戻り値の型、組み込みたいプライベート仮想関数。次に、適切な要件になる必要がある SFINAE テンプレート パラメーター、新しい型を概念的に作成する必要がある typedef、メンバー関数を挿入する非表示の基本クラスがあります。保存コードの重複、消えるべき EBO の基本クラス、関数として文書化する必要がある関数オブジェクト、文書化してリンクする必要がある概念 (C++20 の機能ではない)、グループ化する必要があるオーバーロード セットなど。など

明らかなことは言うまでもありません:C++ の解析は難しい、本当に難しい、本当に本当に

当然のことながら、Doxygen (少なくとも 2015 年の Doxygen) はそれを適切に処理できません。foonathan/memory については、03 を定義する一般的な回避策を使用しました Doxygen がコードを解析し、条件付きコンパイルを使用して、C++ コンパイラが実際に見るものとは異なるソース コードを与えるときのマクロ。 概念のインターフェイスの説明を含めるには、 26 いくつかのものを隠すため、および 34 のようなマクロ Doxygen がアクティブでない限り、基底クラスに展開されます。もちろん、これは面倒でした。

そこで、高校最後の数週間、私は C++ を「取得」するドキュメント ジェネレーターを作成することを計画しました。それは、私たちがしなければならないことをすべて理解し、それに応じてドキュメント化する必要があります。ドキュメント スタイルを生成するドキュメント ジェネレーターを作成します。 C++ 標準に似ているため、Effects を使用:および必須: などなど - 標準語。

私は自分が何に夢中になっているのかまったくわかりませんでした.

初期のプロトタイプ

驚いたことに (現在このブログ投稿を書いて調べている「私」)、2016 年 5 月に最初のプロトタイプを公開しました。すべての高度なものなので、この時点では機能の少ない Doxygen にすぎませんでしたが、次の数か月で機能を追加し、サポートを改善しました。多くの特別なコマンドがドキュメントのコメントに追加され、ブラックリストに登録することを学びました。エンティティ、ドキュメンテーション コメント内の任意のマークダウン、クロス リファレンス、エンティティの基本クラスとパラメータのドキュメンテーション、オーバーロード解決セットのグループ化、エンティティを分類するためのモジュール、概要内のハイパーリンク、別のファイルにドキュメンテーションを埋め込むための小さなテンプレート言語。 /P>

Meeting C++ 2016 で、私は標準語を紹介するライトニング トークを行い、2016 年 10 月にリリースされた私の type_safe ライブラリにそれを使用しました。素敵なドキュメンテーション ジェネレーターです。

しかし、そこにたどり着くために私がしなければならなかったことは…

C++ の解析は難しい

libclang を使用して C++ の構文解析を行っています。これが、現在このブログ投稿を書いている主な理由です。

libclang は、clang コンパイラの API への安定した C インターフェイスです。Clang は C++ を取得するため、Doxygen が行う正規表現よりも優れています (2015 年も、現在は異なる可能性があります)。安定した API は優れているため、大丈夫ですよね?

いいえ、不安定な C++ API である libTooling を直接使用する必要がありました。libclang は必要なすべての情報を公開していないためです。 、または条件付きで 58 65 を取得するには、適切なドキュメントを生成する必要があります。 ネス、私は自分で関数を解析しなければなりませんでした.しかし、これはそれほど悪くはありません.libclangは宣言のトークンを提供するので、それらを反復処理して75があるかどうかを確認するだけです. そこに…

入力:プリプロセッサ。

関数が 83 の場合もあります しかし 90 トークンはどこにもありません。代わりに、関数宣言にマクロが含まれています 105 に展開されます !問題ありません。関数のトークンを取得し、それらをプリプロセッサにフィードして、110 をチェックします .

この時点で libclang を選択する立場を再考するか、API を少し拡張し始めるべきだったのかもしれません。しかし、悲しいことに、私は若かった (今は年をとっているわけではありませんが…) 頑固だったので、回避策を追加し続けました。回避策の後。メンバー関数の cv 修飾子を取得できませんか?問題ありません。トークンを確認してください。ああ、122 はどうでしょうか。 と 135 ?問題ありません。トークンを確認してください。

しばらくすると、標準ソース コードの大部分は C++ パーサーのいくつかの回避策とその場しのぎの実装でした。必要なすべての情報にアクセスして問い合わせてください。

それから私は type_safe で怠惰になり、次のように書きました:

TYPE_SAFE_DETAIL_MAKE_STRONG_TYPEDEF_OP(addition, +)
TYPE_SAFE_DETAIL_MAKE_STRONG_TYPEDEF_OP(subtraction, -)
TYPE_SAFE_DETAIL_MAKE_STRONG_TYPEDEF_OP(multiplication, *)
TYPE_SAFE_DETAIL_MAKE_STRONG_TYPEDEF_OP(division, /)
TYPE_SAFE_DETAIL_MAKE_STRONG_TYPEDEF_OP(modulo, %)

はい、これらは一連のコードを生成するマクロです。コードは文書化する必要があります…

これは、トークンを取得してそれらを前処理するという私のアプローチが機能しなかったことを意味します。プリプロセッサ マクロ自体が宣言全体を生成しました。そのため、最初にすべてを前処理してから libclang に渡す必要がありました…

この頃、私は自分の構文解析コードがめちゃくちゃになってしまったので、あなたができる最悪のことをしました:私はゼロから始めました.C++ を構文解析して AST に変換し、ドキュメントの情報を取得するための新しいプロジェクトを作成しました。生成、リフレクションなど。実際に成功しました。cppast が結果でした。一言で言えば、これは C++ API と libclang の回避策ですが、今回は libclang を完全な実装の詳細にするという賢明な選択をしました。ユーザーに影響を与えずにバックエンドを追加できます。いつか libTooling を実際に使用する日が来るかもしれません。

書き換えられた構文解析コードは、標準語よりもきれいで堅牢だったので、当然、標準語で使用したいと思いました。

標準開発ブランチ

そんなわけで、今は2017年半ば。大学在学中の私は、C++のドキュメントジェネレーターの再実装を始めました。C++の解析コードができたので、コメント自体の解析に専念しました。Markdownをサポートするために、私はもともとコメントの内容を cmark に渡してコメントの AST を取得しました。また、さまざまな形式で AST を記述できるため、ドキュメントの HTML および Latex 出力の生成にも使用しました。ただし、完璧ではありませんでした。

まず、 141 のような特別なコマンドを追加しました 、 154 など、手動で解析する必要がありました (おなじみですか?)。第 2 に、出力 AST は、Markdown がサポートする種類のものに制限されていたため、エンファシスとコード ブロックを構築できましたが、たとえばコード ブロックを構築することはできませんでした。ハイパーリンク.これは、そのために純粋な HTML にフォールバックする必要があることを意味しましたが、これはあまり理想的ではありませんでした.

書き直された標準語 (現在開発ブランチで行われている作業) では、これらの問題を解決したいと考えていました。C++ の解析と同じようにコメントの解析を処理できました。回避策を分離する新しいプロジェクトを作成し、新しいより優れた AST を用意します。など。幸いなことに、必要はありませんでした。なぜなら、GitHub が既に私のためにそれをしてくれているからです!彼らは、ReadMe などの Markdown パーサーとして cmark を使い始めましたが、私と同じ問題に遭遇しました:彼らは、解析が必要な拡張機能を持っていました。 .そこで彼らは、ユーザーが独自の解析拡張機能を登録できるようにするフォークを作成しました。これはまさに私が必要としていたものでした!

出力を改善するために、基本的に、ドキュメントを生成するように設計された独自のマークアップ AST を作成し、それをさまざまな形式にシリアル化するコードを記述しました。これはうまく機能し、標準コード ベースの中で今でも私のお気に入りの部分です。

要約すると、cppast で C++ コードを解析し、cmark と解析拡張機能を使用してコメントを解析すると、マジックが発生してマークアップ AST が構築され、それをシリアル化します。その「マジック」部分は、いくつかの宣言を無視したり、複数の他の宣言をマージしたりしました。最終結果は 1.5k 行のファイルになりました。これは、標準的なコード ベースの中で私が最も気に入らない部分でした。

さらに大きな問題もありました。すべてのロジックを再実装するのは仕事でした。 .

C++ は趣味です

私は C++ でプログラミングしています。それが楽しいからです (何かが間違っている可能性があります)。

設計と実装の課題であるため、いくつかのメモリ アロケータを作成しました。他の人と共有したかったので、GitHub に置きました。

C++ 型システムの限界を調査するため、いくつかの型安全性について実験しました。他の人と共有したかったので、GitHub に置きました。

ドキュメント ジェネレーターを作成しました。これが必要であり、これまでに行ったこととは異なるものです。他のユーザーと共有したかったので、GitHub に配置しました。

しかし、ドキュメンテーション ジェネレーターを書き直して、既に持っていたものを最終的に作成する必要がありますか?それは仕事です。 、それは面白くない!

今は 2018 年ですが、私はもう標準語をあまり使っていませんでした。別のことをしたり、楽しいことをしたりしました。 :コンテナ ライブラリ、ビット フィールド ライブラリを作成し、トークナイザを開始しました。作業が多すぎる標準化とは異なり、それらを作成するのは楽しかったです。

C++ が仕事になった

他の人と共有したかったので、すべてのものを GitHub に置きました。多分他の人はそれが役に立つと思います.そして彼らはそうしました:人々は私のプロジェクトを使用しています!type_safeには過去2週間で1000人による50,000のクローンがあり、メモリは2000から300です.

しかし、彼らは私が修正する必要のあるイシューを提出し、マージする必要のあるプル リクエストを作成しました。そして、私が考えていた機能のアイデアをさらに実装する義務があると感じました。それは非常に仕事のように感じました. /P>

それで、2017 年 11 月に Patreon を始めました。もし私がしていることが仕事なら、お金をもらった方がいいかもしれません!それはまた、物事に取り組むためのより多くのモチベーションを与えてくれましたが、標準的なものでしょうか?私はそれをどんどん遠ざけて、代わりに楽しいことをしていました.

休憩中

2019 年がやってきて、学士課程の最後の数か月になりました。2 月に大学の仕事量が急増し、趣味や仕事に費やす時間が減りました。それ以来、ブログに投稿したり、「生産的」と宣言したりしていません。私はまだ少しプログラミングしていますが、楽しいプライベートなものを GitHub に載せるつもりはありません.

その休憩中に、私は自分のオープンソースについて考えました.私はまだ楽しいものを書きたいです.そして、それを共有したいと思っています.それらを維持する義務があります.しかし、私は楽しいプロジェクトを仕事に変えたくありません!

そこで、ある計画を思いつきました。

未来

プロジェクトのラベリング システムを作成しました。プロジェクトのステータスは、次のいずれかになります。

  • 開発中 :現在、積極的にプロジェクトに取り組んでいます。自由に使用してください。ただし、(大幅に) 変更される可能性があることに注意してください。利点として、より多くの機能を利用できます。
  • メンテナンスのみ :私は必ず PR を確認し、問題を解決します。機能をリクエストする場合は、おそらく PR を依頼します。時間があるときはバグを修正しますが、このプロジェクトは「仕事」になっていることに注意してください。したがって、インセンティブがなければあまり取り組みません。
  • 実験的プロトタイプ :このプロジェクトは、私が試してみたかった楽しいアイデアです。おそらく、これを本番環境で使用するべきではありません。将来的には、さらに取り組み、磨きをかけるかもしれません。
  • 捨てられた :もうこのプロジェクトには関わりたくないです。これは、「開発中」のプロジェクトで燃え尽きてしまったときに起こりますが、「メンテナンスのみ」のプロジェクトを正当化するほどには完成していません。この作業を続けたい場合は、私に連絡してください。何か解決できます。

プロジェクト ラベルは私のプロジェクト ページで見つけることができます。Hugo とshields.io のセットアップのおかげで、プロジェクトの readme のバッジとして表示されます。「実験的なプロトタイプ」とラベル付けされたものを実際に使用することはおそらくないだろうという考えです。 、つまり、私はそれを維持する必要がないので、仕事にはなりません。

それでも、私のやっていることを気に入っていただけたら、サポートページをチェックしていただければ幸いです。直接寄付するか、Patreonサポーターになることができます。「生産期間」ごとに請求しますので、大学でやるべきことはたくさんありますが、あなたは私をサポートする必要はありません.生産的な期間の後、私が行ったことの現在のもののような詳細なレポートを書きます。そこでは、今後のプロジェクト、講演、ブログ投稿。

そして標準語?

standardese は、私の Web サイトで「放棄」とリストされているプロジェクトの 1 つです。それに取り組むのは「仕事」になりすぎています。私が望んでいた範囲.したがって、それを完成させて最終的に開発ブランチをマージする代わりに、私はそれを放棄しました.おそらく二度とそれに取り組むことはありません.

しかし、良いニュースがあります!

standardese はまだ他の人にとって有用なツールであるため、私は所有権を複数の人で構成される GitHub 組織に譲渡しました。新しいメンテナはすでに新しいバージョンをリリースしています。彼らはプロジェクトを完全に制御しています。私は必要な場合にのみ彼らを助けます。

ドキュメンテーション ジェネレーターが改善されることを祈っています。C++ には本当に必要なのです!