バックグラウンド:
新しい組み込みシステムのファームウェアをモデル化しています。現在、ファームウェアはUMLでモデル化されていますが、UMLモデリングツールのコード生成機能は使用されません。
ターゲット言語はC(具体的にはC99)になります。
低電力(つまり、パフォーマンス、迅速な実行)と正確さは重要ですが、コードサイズや実行速度など、何よりも正確さが最優先事項です。
システムのモデリングでは、明確に定義されたコンポーネントのセットを特定しました。各コンポーネントには独自のインターフェースがあり、多くのコンポーネントが多くのコンポーネントと相互作用します。
モデル内のほとんどのコンポーネントは、リアルタイムオペレーティングシステム(RTOS)での個別のタスク(スレッド)になりますが、一部のコンポーネントはライブラリにすぎません。タスクは、メッセージパッシング/キュー投稿を介して完全に相互に通信します。ライブラリとの相互作用は、同期関数呼び出しの形式になります。
アドバイス/推奨事項は規模によって異なる場合があるため、いくつかの情報を提供します。現在、約12〜15個のコンポーネントがありますが、最大20個に増える可能性がありますか?数百のコンポーネントではありません。平均して、各コンポーネントが他のコンポーネントの25%と相互作用するとします。
コンポーネント図には、コンポーネント間のインターフェイスを表すために使用されるポート/コネクタがあります。つまり、一方のコンポーネントが他方のコンポーネントに必要なものを提供します。ここまでは順調ですね。
ここにこすりがあります。「コンポーネントA」が「コンポーネントB」のすべてのインターフェースにアクセスできないようにする場合が多くあります。つまり、コンポーネントAをコンポーネントBが提供するインターフェースのサブセットに制限したい場合があります。
質問/問題:
コンポーネント図で定義されたインターフェイスコントラクトを(できればコンパイル時に)強制するための体系的でかなり簡単な方法はありますか?
明らかに、コンパイル時のソリューションは実行時のソリューションよりも望ましいです(より早い検出、より良いパフォーマンス、おそらくより小さなコード)。
たとえば、ライブラリコンポーネント「B」が関数X()、Y()、およびZ()を提供するとしますが、コンポーネント「A」が関数Z()のみを呼び出し、X()およびY()を呼び出せないようにします。 。同様に、コンポーネント「A」は、メッセージキューを介して多数の異なるメッセージを受信して処理できる場合でも、メッセージを任意のコンポーネントに送信できるコンポーネントはありません。
私が思いついた最善の方法は、コンポーネントとコンポーネントのインターフェイスごとに異なるヘッダーファイルを用意し、コンポーネントが使用を許可されているインターフェイスの部分のみを(ヘッダーファイルを介して)公開することです。明らかに、これにより多くのヘッダーファイルが作成される可能性があります。これは、コンポーネント間でのメッセージパッシングがOS APIで直接行われるのではなく、それぞれが特定の(許可された)メッセージを作成して送信する関数呼び出しを介して行われることも意味します。同期呼び出し/ライブラリの場合、APIの許可されたサブセットのみが公開されます。
この演習では、人々が行儀が良いと想定できます。 言い換えれば、関数プロトタイプを直接不正行為、切り取り、貼り付けしたり、許可されていないヘッダーファイルをインクルードしたりすることを心配する必要はありません。許可されていない場合、「A」から「B」へのメッセージを直接投稿することはありません。
コンパイル時のアサーションを使用してコントラクトを適用する方法があるかもしれません。オーバーヘッドが発生したとしても、実行時にこれをチェック/実施するためのより洗練された方法があるかもしれません。
コードはクリーンにコンパイルおよびリントする必要があるため、「関数プロトタイプファイアウォール」アプローチは問題ありませんが、これを行うにはもっと慣用的な方法があるようです。