将生成的代码打包为共享库
如果您有 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
要生成和使用共享库,请执行下列步骤:
生成模型代码的共享库版本
创建应用程序代码来加载和使用您的共享库文件
生成模型代码的共享库版本
要生成模型代码的共享库版本,请执行下列步骤:
打开您的模型,并将其配置为使用
ert_shrlib.tlc
系统目标文件。选择
ert_shrlib.tlc
系统目标文件会使编译过程在当前工作文件夹中生成模型代码的共享库版本。该选择不会更改代码生成器为您的模型生成的代码。编译模型。
在编译完成后,检查模型子文件夹中生成的代码,并检查当前文件夹中的
.dll
、.so
或.dylib
文件。
创建应用程序代码以使用共享库
为了说明应用程序代码如何加载共享库文件并访问其函数和数据,MathWorks 提供了模型 SharedLibraryCode
。要检查模型,请从 MATLAB® 命令行窗口运行此命令:
openExample('SharedLibraryCode');
在模型中,点击蓝色按钮以运行脚本。脚本:
根据模型编译一个共享库文件(例如,在 64 位 Windows 上为
SharedLibraryCode_win64.dll
)。编译并链接一个加载和使用该共享库文件的示例应用程序
SharedLibraryCode_app
。执行该示例应用程序。
提示
为便于移植,最好使用显式链接。但是,在 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(BORLANDCDLL)) /* Exported symbols contain leading underscores when DLL is linked with 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
并点击白色按钮以查看源代码。该脚本会基于平台构造适用于您的开发环境的编译、链接和执行命令字符向量。要运行该脚本,请点击蓝色按钮。
注意
连续两次调用终止函数是无效的。终止函数会清除指针并将它们设置为 NULL。第二次调用该函数会解引用空指针,这将导致程序失败。
共享库的限制
编译共享库存在以下限制:
针对
ert_shrlib.tlc
系统目标文件的代码生成会将以下内容导出为数据:ExportedGlobal
类型的变量和信号实时模型结构 (
)model
_M
对于包含函数调用子系统的模型,
ert_shrlib.tlc
系统目标文件的代码生成仅将与初始化和终止入口函数相关联的符号导出到共享库。ert_shrlib.tlc
系统目标文件的代码生成仅支持 C 语言(不支持 C++)。当您选择ert_shrlib.tlc
时,模型配置参数语言会灰显。要使用生成的共享库重新构造模型仿真,应用程序作者必须保持原始应用程序中系统和共享库函数调用之间的时序。时序需要一致,以便您比较仿真和集成结果。如果从启用了模型配置参数支持连续时间和单一输出/更新函数的模型生成共享库,则需要考虑其他仿真因素。有关详细信息,请参阅Single output/update function。