Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

生成コードを共有ライブラリとしてパッケージ化

Embedded Coder® のライセンスがある場合は、モデル コンポーネントから生成されたソース コードをパッケージ化して配布を容易にし、コードを Windows® ダイナミック リンク ライブラリ (.dll)、UNIX® 共有オブジェクト (.so)、または Macintosh OS X ダイナミック ライブラリ (.dylib) の共有ライブラリとしてビルドして、共有して使用することができます。自分自身または他のユーザーが、Windows、UNIX または Macintosh OS X 開発用コンピューターで実行されるアプリケーションに共有ライブラリを統合できます。生成された .dll.so、または .dylib ファイルはさまざまなアプリケーション間で共有可能で、そのファイルを使用するアプリケーションを再コンパイルせずにアップグレードできます。

生成された共有ライブラリについて

システム ターゲット ファイル ert_shrlib.tlc を使用するようにコード ジェネレーターを設定して、共有ライブラリをビルドします。システム ターゲット ファイルのコード生成では次をエクスポートします。

  • データとしての ExportedGlobal 型の変数と信号

  • データとしてのリアルタイム モデル構造体 (model_M)

  • モデル コードを実行するために必要な関数

生成された共有ライブラリに含まれるシンボルのリストを表示するには、次のようにします。

  • Windows では、Dependency Walker ユーティリティ (https://www.dependencywalker.com からダウンロード可能) を使用します。

  • UNIX では、nm -D model.so を使用します。

  • Macintosh OS X では、nm -g model.dylib を使用します。

共有ライブラリを生成および使用するには、次のようにします。

  1. モデル コードの共有ライブラリ バージョンを生成します。

  2. 共有ライブラリ ファイルを読み込んで使用するアプリケーション コードを作成します。

モデル コードの共有ライブラリ バージョンの生成

モデル コードの共有ライブラリ バージョンを生成します。

  1. モデルを開き、ert_shrlib.tlc システム ターゲット ファイルを使用するように構成します。

    ert_shrlib.tlc システム ターゲット ファイルを選択すると、ビルド プロセスでモデル コードの共有ライブラリ バージョンが現在の作業フォルダーに生成されます。この選択によって、コード ジェネレーターがモデルに対して生成するコードは変更されません。

  2. モデルを作成します。

  3. ビルドが完了したら、モデル サブフォルダーの生成コードを確認し、現在のフォルダーの .dll.so、または .dylib ファイルを確認します。

共有ライブラリを使用するアプリケーション コードの作成

アプリケーション コードで共有ライブラリ ファイルを読み込み、その関数とデータにアクセスする方法の例を示すために、MathWorks はモデル SharedLibraryCode を提供しています。モデルを検査するには、MATLAB® コマンド ウィンドウから次のコマンドを実行します。

モデルで、青いボタンをクリックしてスクリプトを実行します。スクリプトは以下を実行します。

  1. モデルから共有ライブラリ ファイル (64 ビットの Windows 上の SharedLibraryCode_win64.dll など) をビルドします。

  2. 共有ライブラリ ファイルを読み込んで使用するサンプル アプリケーション SharedLibraryCode_app をコンパイルしてリンクします。

  3. サンプル アプリケーションを実行します。

ヒント

移植性のために、明示的なリンクが推奨されます。ただし、Windows システムでは、暗黙のリンクをサポートするために ert_shrlib システム ターゲット ファイルで .lib ファイルが生成されて、保持されます。

暗黙のリンクを使用するには、生成されたヘッダー ファイルを少しだけ変更して、生成された C ファイルで使用できるようにする必要があります。たとえば、Visual C++® を使用する場合は、共有ライブラリ ファイルから暗黙的にインポートされるデータの前に __declspec(dllimport) を宣言します。

このモデルでは次のサンプル アプリケーション ファイルを使用します。

ファイル説明
SharedLibraryCode_app.hサンプル アプリケーションのヘッダー ファイル
SharedLibraryCode_app.cモデル用に生成された共有ライブラリ ファイルを読み込んで使用するサンプル アプリケーション
run_SharedLibraryCode_app.mサンプル アプリケーションをコンパイル、リンク、および実行するスクリプト

モデル ウィンドウで白いボタンをクリックして、これらの各ファイルを表示できます。さらに、スクリプトを実行すると、関連するソース ファイルおよび生成コード ファイルが現在のフォルダーに配置されます。ファイルは、独自の ERT 共有ライブラリ ファイルのアプリケーション コードを記述するためのテンプレートとして使用できます。

以下の節では、サンプル アプリケーション ファイルの主要な抜粋を示します。

サンプル アプリケーションのヘッダー ファイル

サンプル アプリケーションのヘッダー ファイル SharedLibraryCode_app.h には、モデルの外部入力と出力の型宣言が含まれます。

#ifndef _APP_MAIN_HEADER_
#define _APP_MAIN_HEADER_

typedef struct {
    int32_T Input;
} ExternalInputs_SharedLibraryCode;

typedef struct {
    int32_T Output;
} ExternalOutputs_SharedLibraryCode;

#endif /*_APP_MAIN_HEADER_*/

サンプル アプリケーションの C コード

サンプル アプリケーションの SharedLibraryCode_app.c には、共有ライブラリ ファイルを動的に読み込むための次のコードが含まれています。プラットフォームに応じて、コードは Windows または UNIX のライブラリ コマンドを呼び出します。

#if (defined(_WIN32)||defined(_WIN64)) /* WINDOWS */
#include <windows.h>
#define GETSYMBOLADDR GetProcAddress
#define LOADLIB LoadLibrary
#define CLOSELIB FreeLibrary

#else /* UNIX */
#include <dlfcn.h>
#define GETSYMBOLADDR dlsym
#define LOADLIB dlopen
#define CLOSELIB dlclose

#endif

int main()
{
    void* handleLib;
...
#if defined(_WIN64)
    handleLib = LOADLIB("./SharedLibraryCode_win64.dll");
#else
#if defined(_WIN32)
    handleLib = LOADLIB("./SharedLibraryCode_win32.dll");
#else /* UNIX */
    handleLib = LOADLIB("./SharedLibraryCode.so", RTLD_LAZY);
#endif
#endif
...
    return(CLOSELIB(handleLib));
}

以下のコードの抜粋は、C アプリケーションでモデルのエクスポートされたデータと関数にアクセスする方法を示しています。ユーザー定義の初期化コード、ステップ コード、および終了コードを追加するためのフックに注目してください。

    int32_T i;
 ...
    void (*mdl_initialize)(boolean_T);
    void (*mdl_step)(void);
    void (*mdl_terminate)(void);

    ExternalInputs_SharedLibraryCode (*mdl_Uptr);
    ExternalOutputs_SharedLibraryCode (*mdl_Yptr);
        
    uint8_T (*sum_outptr);
...
#if (defined(LCCDLL)||defined(BORLANDCDLL))
    /* Exported symbols contain leading underscores when DLL is linked with
       LCC or BORLANDC */
    mdl_initialize =(void(*)(boolean_T))GETSYMBOLADDR(handleLib ,
                     "_SharedLibraryCode_initialize");
    mdl_step       =(void(*)(void))GETSYMBOLADDR(handleLib ,
                     "_SharedLibraryCode_step");
    mdl_terminate  =(void(*)(void))GETSYMBOLADDR(handleLib ,
                     "_SharedLibraryCode_terminate");
    mdl_Uptr       =(ExternalInputs_SharedLibraryCode*)GETSYMBOLADDR(handleLib ,
                     "_SharedLibraryCode_U");
    mdl_Yptr       =(ExternalOutputs_SharedLibraryCode*)GETSYMBOLADDR(handleLib ,
                     "_SharedLibraryCode_Y");
    sum_outptr     =(uint8_T*)GETSYMBOLADDR(handleLib , "_sum_out");
#else   
    mdl_initialize =(void(*)(boolean_T))GETSYMBOLADDR(handleLib ,
                     "SharedLibraryCode_initialize");
    mdl_step       =(void(*)(void))GETSYMBOLADDR(handleLib ,
                     "SharedLibraryCode_step");
    mdl_terminate  =(void(*)(void))GETSYMBOLADDR(handleLib ,
                     "SharedLibraryCode_terminate");
    mdl_Uptr       =(ExternalInputs_SharedLibraryCode*)GETSYMBOLADDR(handleLib ,
                     "SharedLibraryCode_U");
    mdl_Yptr       =(ExternalOutputs_SharedLibraryCode*)GETSYMBOLADDR(handleLib ,
                     "SharedLibraryCode_Y");
    sum_outptr     =(uint8_T*)GETSYMBOLADDR(handleLib , "sum_out");
#endif
    
    if ((mdl_initialize && mdl_step && mdl_terminate && mdl_Uptr && mdl_Yptr && 
         sum_outptr)) {
        /* === user application initialization function === */
        mdl_initialize(1); 
        /* insert other user defined application initialization code here */
        
        /* === user application step function === */
        for(i=0;i<=12;i++){ 
            mdl_Uptr->Input = i;
            mdl_step(); 
            printf("Counter out(sum_out): %d\tAmplifier in(Input): %d\tout(Output): %d\n",
                   *sum_outptr, i, mdl_Yptr->Output); 
            /* insert other user defined application step function code here */
        }
        
        /* === user application terminate function === */
        mdl_terminate();
        /* insert other user defined application termination code here */
    }
    else {
        printf("Cannot locate the specified reference(s) in the shared library.\n");
        return(-1);
    }

サンプル アプリケーションのスクリプト

アプリケーション スクリプト run_SharedLibraryCode_app はモデルを読み込んでリビルドした後に、モデルの共有ライブラリ ターゲット ファイルをコンパイル、リンク、および実行します。SharedLibraryCode を開き、白いボタンをクリックしてソース コードを表示して、スクリプト ソース ファイルを表示できます。スクリプトで、開発環境に適用される可能性のあるコンパイル、リンク、および実行用のプラットフォーム依存コマンドの文字ベクトルを構成します。スクリプトを実行するには、青いボタンをクリックします。

メモ

1 つの行で終了関数を 2 回呼び出すのは無効です。終了関数はポインターをクリアし、それらを NULL に設定します。関数を 2 回目に呼び出すと NULL ポインターが逆参照され、プログラム エラーになります。

共有ライブラリの制限

共有ライブラリのビルドには、次のような制限が適用されます。

  • ert_shrlib.tlc システム ターゲット ファイルのコード生成では、次のものをデータとしてエクスポートします。

    • ExportedGlobal 型の変数と信号

    • リアルタイム モデル構造体 (model_M)

  • Function-Call Subsystem を含むモデルでは、ert_shrlib.tlc システム ターゲット ファイルのコード生成で、初期化エントリポイント関数と終了エントリポイント関数に関連付けられたシンボルのみが共有ライブラリにエクスポートされます。

  • ert_shrlib.tlc システム ターゲット ファイルのコード生成では、C 言語のみがサポートされています (C++ ではない)。ert_shrlib.tlc を選択すると、モデル コンフィギュレーション パラメーターの [言語] はグレー表示になります。

  • 生成された共有ライブラリを使用してモデル シミュレーションを再構成するには、アプリケーションの作成者は、システムと元のアプリケーションの共有ライブラリ関数呼び出しの間でタイミングを維持しなければなりません。シミュレーション結果と統合結果を比較できるように、タイミングは一貫していなければなりません。モデル コンフィギュレーション パラメーターの [サポート: 連続時間][1 つの出力/更新関数] を有効にするモデルから共有ライブラリを生成している場合、シミュレーションに関するさらなる考慮事項が適用されます。詳細については、1 つの出力/更新関数依存関係を参照してください。

関連するトピック