C++ Code Generator

イントロダクション

Aurora Vision StudioおよびAurora Vision Executorで受け入れられるプログラムは、仮想マシン環境で実行されます。このようなマシンは、元のプログラムからフィルタを連続して実行します(適切なルールを守りながら)。C++コードジェネレータを使用すると、Aurora Vision Studioエグゼキュータの仮想マシンが実行するジョブの論理的な同等物であるC++プログラムを自動的に作成できます。このようなプログラムを生成、コンパイル、実行するには、Aurora Vision Libraryライセンスも所有している必要があります。

C++コードジェネレータの機能は、ファイル » C++コードを生成...のメインメニューで利用できます。このコマンドを選択すると、追加のジェネレータオプションとパラメータが含まれるウィンドウが開きます。

Outputタブでは、基本的なジェネレータのパラメータを設定できます:

  • プログラム名 - これにより、生成されたC++プログラムの名前が決まります(これはAurora Vision Studioプロジェクトの名前と関連している必要はありません)。これはソースファイルの名前を作成するための基本名であり(適切なオプションを選択した場合)、新しく作成されたプロジェクトの名前でもあります。
  • 出力ディレクトリ - これにより、生成されたプログラムとプロジェクトファイルが保存されるフォルダが決まります。このようなフォルダは生成を開始する前に存在している必要があります。パスは、プロジェクトディレクトリから始まる、絶対または相対のいずれかであることができます。すべてのプログラムおよびプロジェクトファイルは、このフォルダに追加のサブフォルダなしで保存されます。出力ディレクトリ内のファイルを上書きする前には、競合するファイルのリストを含む警告メッセージが表示されます。
  • コードの名前空間 - 生成されたC++コード全体が含まれるオプションの名前空間。名前空間は、ネストされた多くの回の "::" シンボルを使用して入れ子にできます(例: "MyNamespace"または"MyProject::MyLibrary::MyNamespace")。コードの名前空間フィールドを空にした場合、生成されたコードはグローバル名前空間に配置されます。
  • Microsoft Visual Studioのサンプルソリューションを作成 - このオプションを有効にすると、Microsoft Visual Studio環境で生成されたコードをコンパイルするために新しいサンプルの設定済みソリューションが生成されます。このオプションが有効になり、コードが生成されるたびに(たとえばAurora Visionプロジェクトで変更を加えた後にコードを再生成する場合)、新しいソリューションが作成され、同じパスに既存のソリューションに対して行われた可能性のある変更が上書きされます。
    このオプションは、最初に特定のフォルダに対してコードを生成するときにはデフォルトで有効になっています。既存の出力フォルダでコードを再生成すると(更新するとき)、このオプションはデフォルトで無効になります。
    生成されたコードに必要なMicrosoft Visual Studioソリューションの構成の詳細については、この文書の後に説明します。

Modulesタブでは、コード生成に参加できるプロジェクトモジュールのリストがあります。これはAurora Vision Studioプロジェクトに存在するモジュールの任意のサブセットを選択できます。ただし、これによってそれらのモジュール内に存在する依存関係が壊れることはありません。モジュールのサブセットを選択すると、生成されるC++コードには、選択したモジュール内に存在するマクロフィルタとグローバルパラメータしか含まれません。モジュールを無効にすると、依存関係が壊れる場合(たとえば、生成されるマクロフィルタがコード生成で無効にされたモジュール内に存在する別のマクロフィルタを参照している場合)は、コード生成中にエラーが報告されます。

