# 外部函数调用
在 Sysplorer 中,C/C++ 语言编译的外部函数定义方式主要有以下五种:
使用
C文件(例如.c、.h文件),在 annotation 中用 Include 注解包含被调用函数实现的C文件;使用链接库文件(
.lib文件),在 annotation 中用 Library 注解指定链接库,从而调用指定库中的函数。Sysplorer 既支持动态链接库(包含.lib、.dll文件),也支持静态链接库(包含.lib文件);无外部文件,在 annotation 中用 Include 注解直接嵌入 C 代码;
Sysplorer 支持外部函数在环境变量中配置。
Sysplorer 提供了外部函数编辑器,使得用户能够以可视化的方式导入和编辑外部 C/C++ 函数
# 头文件
Modelica 中外部函数声明时用 Include 注解指定所需的.c文件(或.h文件)。IncludeDirectory 注解指定所需的.c文件(或.h文件)所在的位置。
调用的外部函数内容如下,该函数的目的是将输入值相加 。
double add(double a , double b)
{
return a + b;
}
示例1:
model UriTest1
//将外部函数封装成function
function IncTest1
input Real a1;
input Real b1;
output Real c1;
//外部函数声明
//IncludeDirectory注解指定包含文件所在的位置,以URI的modelica模式表示
//Include指定外部函数所需的头文件
external "C" c1 = add(a1, b1)
annotation (IncludeDirectory =
"modelica://ExternFunc/Include",
Include = "#include\"add.c\"");
end IncTest1;
//调用函数IncTest1
Real y = IncTest1(2.0, 3.0);
end UriTest1;
Include 注解:Include = "#include"add.c"" ,表示add.c为外部函数所需的头文件。
IncludeDirectory 注解:IncludeDirectory ="modelica://ExternFunc/Include" ,表示add.c位于 ExternFunc/Include 文件夹中。这里 IncludeDirectory 注解中.c文件所在路径采用了 Modelica 模式 URI 的方式来表示,关于 Modelica 模式 URI 的具体内容请参见外部资源说明。
# 链接库文件
Modelica 中外部函数声明时用 Library 注解指定链接库名(注意:不带扩展名)。LibraryDirectory 注解指定链接库文件和dll(或so)文件所在的位置。
示例2:
model TestExternFuncUseDll
function call_lib
input Real a;
input Real b;
output Real y;
//Library指定链接库
//LibraryDirectory指定库文件所在的位置
external "C" y = add(a, b)
annotation (
Library = "add",
LibraryDirectory = "modelica://ExternFunc/library");
end call_lib;
parameter Real a = 1;
parameter Real b = 2;
Real addr;
equation
addr = call_lib(a, b);
end TestExternFuncUseDll;
上例中指定的链接库名是add,那么完整的链接库名称是add.lib(vc 编译生成)或Load.a(gcc 编译生成),指定的链接库文件和dll(或so)文件所在的位置是ExternFunc/library。此处 Sysplorer 求解器设置为“32 位求解器”。
LibraryDirectory 指定位置中可以使用不同的平台文件夹存放各平台的库文件和dll(或so)文件:
win32 [32 位 Microsoft Windows]
win64 [64 位 Microsoft Windows]
linux32 [Intel 32 位 Linux]
linux64 [Intel 64 位 Linux]
目前 Sysplorer 支持 win32 、win64 平台文件夹。如果没有平台文件夹,就位于指定目录中。如果文件夹 library 下同时存在 win32 和 win64 两个文件夹,则由求解器的位数决定在哪个文件夹中搜索文件。求解器的位数在 仿真设置 >编译 中设置。
Sysplorer 要求保持求解器和链接库文件的一致性,当求解器为 32 位时,相对的链接库文件在 vc 或 gcc 中编译时必须也由 32 位平台生成。
提示
- 一般情况下要求同时具有 IncludeDirectory 注解和 LibraryDirectory 注解;
- 要使模型仿真时能正确找到外部函数相关的资源文件,IncludeDirectory 注解和 LibraryDirectory 注解中指定的文件位置需要遵循 Modelica 模式 URI ,具体内容请参见外部资源。
# 无外部文件
在没有外部文件(C文件或库文件)的情况下,可以直接将 C 代码嵌入到 Include 注解中。但是由于这种方式不适合调试,所以不建议使用。
示例3:
model UriTest2
//将外部函数封装成function
function IncTest2
input Real x1;
input Real x2;
output Real y;
//外部函数声明
//Include引用外部函数的关键字
//add(double x,double y){return x+y;} 外部函数的具体实现
external "C" y = add(x1, x2)
annotation (Include =
"double add(double x,double y)
{
return x+y;
}");
end IncTest2;
//调用函数IncTest2
Real y1 = IncTest2(1.0, 2.0);
end UriTest2;
对应如下的 C 函数原型:
double add(double x,double y);
翻译为 C 中的调用为:
y = add(1.0,2.0);
返回值 y=1.0+2.0=3.0。
# 头文件和库文件的默认搜索路径
如果没有 IncludeDirectory 注解,外部函数所需头文件默认位置是../Resources/Include。同样,若没有 LibraryDirectory 注解,外部函数所需库文件默认位置是../Resources/Library。
下例中外部函数有 Include、Library 注解但没有 IncludeDirectory、LibraryDirectory 注解。
示例4:
package Functions
function ExternalFunc1 "没有 LibraryDirectory 注解,调用该函数时搜索“Resources/Library”子文件"
input Real x;
output Real y;
external "C" y = getreal_arg(x)
annotation (Library = "ExternFunction");
end ExternalFunc1;
function ExternalFunc2 "没有 IncludeDirectory 注解,调用该函数时搜索“Resources/Include”子文件"
input Real x;
output Real y;
external "C" y = getreal_arg(x)
annotation (Include = "#include\"ExportFuncs2.c\"");
end ExternalFunc2;
function ExternalFunc3 "调用该函数时同时搜索“Resources/Library”、“Resources/Include”子文件"
input Real x;
output Real y;
external "C" y = getreal_arg(x)
annotation (Library = "ExternFunction",
Include = "#include\"ExportFuncs.h\"");
end ExternalFunc3;
end Functions;
那么,头文件和库文件的默认搜索路径如下所示: 图中 1 为定义 Modelica 外部函数的模型文件,2 为头文件搜索路径,3 为不同平台库文件搜索路径,4 为 vg 库文件,5为 gcc 库文件。
