外部函数:在 C-script 中引用 headers 到已编译的 dll

External Functions: Reference headers in C-script to compiled dll

使用 Dymola 2017。

案例 A) 调用外部 c-script

我成功实现了没有“#include <-->”语句的简单外部 C 函数:

模型函数:

function chirp

  input Modelica.SIunits.AngularVelocity w_start;
  input Modelica.SIunits.AngularVelocity w_end;
  input Real A;
  input Real M;
  input Real t;
  output Real u "output signal";

  external "C" u=chirp(w_start,w_end,A,M,t)
    annotation(IncludeDirectory="modelica://ExternalFuncTest/Resources/Source/", Include="#include \"chirp.c\"");

end chirp;

C-script:

double chirp(double w1, double w2, double A, double M, double time)
{
  double res;
  res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
    
  return res;
}

案例 B) 在 .dll 文件中调用外部函数

我也成功地在已编译的 dll 中调用外部函数:

模型函数:

function bessel_Jn
  "Bessel function of the 1st kind (regular cylindrical) of order n"

  extends Modelica.Icons.Function;

  input Integer n;
  input Real x;
  output Real y;

  external "C" y=gsl_sf_bessel_Jn(n,x) annotation(LibraryDirectory="modelica://ExternalFuncTest/Resources/Source/gsl-1.8/", Library="libgsl");

end bessel_Jn;

案例 C) 调用外部 c-script,它通过 headers

使用外部 .dll 中的函数

我现在想做的是创建一个 c 函数来做更多有趣的事情。我目前的方法是在引用编译后的 dll(在本例中是 GNU 科学库的编译版本)的 c 函数中包含 header 文件。这个例子有 header(尽管它暂时没有做任何事情)。

模型函数:

function chirp

  input Modelica.SIunits.AngularVelocity w_start;
  input Modelica.SIunits.AngularVelocity w_end;
  input Real A;
  input Real M;
  input Real t;
  output Real u "output signal";

  external "C" u=chirp(w_start,w_end,A,M,t)
    annotation(LibraryDirectory="modelica://ExternalFuncTest/Resources/Source/gsl-1.8/", Library="libgsl",
               IncludeDirectory="modelica://ExternalFuncTest/Resources/Source/", Include="#include \"chirp.c\"");

end chirp;

C-cript:

#include <gsl/gsl_sf_bessel.h> //<-- note the additional header

double chirp(double w1, double w2, double A, double M, double time)
{
  double res;
  res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
  return res;
}

当尝试调用上述函数时,错误指示翻译失败,并且由于 header 文件的存在而没有其他原因。如果 header 文件被注释掉,函数将按预期 运行。

如果您对如何正确实施此功能有任何见解,请告诉我。谢谢。


供参考:下图是外部c-script和.dll.

的路径

错误路径: 注意 gsl header 文件夹在 gsl-1.8 文件夹中

正确路径:注意gsl header文件夹与gsl-1.8文件夹同级


更新: Header 有效但函数调用导致翻译失败

我已将 c-script 更新为现在调用应由 header 处理的函数。在目前的状态下,它是行不通的。也许它找不到 .dll 文件,尽管它在 modelica 代码中指定?我是否必须在 c-script 中包含加载 .dll 命令?

#include <gsl/gsl_sf_bessel.h>

double chirp(double w1, double w2, double A, double M, double time)
{
  double res;
  double y;
  res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
  y = gsl_sf_bessel_j0(time); // <-- Calls a function from the .dll file using the header
  return res;
}

我相信这只能通过相关包含路径或实现未来 Modelica 语言规范 3.4 的未来工具来解决。有关 Modelica 语言规范的相应更新,请参阅 https://trac.modelica.org/Modelica/ticket/2103

您将包含目录设置为 modelica://ExternalFuncTest/Resources/Source/gsl-1.8/ 然后使用 #include <gsl-1.8/gsl/gsl_errno.h>

gsl-1.8目录下真的有gsl-1.8目录吗(有些项目有这样的结构——但一般很少见)?如果不是这种情况,请更改为 #include <gsl/gsl_errno.h>.

我相信也会在路径中搜索分层包含,因此应该可以;否则你总是可以将 includeDirectory 设置为 modelica://ExternalFuncTest/Resources/Source/gsl-1.8/gsl 并使用 #include <gsl_errno.h>.

可以从 c-scripts 引用由 Modelica 外部函数调用调用的已编译库 header。

但是,目前还不确定是否有有效的方法来访问.dll。这在后续问题 External Functions: Alternative Method to use .dll from a C-script.

中进行了讨论

给出了允许识别header个文件的解决方案。感谢所有帮助解决这个问题的人。


步骤 1) 创建文件夹结构

Modelica 会自动在默认目录中查找外部函数依赖项。 modelica.org/documents/ModelicaSpec33Revision1.pdf

的第 12.9.4 节

Modelica 查找已编译库的默认位置是项目资源文件夹中名为 Library 的文件夹:

LibraryDirectory="modelica://LibraryPackageName/Resources/Library"

对于 header 文件和 c-scripts,默认位置是项目资源文件夹中名为 Include 的文件夹:

IncludeDirectory="modelica://LibraryPackageName/Resources/Include"

要指定替代目录,请遵循 modelica 规范文档。从 Modelica Specification 3.3 Rev 1 开始,您只能指定一个 LibraryDirectory 和一个 IncludeDirectory。虽然这可能会在未来得到解决 https://trac.modelica.org/Modelica/ticket/2103.

整体文件夹结构总结

步骤 2) 在上图中指定的位置创建 Modelica 函数和 C-Scripts

以下是可供参考的范例

Modelica 函数

function chirp

  input Modelica.SIunits.AngularVelocity w_start;
  input Modelica.SIunits.AngularVelocity w_end;
  input Real A;
  input Real M;
  input Real t;
  output Real u "output signal";

  external "C" u=chirp(w_start,w_end,A,M,t)
    annotation(Library="libgsl",Include="#include \"chirp.c\"");

end chirp;

C-Script

#include <gsl/gsl_sf_bessel.h>

double chirp(double w1, double w2, double A, double M, double time)
{
  double res;
  res=A*cos(w1*time+(w2-w1)*time*time/(2*M));
  return res;
}