Optionsタブでは、C++コードジェネレータの動作を変更する追加の高度なオプションがあります:

  • 診断モードのインスタンスを含める - 診断インスタンス(前のフィルタインスタンスの診断出力からデータを処理するインスタンス)は、プログラムの開発中にプログラムの実行を分析するために使用されるものであり、そのためデフォルトでは生成されたプログラムに含まれません。このオプションを有効にして生成されたプログラムにこのようなインスタンスを含めるには、このオプションを有効にする必要があります(注意:関数の診断出力が正しく機能するためには、C++プログラムでAurora Vision Libraryの診断モードを有効にする必要があります)。
  • マクロフィルタの入力範囲チェックを生成 - 仮想マシンは、それに割り当てられた許可された範囲の観点からマクロフィルタの入力上のデータを制御します。生成されたコードは、これをデフォルトで再現します。最終製品でこのような制御が不要な場合は、このオプションをオフにしてC++プログラムから削除することができます。
  • ファンクションブロックのマージを有効にする - 仮想マシン関数の条件付きブロックとループをマップする言語構造は、生成されたコードに配置されます。C++コードジェネレータは、可能な場合にフィルタ呼び出しを共通のブロックに配置する最適化を使用します(ファンクションブロックをマージ)。このオプションを無効にすると、そのような最適化が無効になります。この機能は問題の解決に役立つため、通常は有効にしておくべきです。

ウィンドウの底部にあるGenerateボタンは、選択した構成に従ってコード生成を開始します(既存のファイルを上書きする必要がある場合、そのようなアクションを確認するための追加のウィンドウが表示されます)。

生成操作が正常に完了すると、ウィンドウは閉じられ、パラメータが保存されます。 Closeボタンはウィンドウを閉じ、選択した構成を保存します。 Cancelボタンはウィンドウを閉じ、構成への変更を無視します。

すべてのパラメータとジェネレーションオプションはAurora Vision Studioプロジェクトと一緒に保存されます。 次回のコード生成時(構成ウィンドウが再び開かれるとき)、以前にプロジェクトに選択されたパラメータが復元されます。

Aurora Vision StudioプロジェクトファイルとC++プログラムファイルの間の名前を同期させるために、C++コードを生成する前にプロジェクトを保存することをお勧めします。

生成されたコードの組織

プログラムは、プログラムがモジュールに分割された状態を保持したまま、C++コードに生成されます。生成された各プログラムモジュールには、2つのファイル(.cppおよび.h)が作成されます。メインモジュールの場合(またはモジュールが1つしかない場合)、これらのファイルの名前は、生成オプションで選択されたプログラム名と同じです(適切な拡張子を使用しています)。他のモジュールの場合、ファイル名はprogram-name.module-name.cpp/hというテンプレートに従って作成されます。

モジュールに含まれるマクロフィルタは、C++関数の形式で生成されます。生成されたコードに含まれる各パブリックマクロフィルタ、または生成されたコードで使用される他のマクロフィルタによって使用されるプライベートマクロフィルタは、.cppファイルに関数定義として含まれます。各パブリックマクロフィルタについては、その宣言も.hファイルに含まれます。同様のルールがグローバルパラメータにも適用されます。マクロフィルタの可視性レベル(パブリック/プライベート)は、そのプロパティで設定できます。

他のプロジェクト要素、例えばHMI構造、は生成されたコードに対応する要素を持っていません。

生成された関数インターフェースは、マクロフィルタの入力および出力のセットに対応しています。最初に、入力は関数引数に連続してマッピングされます(時には定数参照型を使用)。次に、出力のリファレンス型の引数(関数の出力引数)からも引数がマッピングされ、それらを介して関数は外部から関数に渡されたオブジェクトに結果を割り当てます。たとえば、2つの入力(inValue1、inValue2)および1つの出力(outResult)を含むマクロフィルタの場合、関数インターフェースは次のようになります。

void MyMacro( int inValue1, int inValue2, int& outResult )

マクロフィルタが連続するマクロフィルタの反復でその状態を保存する必要がある機能を含む場合(例: レジスタ、ループジェネレータ、アキュムレータを含むStepマクロフィルタ)、関数インターフェースの最初の位置に状態引数が追加されます:

bool MyMacro( MyMacroState& state, int inValue1, int inValue2, int& outResult )

入力、出力、および接続のデータ型は、Aurora Vision Libraryからのテンプレートに基づく型、構造、および構造を使用してコードにマッピングされます(たとえば、atl::Array<>またはatl::Conditional<>)。フィルタ呼び出しは、Aurora Vision Libraryからも来る関数呼び出しにマッピングされます。適切な実装および宣言にアクセスするために、生成されたコードにはAurora Vision Libraryのヘッダが含まれています。このようなインクルードは.cppファイルだけでなく、.hファイルでも現れる可能性があります(なぜなら、マクロフィルタから生成された関数のシグネチャにもAurora Vision Libraryの型への参照が現れるためです)。

生成されたプログラムには、初期の初期化またはファイルからの読み込みが必要な静的定数も含まれています(たとえば、IDEでフィルタ入力の手動編集領域がある場合、そのような領域は生成されたコードと一緒に.avdataファイルに保存されます)。プログラムは、生成されたコードの要素を使用する前に定数の準備が必要です。これを行うために、生成されたコードのメインモジュールに、引数のない追加のInit関数が追加されます。この関数の一部として、複合定数が準備されます。この関数は、生成されたコードの任意の要素を使用する前に呼び出す必要があります(また、状態オブジェクトを構築する前にも)。

生成されたコードの使用

生成されたコードの基礎は、上記で説明した構造のモジュールから生じるファイルのペアです。これらのモジュールは、ビジョンプログラムの一部として使用できます。例えば、Aurora Vision Studio環境で設計されたアルゴリズムを実装する一連の関数として使用できます。

生成された関数を呼び出す前、関数ステートオブジェクトを構築する前、またはグローバルパラメータにアクセスする前には、生成されたコードに追加されたInit()関数を呼び出す必要があります。 Init関数はプログラムの開始時に1回呼び出す必要があります。この関数は、プログラムが初期化が必要な複合定数を含まない場合でも、プログラムを変更および更新した後に生成されたコードのスキーマを変更せざるを得なくなるのを防ぐために、生成されたコードに追加されます。

ステートフルな関数

前述のように、関数には場合によってはstateという名前の追加の最初の引数があり、参照によって渡されることがあります。このオブジェクトは、連続する反復(この関数の各呼び出しは反復と見なされます)の間で関数の状態を保存します。このオブジェクトには、ジェネレータの位置(Enumerate*型のフィルタの現在の位置など)、Stepマクロフィルタのレジスタ状態、内部フィルタデータ(カメラから画像を取得するフィルタでのデバイスとの接続の状態など)が含まれます。

ステートオブジェクトの型は、パラメータのないコンストラクタ(最初の反復の状態を初期化する)およびデストラクタ(状態リソースを解放する)を持つ単純なクラスです。関数でステートを使用するアプリケーションのタスクは、ステートオブジェクトを準備し、それを関数にパラメータとして渡すことです。アプリケーションは、Init()関数を呼び出した後にのみステートオブジェクトを構築できます。 アプリケーションはこのオブジェクトを自分で修正すべきではありません。1つのステートオブジェクトのインスタンスは、同じタスクの一環として関数呼び出しの一部として意図されています(これはAurora Vision Studioプログラムの単一のマクロフィルタインスタンスの相当物です)。1つのオブジェクトの寿命は、そのタスクが実行される時間にわたって維持する必要があります(例: 連続するビデオフレームで同じ操作を実行するために新しいステートオブジェクトを構築してはいけません)。単一のステートオブジェクトは異なるタスク間で共有できません(例: 同じ関数が1つの反復の一環として2回呼び出される場合、両方の呼び出しは異なるステートオブジェクトのインスタンスを使用する必要があります)。

ステートオブジェクトの型名は動的に生成され、生成された関数の宣言で見つけることができます。C++ Code Generatorは可能な限り、ステートタイプの名前をMacrofilter-nameStateのテンプレートに従って作成します。

ステートリソースの解放は、ステートクラスのデストラクタで実行されます。関数が外部デバイスとの接続を確立した場合、ステートオブジェクトのデストラクタもそれらを閉じるために使用されます。ステートの処理の推奨される方法は、スタック上のローカル変数を使用することで、デストラクタが自動的に呼び出されるようにすることです。

エラーハンドリング

Aurora Vision Libraryおよび生成されたコードの関数は、Aurora Vision Studio環境で観察できるエラーを報告します。C++コードレベルでのエラー報告は、例外をスローすることによって行われます。 例外をスローするには、atl::Errorクラスから派生した型のオブジェクトが使用されます。このクラスのメソッドを使用して、報告された問題の説明を取得できます。

注意: Init()関数も例外をスローする可能性があります(例: 静的定数を含む外部の.avdataファイルが読み込めない場合)。

グローバルパラメータ

シンプルなグローバルパラメータ(ビジョンアプリケーションで読み取り専用のみ)は、C++プログラム内のグローバル変数として生成されます(グローバルパラメータと同じ名前)。これらの変数は、アプリケーションの設定を変更するためにユーザーコードから変更することができますが、そのような変更はスレッドセーフではありません

グローバルパラメータをスレッドセーフに変更する必要がある場合、グローバルパラメータにはユーザーコードからのアクセスが許可されるように、適切な読み書きを生成する公開マクロフィルタでカプセル化する必要があります。これにより、ユーザーコードからパラメータにアクセスできるようになり、関数呼び出しの形でアクセスできます。

生成されたコードでプログラムをコンパイル

生成されたC++コードは基本的にはAurora Vision Libraryに基づくプロジェクトであり、そのガイドラインに従う必要があります。コンパイルにはこの製品がインストールされている必要があり、適切なヘッダーと.libファイルにアクセスできるようにする必要があります。Aurora Vision LibraryはプロジェクトがMicrosoft Visual Studio環境でコンパイルされていることを要求しています。

コンパイルされているプログラムには、次の設定が必要です:

  • ヘッダーファイルの検索パスがAurora Vision Libraryパッケージのincludeフォルダに設定されています。
  • 各プラットフォーム用の.libファイルの検索パスは、Aurora Vision Libraryパッケージのlibディレクトリの対応するサブフォルダに設定されています(例: Microsoft Visual StudioパッケージでコンパイルされたRelease|Win32構成はlib\Win32\サブフォルダからライブラリを使用する必要があります)。
  • プロジェクトにAVL.libライブラリがリンクされています(動的ライブラリ - AVL.dllをリンクするため)。

コンパイルされたプログラムの実行

生成されたコードおよびAurora Vision Library製品を基に作成されたプログラムを実行するには、次のコンポーネントが必要です:

  • すべてのC++コードで生成された.avdataファイル(あれば)、Init()関数呼び出し時に現在のアプリケーションフォルダに配置されています。
  • Aurora Vision Studioプロジェクト(コードが生成されたもの)で外部データを読み取るフィルタ(LoadImageなど)またはデータファイルをフィルタの入力にエンクロージョンしている場合、プログラムの実行中にはこれらのファイルが利用可能でなければなりません。ファイルは定義されたパスに従って検索され、相対パスの場合は現在のアプリケーションフォルダから検索が開始されます。
  • 宛先システムにインストールされている、使用されているMicrosoft Visual Studioのバージョンの再頒布可能パッケージ。
  • 使用されているプラットフォームと互換性のある、準備が整ったAVL.dllファイル。このモジュールはAurora Vision Libraryパッケージのbinディレクトリのサブフォルダに見つかります(.libファイルの検索パスの使用方法と同様)。
  • 生成されたコードがサードパーティのパッケージ(カメラ、I/Oカード、シリアルポートなど)を使用している場合、追加の.dllファイル(これらのデバイスのドライバーへのアクセスを仲介するもの)が必要です。このようなファイルは"_Kit"サフィックスで終わる名前で識別され、使用されているAVL.dllファイルと同じディレクトリに見つかります(この場合もこのファイルが対応するプラットフォームと互換性がある必要があります)。必要なファイルが不足している場合、実行中のプログラムはメッセージで欠落しているモジュールの名前を指摘するエラーを報告します。このようなライブラリはプログラムの実行中に動的に読み込まれます。この場合、正常な実行のためには使用されているデバイスの正しい再頒布パッケージまたはSDKもインストールする必要があります。
  • 宛先システムで有効なAurora Vision Libraryライセンス。

生成されたサンプル Microsoft Visual Studio ソリューション

Output タブで適切なオプションを選択した後、C++コードジェネレーターは、モジュールのコードに加えて、生成されたコードを使用するサンプルのMicrosoft Visual Studioプロジェクトと、生成されたコードを使用するサンプルユーザーコードを含むプロジェクトを作成します。このプロジェクトの構成は、上記のコンパイル要件に従います。これにはAurora Vision Libraryパッケージからのヘッダーと.libファイルの添付も含まれます(Aurora Vision Libraryのインストーラーによって作成されるAVL_PATHXX環境パスを使用します)。これは、サンプルプロジェクトをコンパイルするために、正しくインストールされたAurora Vision Libraryパッケージが必要であることを意味します。

生成されたプロジェクトの構造を明確にし、その要素を区別するために、このようなプロジェクトで2つのフィルタ(ソリューションディレクトリ)が作成されています:

  • Generated Code - ここにはプロジェクトモジュールの生成から派生したファイルがあります。これらの要素は、プロジェクトの更新とコードの再生成の際に手動で変更しないようにする必要があります。そうしないと、変更は上書きされます。
  • User Code - ここにはサンプルのユーザーアプリケーションからのファイルがあります。これはユーザーが作成し、生成されたコードを使用する最終アプリケーションを実装するものと想定されています。

プロジェクトの構成には次の項目が含まれます:

  • Aurora Vision Libraryパッケージのヘッダーへのパスを含める。
  • AVL.libライブラリとのリンク。
  • AVL.dllファイルを宛先フォルダにコピー。

この構成には適切な _Kit ファイルが含まれていない場合があります。

サンプルユーザーコードとしては、1つのシンプルな "main.cpp" ファイルが作成されており、次のアクションを実行します:

  • Init 関数の呼び出し。
  • Aurora Vision Libraryの診断モードを有効化(プロジェクトオプションでコード生成のために診断インスタンスの使用が有効になっている場合)。
  • Main マクロフィルタの関数の呼び出し(main.cppファイルの作成時にコード生成で主要だった場合)。
  • プログラムとAurora Vision Libraryによって投げられるすべての例外をキャッチし、プログラムを閉じる前に標準出力にエラーメッセージを報告します。

プロジェクトとサンプルユーザーコードは1度だけ生成されます。これはプロジェクトの更新(コードの再生成)中にプロジェクト構成や生成されたコードを更新することはなく、これらはサンプルMicrosoft Visual Studioソリューションの作成オプションを再び選択した場合にのみ完全に上書きされることを意味します。プロジェクトとサンプルコードはAurora Vision Studioのコード生成構成からの名前とオプションに基づいて作成されます。

生成されたコードを使用してアプリケーションを開発する場合、プロジェクトを生成されたコードの変更に合わせる責任がユーザーにあります。これには次のタスクが含まれます:

  • プロジェクトに生成されたモジュールのコードを追加し、削除し、Aurora Vision Studioプロジェクトでモジュールを変更する場合は#includeディレクティブを調整します。
  • パブリックマクロフィルタのインターフェースの変更の場合は、生成されたコードを呼び出すコードを調整します。
  • 生成されたプログラムの範囲内で適切な _Kit ファイルを提供します。

なお、Aurora Vision Studioバージョン3.2までから生成されたプロジェクトはAurora Vision Libraryバージョン3.2まで対応しており、追加のライブラリ "AvCodeGenRuntime.lib" とのリンクが必要でした。このライブラリはもはや必要ではなく、新しいバージョンのAurora Vision Libraryに更新する際には、プロジェクト構成から削除できます。