Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 53.8% 14 / 0 / 26
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

OMCompiler/Compiler/Template/CodegenFMUCpp.tpl
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 // This file defines templates for transforming Modelica/MetaModelica code to FMU
37 // code. They are used in the code generator phase of the compiler to write
38 // target code.
39 //
40 // There are one root template intended to be called from the code generator:
41 // translateModel. These template do not return any
42 // result but instead write the result to files. All other templates return
43 // text and are used by the root templates (most of them indirectly).
44 //
45 // To future maintainers of this file:
46 //
47 // - A line like this
48 // # var = "" /*BUFD*/
49 // declares a text buffer that you can later append text to. It can also be
50 // passed to other templates that in turn can append text to it. In the new
51 // version of Susan it should be written like this instead:
52 // let &var = buffer ""
53 //
54 // - A line like this
55 // ..., Text var /*BUFP*/, ...
56 // declares that a template takes a text buffer as input parameter. In the
57 // new version of Susan it should be written like this instead:
58 // ..., Text &var, ...
59 //
60 // - A line like this:
61 // ..., var /*BUFC*/, ...
62 // passes a text buffer to a template. In the new version of Susan it should
63 // be written like this instead:
64 // ..., &var, ...
65 //
66 // - Style guidelines:
67 //
68 // - Try (hard) to limit each row to 80 characters
69 //
70 // - Code for a template should be indented with 2 spaces
71 //
72 // - Exception to this rule is if you have only a single case, then that
73 // single case can be written using no indentation
74 //
75 // This single case can be seen as a clarification of the input to the
76 // template
77 //
78 // - Code after a case should be indented with 2 spaces if not written on the
79 // same line
80
81 package CodegenFMUCpp
82
83 import interface SimCodeTV;
84 import interface SimCodeBackendTV;
85 import CodegenUtil.*;
86 import CodegenCpp.*; //unqualified import, no need the CodegenC is optional when calling a template; or mandatory when the same named template exists in this package (name hiding)
87 import CodegenCppCommon.*;
88 import CodegenFMUModelDescription;
89 import CodegenCppInit;
90 import CodegenFMUCommon;
91 import CodegenFMU2;
92
93 9 template translateModel(SimCode simCode, String FMUVersion, String FMUType, list<String> sourceFiles)
94 "Generates C++ code and Makefile for compiling an FMU of a Modelica model.
95 Calls CodegenCpp.translateModel for the actual model code."
96 ::=
97 match simCode
98 case SIMCODE(modelInfo=modelInfo as MODELINFO(__)) then
99 let guid = getUUIDStr()
100 let target = simulationCodeTarget()
101 let stateDerVectorName = "__zDot"
102 let &extraFuncs = buffer "" /*BUFD*/
103 let &extraFuncsDecl = buffer "" /*BUFD*/
104 let &complexStartExpressions = buffer ""
105
106 let numRealVars = numRealvars(modelInfo)
107 let numIntVars = numIntvars(modelInfo)
108 let numBoolVars = numBoolvars(modelInfo)
109 let numStringVars = numStringvars(modelInfo)
110
111 let extraAnnotations = Flags.getConfigString(FMI_EXTRA_ANNOTATIONS)
112
113 let _ = FlagsUtil.set(Flags.HARDCODED_START_VALUES, true)
114 let cpp = CodegenCpp.translateModel(simCode)
115 let()= textFile(fmuWriteOutputHeaderFile(simCode , &extraFuncs , &extraFuncsDecl, ""),'OMCpp<%fileNamePrefix%>WriteOutput.h')
116 let()= textFile(fmuModelHeaderFile(simCode, extraFuncs, extraFuncsDecl, "",guid, FMUVersion), 'OMCpp<%fileNamePrefix%>FMU.h')
117 let()= textFile(fmuModelCppFile(simCode, extraFuncs, extraFuncsDecl, "",guid, FMUVersion), 'OMCpp<%fileNamePrefix%>FMU.cpp')
118 let()= textFile((if isFMIVersion10(FMUVersion) then CodegenCppInit.modelInitXMLFile(simCode, numRealVars, numIntVars, numBoolVars, numStringVars, FMUVersion, FMUType, guid, true, "cpp-runtime", complexStartExpressions, stateDerVectorName) else
119 CodegenFMUModelDescription.fmuModelDescriptionFile(simCode, guid, FMUVersion, FMUType, sourceFiles)), 'modelDescription.xml')
120 let()= textFile(CodegenFMUCommon.fmudeffile(simCode, FMUVersion), '<%fileNamePrefix%>.def')
121 let()= textFile(fmuMakefile(target, simCode, extraFuncs, extraFuncsDecl, "", FMUVersion, "", "", "", "", extraAnnotations), '<%fileNamePrefix%>_FMU.makefile')
122 let()= textFile(fmuCalcHelperMainfile(simCode), 'OMCpp<%fileNamePrefix%>CalcHelperMain.cpp')
123 let _ = FlagsUtil.set(Flags.HARDCODED_START_VALUES, false)
124
125 ""
126 // Return empty result since result written to files directly
127 end translateModel;
128
129 9 template fmuCalcHelperMainfile(SimCode simCode)
130 ::=
131 match simCode
132 case SIMCODE(modelInfo = MODELINFO(__)) then
133 <<
134 /*****************************************************************************
135 *
136 * Helper file that includes all generated calculation files, except the alg loops.
137 * This file is generated by the OpenModelica Compiler and produced to speed-up the compile time.
138 *
139 *****************************************************************************/
140 #include <Core/ModelicaDefine.h>
141 #include <Core/Modelica.h>
142 #include <Core/System/FactoryExport.h>
143 #include <Core/DataExchange/SimData.h>
144 #include <Core/System/SimVars.h>
145 #include <Core/System/DiscreteEvents.h>
146 #include <Core/System/EventHandling.h>
147 #include <Core/Utils/extension/logger.hpp>
148
149 #include "OMCpp<%fileNamePrefix%>Types.h"
150 #include "OMCpp<%fileNamePrefix%>Functions.h"
151 #include "OMCpp<%fileNamePrefix%>.h"
152
153 #include "OMCpp<%fileNamePrefix%>Jacobian.h"
154 #include "OMCpp<%fileNamePrefix%>Mixed.h"
155 #include "OMCpp<%fileNamePrefix%>StateSelection.h"
156 #include "OMCpp<%fileNamePrefix%>WriteOutput.h"
157 #include "OMCpp<%fileNamePrefix%>Initialize.h"
158
159 #include "OMCpp<%fileNamePrefix%>FMU.h"
160
161 #include "OMCpp<%fileNamePrefix%>AlgLoopMain.cpp"
162 #include "OMCpp<%fileNamePrefix%>Mixed.cpp"
163 #include "OMCpp<%fileNamePrefix%>Functions.cpp"
164 <%if(boolOr(Flags.isSet(Flags.HARDCODED_START_VALUES), Flags.isSet(Flags.GEN_DEBUG_SYMBOLS))) then
165 <<
166 #include "OMCpp<%fileNamePrefix%>InitializeParameter.cpp"
167 #include "OMCpp<%fileNamePrefix%>InitializeAlgVars.cpp"
168 >>
169 %>
170 #include "OMCpp<%fileNamePrefix%>Initialize.cpp"
171 #include "OMCpp<%fileNamePrefix%>Jacobian.cpp"
172 #include "OMCpp<%fileNamePrefix%>StateSelection.cpp"
173 #include "OMCpp<%fileNamePrefix%>.cpp"
174 #include "OMCpp<%fileNamePrefix%>FMU.cpp"
175 >>
176 end fmuCalcHelperMainfile;
177
178 9 template fmuWriteOutputHeaderFile(SimCode simCode ,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace)
179 "Overrides code for writing simulation file. FMU does not write an output file"
180 ::=
181 match simCode
182 case SIMCODE(modelInfo=MODELINFO(__),simulationSettingsOpt = SOME(settings as SIMULATION_SETTINGS(__))) then
183 <<
184 #pragma once
185
186 // Dummy code for FMU that writes no output file
187 class <%lastIdentOfPath(modelInfo.name)%>WriteOutput : public IWriteOutput,public <%lastIdentOfPath(modelInfo.name)%>StateSelection
188 {
189 public:
190 <%lastIdentOfPath(modelInfo.name)%>WriteOutput(IGlobalSettings* globalSettings, shared_ptr<ISimObjects> simObjects): <%lastIdentOfPath(modelInfo.name)%>StateSelection(globalSettings, simObjects) {}
191 virtual ~<%lastIdentOfPath(modelInfo.name)%>WriteOutput() {}
192
193 virtual void writeOutput(const IWriteOutput::OUTPUT command = IWriteOutput::UNDEF_OUTPUT) {}
194 virtual IHistory* getHistory() {return NULL;}
195
196 protected:
197 void initialize() {}
198 };
199 >>
200 end fmuWriteOutputHeaderFile;
201
202 9 template fmuModelHeaderFile(SimCode simCode,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, String guid, String FMUVersion)
203 "Generates declaration for FMU target."
204 ::=
205 match simCode
206 case SIMCODE(modelInfo=MODELINFO(__)) then
207 let modelShortName = lastIdentOfPath(modelInfo.name)
208 //let modelIdentifier = System.stringReplace(dotPath(modelInfo.name), ".", "_")
209 <<
210 // declaration for Cpp FMU target
211
212 class <%modelShortName%>FMU: public <%modelShortName%>Initialize {
213 public:
214 // constructor
215 <%modelShortName%>FMU(IGlobalSettings* globalSettings, shared_ptr<ISimObjects> simObjects);
216
217 // initialization
218 virtual void initialize();
219
220 // getters for given value references
221 virtual void getReal(const unsigned int vr[], size_t nvr, double value[]);
222 virtual void getInteger(const unsigned int vr[], size_t nvr, int value[]);
223 virtual void getBoolean(const unsigned int vr[], size_t nvr, int value[]);
224 virtual void getString(const unsigned int vr[], size_t nvr, string value[]);
225
226 // setters for given value references
227 virtual void setReal(const unsigned int vr[], size_t nvr, const double value[]);
228 virtual void setInteger(const unsigned int vr[], size_t nvr, const int value[]);
229 virtual void setBoolean(const unsigned int vr[], size_t nvr, const int value[]);
230 virtual void setString(const unsigned int vr[], size_t nvr, const string value[]);
231
232 // Jacobian
233 void getDirectionalDerivative(const unsigned int vrUnknown[], size_t nUnknown,
234 const unsigned int vrKnown[], size_t nKnown,
235 const double dvKnown[], double dvUnknown[]);
236
237 protected:
238 static unsigned int _inputRefs[]; ///< Value references of input variables
239 static unsigned int _outputRefs[]; ///< Value references of discrete states and outputs
240 };
241
242 /// create instance of <%modelShortName%>FMU
243 static <%modelShortName%>FMU *createSystemFMU(IGlobalSettings *globalSettings);
244 >>
245 end fmuModelHeaderFile;
246
247 9 template fmuModelCppFile(SimCode simCode,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, String guid, String FMUVersion)
248 "Generates code for FMU target."
249 ::=
250 match simCode
251 case SIMCODE(modelInfo=MODELINFO(vars=SIMVARS(inputVars=inputVars, algVars=algVars)), modelStructure=modelStructure) then
252 let modelName = CodegenUtil.dotPath(modelInfo.name)
253 let modelShortName = lastIdentOfPath(modelInfo.name)
254 let modelLongName = System.stringReplace(modelName, ".", "_")
255 let algloopfiles = (listAppend(listAppend(allEquations, initialEquations), getClockedEquations(getSubPartitions(clockedPartitions))) |> eqs => algloopMainfile2(eqs, simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, modelShortName) ;separator="\n")
256 let solverFactory = match algloopfiles case "" then '' else
257 'createStaticAlgLoopSolverFactory(globalSettings, PATH(""), PATH(""))'
258 <<
259 // define model identifier and unique id
260 #define MODEL_IDENTIFIER <%modelLongName%>
261 #define MODEL_IDENTIFIER_SHORT <%modelShortName%>
262 #define MODEL_CLASS <%modelShortName%>FMU
263 #define MODEL_GUID "{<%guid%>}"
264
265 <%ModelDefineData(modelInfo)%>
266 #define NUMBER_OF_EVENT_INDICATORS <%CodegenFMUCommon.getNumberOfEventIndicators(simCode)%>
267
268 <%if isFMIVersion10(FMUVersion) then
269 '#include <FMU/FMUWrapper.h>'
270 else if isFMIVersion30(FMUVersion) then
271 '#include "FMU3/FMU3Wrapper.cpp"'
272 else
273 '#include "FMU2/FMU2Wrapper.cpp"'%>
274 <%if isFMIVersion30(FMUVersion) then
275 // FMI 3.0 uses its own FMU3Wrapper (included above); the FMI 3.0 C API is
276 // provided by FMU3Interface.cpp using the per-base-type value-reference
277 // offsets defined here (see SimCodeCodegenUtil.getFMI3TypeOffset).
278 (fmi3CppOffsetDefines(simCode) + "\n #include \"FMU3/FMU3Interface.cpp\"")
279 else if isFMIVersion10(FMUVersion) then
280 '#include <FMU/FMULibInterface.h>'
281 else
282 '#include "FMU2/FMU2Interface.cpp"'%>
283
284 // SimObjects for <%modelShortName%>FMU
285 shared_ptr<IAlgLoopSolverFactory> createStaticAlgLoopSolverFactory(IGlobalSettings*, PATH, PATH);
286
287 class <%modelShortName%>SimObjects : public ISimObjects {
288 public:
289 <%modelShortName%>SimObjects(IGlobalSettings *globalSettings) {
290 _algLoopSolverFactory = shared_ptr<IAlgLoopSolverFactory>(<%solverFactory%>);
291 }
292 <%modelShortName%>SimObjects(<%modelShortName%>SimObjects& instance) {
293 _algLoopSolverFactory = instance._algLoopSolverFactory;
294 }
295 weak_ptr<ISimData> LoadSimData(string modelKey) {
296 return shared_ptr<ISimData>();
297 }
298 weak_ptr<ISimVars> LoadSimVars(string modelKey, size_t dim_real, size_t dim_int, size_t dim_bool, size_t dim_string, size_t dim_pre_vars, size_t dim_z, size_t z_i) {
299 _simVars = shared_ptr<ISimVars>(new SimVars(dim_real, dim_int, dim_bool, dim_string, dim_pre_vars, dim_z, z_i));
300 return _simVars;
301 }
302 weak_ptr<IHistory> LoadWriter(size_t) {
303 return shared_ptr<IHistory>();
304 }
305 shared_ptr<ISimData> getSimData(string modelKey) {
306 return shared_ptr<ISimData>();
307 }
308 shared_ptr<ISimVars> getSimVars(string modelKey) {
309 return _simVars;
310 }
311 void eraseSimData(string modelKey) {}
312 void eraseSimVars(string modelKey) {}
313 shared_ptr<IAlgLoopSolverFactory> getAlgLoopSolverFactory() {
314 return _algLoopSolverFactory;
315 }
316
317 ISimObjects* clone() {
318 return new <%modelShortName%>SimObjects(*this);
319 }
320 protected:
321 shared_ptr<ISimVars> _simVars;
322 shared_ptr<IAlgLoopSolverFactory> _algLoopSolverFactory;
323 };
324
325 // create instance of <%modelShortName%>FMU
326 <%modelShortName%>FMU *createSystemFMU(IGlobalSettings *globalSettings) {
327 shared_ptr<ISimObjects> simObjects(new <%modelShortName%>SimObjects(globalSettings));
328 simObjects->LoadSimVars("<%modelShortName%>", <%numRealvars(modelInfo)%>, <%numIntvars(modelInfo)%>, <%numBoolvars(modelInfo)%>, <%numStringvars(modelInfo)%>, <%getPreVarsCount(modelInfo)%>, <%numStatevars(modelInfo)%>, <%numStateVarIndex(modelInfo)%>);
329 simObjects->LoadSimData("<%modelShortName%>");
330 globalSettings->setOutputFormat(EMPTY);
331 return new <%modelShortName%>FMU(globalSettings, simObjects);
332 }
333
334 // value references of real inputs
335 unsigned int <%modelShortName%>FMU::_inputRefs[] = {<%inputVars |> var =>
336 match var case SIMVAR(name=name, type_=T_REAL()) then
337 intSub(getVariableIndex(cref2simvar(name, simCode)), 1) ;separator=", "%>};
338 // value references of real discrete states and outputs
339 unsigned int <%modelShortName%>FMU::_outputRefs[] = {<%algVars |> var =>
340 match var case SIMVAR(name=name, type_=T_REAL(), varKind=CLOCKED_STATE())
341 case SIMVAR(name=name, type_=T_REAL(), causality=SOME(OUTPUT())) then
342 intSub(getVariableIndex(cref2simvar(name, simCode)), 1) ;separator=", "%>};
343
344 // constructor
345 <%modelShortName%>FMU::<%modelShortName%>FMU(IGlobalSettings* globalSettings, shared_ptr<ISimObjects> simObjects)
346 : <%modelShortName%>Initialize(globalSettings, simObjects) {
347 }
348
349 // initialization
350 void <%modelShortName%>FMU::initialize() {
351 <%modelShortName%>WriteOutput::initialize();
352 <%modelShortName%>Initialize::initializeMemory();
353 <%modelShortName%>Initialize::initializeFreeVariables();
354 <%modelShortName%>Jacobian::initialize();
355 }
356
357 // getters
358 <%accessFunctions(simCode, "get", modelShortName, modelInfo)%>
359
360 // setters
361 <%accessFunctions(simCode, "set", modelShortName, modelInfo)%>
362
363 // Jacobian
364 <%directionalDerivativeFunction(simCode)%>
365
366 >>
367 // TODO:
368 // <%setDefaultStartValues(modelInfo)%>
369 // <%setStartValues(modelInfo)%>
370 // <%setExternalFunction(modelInfo)%>
371 end fmuModelCppFile;
372
373 1 template fmi3CppOffsetDefines(SimCode simCode)
374 "Generates the FMI 3.0 per-base-type value-reference offset macros used by
375 FMU3Interface.cpp. They must match SimCodeCodegenUtil.getFMI3TypeOffset, i.e. reals
376 first, then integers, booleans and strings."
377 ::=
378 match simCode
379 case SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__), nClocks=numberOfClocks)) then
380 // emit the per-base-type counts as C preprocessor expressions (the compiler
381 // evaluates them); the offsets are then composed from those, matching
382 // SimCodeCodegenUtil.getFMI3TypeOffset.
383 <<
384 #define FMI3_NUMBER_OF_REALS (2*<%varInfo.numStateVars%> + <%varInfo.numDiscreteReal%> + <%varInfo.numAlgVars%> + <%varInfo.numParams%> + <%varInfo.numAlgAliasVars%>)
385 #define FMI3_NUMBER_OF_INTEGERS (<%varInfo.numIntAlgVars%> + <%varInfo.numIntParams%> + <%varInfo.numIntAliasVars%>)
386 #define FMI3_NUMBER_OF_BOOLEANS (<%varInfo.numBoolAlgVars%> + <%varInfo.numBoolParams%> + <%varInfo.numBoolAliasVars%>)
387 #define FMI3_NUMBER_OF_STRINGS (<%varInfo.numStringAlgVars%> + <%varInfo.numStringParamVars%> + <%varInfo.numStringAliasVars%>)
388 #define FMI3_NUMBER_OF_EXTERNALOBJECTS (<%varInfo.numExternalObjects%>)
389 #define FMI3_NUMBER_OF_CLOCKS (<%numberOfClocks%>)
390 #define FMI3_REAL_VR_OFFSET 0
391 #define FMI3_INTEGER_VR_OFFSET (FMI3_NUMBER_OF_REALS)
392 #define FMI3_BOOLEAN_VR_OFFSET (FMI3_NUMBER_OF_REALS + FMI3_NUMBER_OF_INTEGERS)
393 #define FMI3_STRING_VR_OFFSET (FMI3_NUMBER_OF_REALS + FMI3_NUMBER_OF_INTEGERS + FMI3_NUMBER_OF_BOOLEANS)
394 // external objects are exported as FMI 3.0 Binary, then the model clocks, after the string block
395 #define FMI3_BINARY_VR_OFFSET (FMI3_NUMBER_OF_REALS + FMI3_NUMBER_OF_INTEGERS + FMI3_NUMBER_OF_BOOLEANS + FMI3_NUMBER_OF_STRINGS)
396 #define FMI3_CLOCK_VR_OFFSET (FMI3_NUMBER_OF_REALS + FMI3_NUMBER_OF_INTEGERS + FMI3_NUMBER_OF_BOOLEANS + FMI3_NUMBER_OF_STRINGS + FMI3_NUMBER_OF_EXTERNALOBJECTS)
397 #define FMI3_TIME_VR (FMI3_NUMBER_OF_REALS + FMI3_NUMBER_OF_INTEGERS + FMI3_NUMBER_OF_BOOLEANS + FMI3_NUMBER_OF_STRINGS + FMI3_NUMBER_OF_EXTERNALOBJECTS + FMI3_NUMBER_OF_CLOCKS)
398 #define FMI3_EVENT_INDICATOR_VR_START (FMI3_TIME_VR + 1)
399 #define FMI3_NUMBER_OF_STATES <%varInfo.numStateVars%>
400 >>
401 end fmi3CppOffsetDefines;
402
403 9 template ModelDefineData(ModelInfo modelInfo)
404 "Generates global data in simulation file."
405 ::=
406 match modelInfo
407 case MODELINFO(varInfo=VARINFO(__), vars=SIMVARS(stateVars = listStates)) then
408 <<
409 /* TODO: implement external functions in FMU wrapper for c++ target
410 <%System.tmpTickReset(0)%>
411 <%(functions |> fn => defineExternalFunction(fn) ; separator="\n")%>
412 */
413 >>
414 end ModelDefineData;
415
416 ✗ template DefineVariables(SimVar simVar, Boolean useFlatArrayNotation)
417 "Generates code for defining variables in c file for FMU target. "
418 ::=
419 match simVar
420 case SIMVAR(__) then
421 let description = if comment then '// "<%comment%>"'
422 if stringEq(CodegenUtil.crefStr(name),"$dummy") then
423 <<>>
424 else if stringEq(CodegenUtil.crefStr(name),"der($dummy)") then
425 <<>>
426 else
427 <<
428 #define <%cref(name,useFlatArrayNotation)%>_ <%System.tmpTick()%> <%description%>
429 >>
430 end DefineVariables;
431
432 ✗ template defineExternalFunction(SimCodeFunction.Function fn)
433 "Generates external function definitions."
434 ::=
435 match fn
436 case EXTERNAL_FUNCTION(dynamicLoad=true) then
437 let fname = CodegenUtil.extFunctionName(extName, language)
438 <<
439 #define $P<%fname%> <%System.tmpTick()%>
440 >>
441 end defineExternalFunction;
442
443
444 ✗ template setDefaultStartValues(ModelInfo modelInfo)
445 "Generates code in c file for function setStartValues() which will set start values for all variables."
446 ::=
447 match modelInfo
448 case MODELINFO(varInfo=VARINFO(numStateVars=numStateVars, numAlgVars= numAlgVars),vars=SIMVARS(__)) then
449 <<
450 // Set values for all variables that define a start value
451 void setDefaultStartValues(ModelInstance *comp) {
452 /*
453 <%vars.stateVars |> var => initValsDefault(var,"realVars",0) ;separator="\n"%>
454 <%vars.derivativeVars |> var => initValsDefault(var,"realVars",numStateVars) ;separator="\n"%>
455 <%vars.algVars |> var => initValsDefault(var,"realVars",intMul(2,numStateVars)) ;separator="\n"%>
456 <%vars.discreteAlgVars |> var => initValsDefault(var, "realVars", intAdd(intMul(2,numStateVars), numAlgVars)) ;separator="\n"%>
457 <%vars.intAlgVars |> var => initValsDefault(var,"integerVars",0) ;separator="\n"%>
458 <%vars.boolAlgVars |> var => initValsDefault(var,"booleanVars",0) ;separator="\n"%>
459 <%vars.stringAlgVars |> var => initValsDefault(var,"stringVars",0) ;separator="\n"%>
460 <%vars.paramVars |> var => initParamsDefault(var,"realParameter") ;separator="\n"%>
461 <%vars.intParamVars |> var => initParamsDefault(var,"integerParameter") ;separator="\n"%>
462 <%vars.boolParamVars |> var => initParamsDefault(var,"booleanParameter") ;separator="\n"%>
463 <%vars.stringParamVars |> var => initParamsDefault(var,"stringParameter") ;separator="\n"%>
464 */
465 }
466 >>
467 end setDefaultStartValues;
468
469 ✗ template setStartValues(ModelInfo modelInfo)
470 "Generates code in c file for function setStartValues() which will set start values for all variables."
471 ::=
472 match modelInfo
473 case MODELINFO(varInfo=VARINFO(numStateVars=numStateVars, numAlgVars= numAlgVars),vars=SIMVARS(__)) then
474 <<
475 // Set values for all variables that define a start value
476 void setStartValues(ModelInstance *comp) {
477 /*
478 <%vars.stateVars |> var => initVals(var,"realVars",0) ;separator="\n"%>
479 <%vars.derivativeVars |> var => initVals(var,"realVars",numStateVars) ;separator="\n"%>
480 <%vars.algVars |> var => initVals(var,"realVars",intMul(2,numStateVars)) ;separator="\n"%>
481 <%vars.discreteAlgVars |> var => initVals(var, "realVars", intAdd(intMul(2,numStateVars), numAlgVars)) ;separator="\n"%>
482 <%vars.intAlgVars |> var => initVals(var,"integerVars",0) ;separator="\n"%>
483 <%vars.boolAlgVars |> var => initVals(var,"booleanVars",0) ;separator="\n"%>
484 <%vars.stringAlgVars |> var => initVals(var,"stringVars",0) ;separator="\n"%>
485 <%vars.paramVars |> var => initParams(var,"realParameter") ;separator="\n"%>
486 <%vars.intParamVars |> var => initParams(var,"integerParameter") ;separator="\n"%>
487 <%vars.boolParamVars |> var => initParams(var,"booleanParameter") ;separator="\n"%>
488 <%vars.stringParamVars |> var => initParams(var,"stringParameter") ;separator="\n"%>
489 */
490 }
491 >>
492 end setStartValues;
493
494 ✗ template initVals(SimVar var, String arrayName, Integer offset) ::=
495 match var
496 case SIMVAR(__) then
497 if stringEq(CodegenUtil.crefStr(name),"$dummy") then
498 <<>>
499 else if stringEq(CodegenUtil.crefStr(name),"der($dummy)") then
500 <<>>
501 else
502 let str = 'comp->fmuData->modelData.<%arrayName%>Data[<%intAdd(index,offset)%>].attribute.start'
503 <<
504 <%str%> = comp->fmuData->localData[0]-><%arrayName%>[<%intAdd(index,offset)%>];
505 >>
506 end initVals;
507
508 ✗ template initParams(SimVar var, String arrayName) ::=
509 match var
510 case SIMVAR(__) then
511 let str = 'comp->fmuData->modelData.<%arrayName%>Data[<%index%>].attribute.start'
512 '<%str%> = comp->fmuData->simulationInfo.<%arrayName%>[<%index%>];'
513 end initParams;
514
515
516 ✗ template initValsDefault(SimVar var, String arrayName, Integer offset) ::=
517 match var
518 case SIMVAR(index=index, type_=type_) then
519 let str = 'comp->fmuData->modelData.<%arrayName%>Data[<%intAdd(index,offset)%>].attribute.start'
520 match initialValue
521 case SOME(v) then
522 '<%str%> = <%initVal(v)%>;'
523 case NONE() then
524 match type_
525 case T_INTEGER(__)
526 case T_REAL(__)
527 case T_ENUMERATION(__)
528 case T_BOOL(__) then '<%str%> = 0;'
529 case T_STRING(__) then '<%str%> = "";'
530 else 'UNKOWN_TYPE'
531 end initValsDefault;
532
533 ✗ template initParamsDefault(SimVar var, String arrayName) ::=
534 match var
535 case SIMVAR(__) then
536 let str = 'comp->fmuData->modelData.<%arrayName%>Data[<%index%>].attribute.start'
537 match initialValue
538 case SOME(v) then
539 '<%str%> = <%initVal(v)%>;'
540 end initParamsDefault;
541
542 ✗ template initVal(Exp initialValue)
543 ::=
544 match initialValue
545 case ICONST(__) then integer
546 case RCONST(__) then real
547 case SCONST(__) then '"<%Util.escapeModelicaStringToXmlString(string)%>"'
548 case BCONST(__) then if bool then "1" else "0"
549 case ENUM_LITERAL(__) then '<%index%>/*ENUM:<%CodegenUtil.dotPath(name)%>*/'
550 else "*ERROR* initial value of unknown type"
551 end initVal;
552
553
554 ✗ template setExternalFunction(ModelInfo modelInfo)
555 "Generates setString function for c file."
556 ::=
557 match modelInfo
558 case MODELINFO(vars=SIMVARS(__)) then
559 let externalFuncs = setExternalFunctionsSwitch(functions)
560 <<
561 fmiStatus setExternalFunction(ModelInstance* c, const fmiValueReference vr, const void* value){
562 switch (vr) {
563 /*
564 <%externalFuncs%>
565 */
566 default:
567 return fmiError;
568 }
569 return fmiOK;
570 }
571
572 >>
573 end setExternalFunction;
574
575 ✗ template setExternalFunctionsSwitch(list<SimCodeFunction.Function> functions)
576 "Generates external function definitions."
577 ::=
578 (functions |> fn => setExternalFunctionSwitch(fn) ; separator="\n")
579 end setExternalFunctionsSwitch;
580
581 ✗ template setExternalFunctionSwitch(SimCodeFunction.Function fn)
582 "Generates external function definitions."
583 ::=
584 match fn
585 case EXTERNAL_FUNCTION(dynamicLoad=true) then
586 let fname = CodegenUtil.extFunctionName(extName, language)
587 <<
588 case $P<%fname%> : ptr_<%fname%>=(ptrT_<%fname%>)value; break;
589 >>
590 end setExternalFunctionSwitch;
591
592 18 template accessFunctions(SimCode simCode, String direction, String modelShortName, ModelInfo modelInfo)
593 "Generates getters or setters for Real, Integer, Boolean, and String."
594 ::=
595 match modelInfo
596 case MODELINFO(vars=SIMVARS(__), varInfo=VARINFO(numStateVars=numStateVars, numAlgVars=numAlgVars, numDiscreteReal=numDiscreteReal, numParams=numParams)) then
597 <<
598 <%accessVarsFunction(simCode, direction, modelShortName, "Real", "Real", "double", intAdd(intAdd(intAdd(intMul(2, numStateVars), numAlgVars), numDiscreteReal), numParams), vars.aliasVars)%>
599 <%accessVarsFunction(simCode, direction, modelShortName, "Integer", "Int", "int", intAdd(listLength(vars.intAlgVars), listLength(vars.intParamVars)), vars.intAliasVars)%>
600 <%accessVarsFunction(simCode, direction, modelShortName, "Boolean", "Bool", "int", intAdd(listLength(vars.boolAlgVars), listLength(vars.boolParamVars)), vars.boolAliasVars)%>
601 <%accessVarsFunction(simCode, direction, modelShortName, "String", "String", "string", intAdd(listLength(vars.stringAlgVars), listLength(vars.stringParamVars)), vars.stringAliasVars)%>
602 >>
603 end accessFunctions;
604
605 72 template accessVarsFunction(SimCode simCode, String direction, String modelShortName, String typeName, String pointerName, String typeImpl, Integer offset, list<SimVar> aliasVars)
606 "Generates get<%typeName%> or set<%typeName%> function."
607 ::=
608 let qualifier = if stringEq(direction, "set") then "const"
609 <<
610 void <%modelShortName%>FMU::<%direction%><%typeName%>(const unsigned int vr[], size_t nvr, <%qualifier%> <%typeImpl%> value[]) {
611 for (size_t i = 0; i < nvr; i++, vr++, value++) {
612 // access variables and aliases in SimVars memory
613 if (*vr < _dim<%typeName%>)
614 <%if stringEq(direction, "get") then
615 <<
616 *value = _pointerTo<%pointerName%>Vars[*vr];
617 >>
618 else
619 <<
620 _pointerTo<%pointerName%>Vars[*vr] = *value;
621 >>%>
622 // convert negated aliases
623 else switch (*vr) {
624 <%aliasVars |> var => match var
625 case SIMVAR(aliasvar=NEGATEDALIAS()) then
626 accessVar(simCode, direction, var, offset)
627 else ''
628 end match; separator="\n"%>
629 default:
630 throw std::invalid_argument("<%direction%><%typeName%> with wrong value reference " + omcpp::to_string(*vr));
631 }
632 }
633 }
634 >>
635 end accessVarsFunction;
636
637 14 template accessVar(SimCode simCode, String direction, SimVar simVar, Integer offset)
638 "Generates a case statement accessing one variable."
639 ::=
640 match simVar
641 case SIMVAR(__) then
642 let descName = System.stringReplace(crefStrNoUnderscore(name), "$", "_D_")
643 let description = if comment then '/* <%descName%> "<%comment%>" */' else '/* <%descName%> */'
644 let cppName = getCppName(simCode, simVar)
645 let cppSign = getCppSign(simCode, simVar)
646 if stringEq(direction, "get") then
647 <<
648 case <%intAdd(offset, index)%>: <%description%>
649 *value = <%cppSign%><%cppName%>; break;
650 >>
651 else
652 <<
653 case <%intAdd(offset, index)%>: <%description%>
654 <%cppName%> = <%cppSign%>*value; break;
655 >>
656 end accessVar;
657
658 14 template getCppName(SimCode simCode, SimVar simVar)
659 "Get name of variable in Cpp runtime, resolving aliases"
660 ::=
661 match simVar
662 case SIMVAR(__) then
663 let actualName = cref1(name, simCode, "", "", "", contextOther, "", "", false)
664 match aliasvar
665 case ALIAS(__)
666 case NEGATEDALIAS(__) then
667 '<%cref1(varName, simCode, "", "", "", contextOther, "", "", false)%>'
668 else
669 '<%actualName%>'
670 end getCppName;
671
672 14 template getCppSign(SimCode simCode, SimVar simVar)
673 "Get sign of variable in Cpp runtime, resolving aliases"
674 ::=
675 match simVar
676 case SIMVAR(type_=type_) then
677 match aliasvar
678 case NEGATEDALIAS(__) then
679 match type_ case T_BOOL(__) then '!' else '-'
680 else ''
681 end getCppSign;
682
683 9 template directionalDerivativeFunction(SimCode simCode)
684 "Generates getDirectionalDerivative."
685 ::=
686 match simCode
687 case SIMCODE(modelInfo=MODELINFO(), modelStructure=fmiModelStructure) then
688 let modelShortName = lastIdentOfPath(modelInfo.name)
689 let dimDiscreteStates = match fmiModelStructure
690 case SOME(modelStructure as FMIMODELSTRUCTURE(__)) then
691 match modelStructure.fmiDiscreteStates
692 case FMIDISCRETESTATES(fmiUnknownsList=fmiUnknownsList) then
693 listLength(fmiUnknownsList)
694 else "0"
695 else "0"
696 <<
697 void <%modelShortName%>FMU::getDirectionalDerivative(
698 const unsigned int vrUnknown[], size_t nUnknown,
699 const unsigned int vrKnown[], size_t nKnown,
700 const double dvKnown[], double dvUnknown[])
701 {
702 <% if providesDirectionalDerivative(simCode) then
703 <<
704 unsigned int idx, *ref_p, ref_1;
705 int dimStates = _dimContinuousStates + <%dimDiscreteStates%>;
706
707 _FMIDERjac_x.clear();
708 ref_p = NULL;
709 for (size_t j = 0; j < nKnown; j++) {
710 idx = vrKnown[j];
711 if (idx >= dimStates) {
712 // find input reference
713 if (ref_p == NULL || idx < ref_1)
714 ref_p = _inputRefs; // reset ref_p if vrKnown decreases
715 ref_p = std::find(ref_p, _inputRefs + sizeof(_inputRefs)/sizeof(unsigned int), vrKnown[j]);
716 ref_1 = idx;
717 idx = dimStates + (ref_p - _inputRefs);
718 }
719 if (idx >= _FMIDERjac_x.size())
720 throw std::invalid_argument("getDirectionalDerivative with wrong value reference of known " + omcpp::to_string(vrKnown[j]));
721 _FMIDERjac_x(idx) = dvKnown[j];
722 }
723 calcFMIDERJacobianColumn();
724 ref_p = NULL;
725 for (size_t i = 0; i < nUnknown; i++) {
726 idx = vrUnknown[i] - _dimContinuousStates; // derivatives behind states
727 if (idx >= _dimContinuousStates) {
728 // find output reference
729 if (ref_p == NULL || idx < ref_1)
730 ref_p = _outputRefs; // reset ref_p if vrUnknown decreases
731 ref_p = std::find(ref_p, _outputRefs + sizeof(_outputRefs)/sizeof(unsigned int), vrUnknown[i]);
732 ref_1 = idx;
733 idx = _dimContinuousStates + (ref_p - _outputRefs);
734 }
735 if (idx >= _FMIDERjac_y.size())
736 throw std::invalid_argument("getDirectionalDerivative with wrong value reference of unknown " + omcpp::to_string(vrUnknown[i]));
737 dvUnknown[i] = _FMIDERjac_y(idx);
738 }
739 >>
740 else
741 <<
742 throw ModelicaSimulationError(MATH_FUNCTION, "No derivative code, see flag disableDirectionalDerivatives");
743 >>
744 %>
745 }
746 >>
747 end directionalDerivativeFunction;
748
749 9 template fmuMakefile(String target, SimCode simCode, Text& extraFuncs, Text& extraFuncsDecl, Text extraFuncsNamespace, String FMUVersion, String additionalLinkerFlags_GCC,
750 String additionalLinkerFlags_MSVC, String additionalCFlags_GCC, String additionalCFlags_MSVC, String extraAnnotations)
751 "Generates the contents of the makefile for the simulation case. Copy libexpat & correct linux fmu"
752 ::=
753 match getGeneralTarget(target)
754 case "msvc" then
755 match simCode
756 case SIMCODE(modelInfo=MODELINFO(__), makefileParams=MAKEFILE_PARAMS(__), simulationSettingsOpt = sopt) then
757 let dirExtra = if modelInfo.directory then '-L"<%modelInfo.directory%>"' //else ""
758 let libsExtra = (makefileParams.libs |> lib => lib ;separator=" ")
759 let ParModelicaLibs = if acceptParModelicaGrammar() then '-lOMOCLRuntime -lOpenCL' // else ""
760 let extraCflags = match sopt case SOME(s as SIMULATION_SETTINGS(__)) then
761 match s.method case "dassljac" then "-D_OMC_JACOBIAN "
762 <<
763 # Makefile generated by OpenModelica
764 # run with nmake from Visual Studio Command Prompt
765 # FMU packaging requires PATH to <%makefileParams.omhome%>/mingw/bin
766 OMHOME=<%if boolOr(stringEq(makefileParams.platform, "win32"),stringEq(makefileParams.platform, "win64")) then '$(OPENMODELICAHOME)' else makefileParams.omhome%>
767 <% /* Don't use $(OMHOME) with include. NMAKE fails to evaluate it. */ %>
768 include <%makefileParams.omhome%>/include/omc/cpp/ModelicaConfig_msvc.inc
769 include <%makefileParams.omhome%>/include/omc/cpp/ModelicaLibraryConfig_msvc.inc
770 # Simulations use /Od by default
771 SIM_OR_DYNLOAD_OPT_LEVEL=
772 MODELICAUSERCFLAGS=
773 CXX=cl
774 EXEEXT=.exe
775 DLLEXT=.dll
776
777 # /Od - Optimization disabled
778 # /EHa enable C++ EH (w/ SEH exceptions)
779 # /fp:except - consider floating-point exceptions when generating code
780 # /arch:SSE2 - enable use of instructions available with SSE2 enabled CPUs
781 # /I - Include Directories
782 # /DNOMINMAX - Define NOMINMAX (does what it says)
783 # /TP - Use C++ Compiler
784
785 CFLAGS=$(SYSTEM_CFLAGS) /w /I"<%makefileParams.omhome%>/include/omc/cpp/" /I"$(SUITESPARSE_INCLUDE)" /I. /TP /DNOMINMAX /DNO_INTERACTIVE_DEPENDENCY /DFMU_BUILD /DRUNTIME_STATIC_LINKING
786
787
788 # /MD - link with MSVCRT.LIB
789 # /link - [linker options and libraries]
790 # /LIBPATH: - Directories where libs can be found
791 OMCPP_SOLVER_LIBS=OMCppNewton_static.lib OMCppDgesv_static.lib OMCppDgesvSolver_static.lib -lOMCppSolver_static
792 MODELICA_UTILITIES_LIB=OMCppModelicaUtilities_static.lib
793 EXTRA_LIBS=<%dirExtra%> <%libsExtra%>
794
795 LDFLAGS=/link /DLL /NOENTRY /LIBPATH:"<%makefileParams.omhome%>/lib/<%Config.targetTriple()%>/omc/cpp" /LIBPATH:"<%makefileParams.omhome%>/bin" OMCppSystem_static.lib OMCppMath_static.lib OMCppExtensionUtilities_static.lib OMCppFMU_static.lib $(OMCPP_SOLVER_LIBS) $(EXTRA_LIBS) $(MODELICA_UTILITIES_LIB)
796
797 PLATFORM="<%makefileParams.platform%>"
798
799 MODELICA_SYSTEM_LIB=<%fileNamePrefix%>
800 CALCHELPERMAINFILE=OMCpp$(MODELICA_SYSTEM_LIB)CalcHelperMain.cpp
801
802 <%fmuTargetName%>.fmu: $(MODELICA_SYSTEM_LIB)$(DLLEXT)
803 <%\t%>rm -rf binaries
804 <%\t%>mkdir -p "binaries/$(PLATFORM)"
805 <%\t%>mv $(MODELICA_SYSTEM_LIB)$(DLLEXT) "binaries/$(PLATFORM)/"
806 <%\t%>rm -f $(MODELICA_SYSTEM_LIB).fmu
807 <%\t%>zip -r "<%fmuTargetName%>.fmu" modelDescription.xml binaries
808 <%\t%>rm -rf binaries
809
810 $(MODELICA_SYSTEM_LIB)$(DLLEXT):
811 <%\t%>$(CXX) /Fe$(MODELICA_SYSTEM_LIB)$(DLLEXT) $(CALCHELPERMAINFILE) $(CFLAGS) $(LDFLAGS)
812 >>
813 end match
814 case "gcc" then
815 match simCode
816 case SIMCODE(modelInfo=MODELINFO(__), makefileParams=MAKEFILE_PARAMS(__), simulationSettingsOpt = sopt) then
817 let dirExtra = if modelInfo.directory then '-L"<%modelInfo.directory%>"' //else ""
818 let libsExtra = (makefileParams.libs |> lib => lib ;separator=" ")
819 let extraCflags = match sopt case SOME(s as SIMULATION_SETTINGS(__)) then ""
820 // Note: FMI 1.0 did not distinguish modelIdentifier from fileNamePrefix
821 // FMI 3.0 uses the "{arch}-{os}" platform tuple for the binaries folder
822 // (e.g. x86_64-linux), unlike FMI 1.0/2.0 which use "{os}{bitness}" (linux64).
823 let platformstr = if isFMIVersion30(FMUVersion) then
824 (match makefileParams.platform
825 case "i386-pc-linux" case "linux32" case "i686-linux" then 'i686-linux'
826 case "x86_64-linux" case "linux64" then 'x86_64-linux'
827 case "win64" then 'x86_64-windows'
828 case "win32" then 'i686-windows'
829 case "darwin64" then 'x86_64-darwin'
830 else '<%makefileParams.platform%>')
831 else
832 (match makefileParams.platform case "i386-pc-linux" then 'linux32' case "x86_64-linux" then 'linux64' else '<%makefileParams.platform%>')
833 let omhome = makefileParams.omhome
834 let lapackbins = match platformstr case "win32" case "win64" case "i686-windows" case "x86_64-windows" then '"<%omhome%>/bin/libopenblas.dll"' else ''
835 let mkdir = match makefileParams.platform case "win32" case "win64" then '"mkdir.exe"' else 'mkdir'
836 <<
837 # Makefile generated by OpenModelica for native and cross compilation
838 # How to cross compile:
839 # - build OpenModelica (omc) from source code (see github.com/OpenModelica)
840 # - install a cross compiler, e.g. apt-get install g++-mingw-w64-i686
841 # - fix or work around capitalization of windows.h in MSL, see
842 # https://trac.modelica.org/Modelica/ticket/1962
843 # - add the target triplet, e.g. i686-w64-mingw32, to
844 # OMCompiler/SimulationRuntime/cpp/Makefile
845 # - rebuild omc to add the new platform
846 # - invoke the omc commands
847 # setCommandLineOptions("--simCodeTarget=Cpp");
848 # buildModelFMU(MyModel, platforms={"i686-w64-mingw32"});
849 # - alternatively call this Makefile with
850 # make TARGET_TRIPLET=i686-w64-mingw32 -f <%fileNamePrefix%>_FMU.makefile
851
852 #TARGET_TRIPLET=
853 # escape spaces for make
854 empty :=
855 space := $(empty) $(empty)
856 escape_path = $(subst $(space),\$(space),$1)
857
858 OMHOME:=<%if boolOr(stringEq(makefileParams.platform, "win32"),stringEq(makefileParams.platform, "win64")) then '$(OPENMODELICAHOME)' else makefileParams.omhome%>
859 OMHOME_ESCAPED:=$(call escape_path,$(OMHOME))
860 include $(OMHOME_ESCAPED)/include/omc/cpp/ModelicaConfig_gcc.inc
861 include $(OMHOME_ESCAPED)/include/omc/cpp/ModelicaLibraryConfig_gcc.inc
862
863 # simulations use -O0 by default; can be changed to e.g. -O2 or -Ofast
864 SIM_OPT_LEVEL=-O0
865 # the default is ON by default, override the var from commandLine to skip the zipping of fmu e.g. make -f ZIP_FMU=OFF
866 ZIP_FMU = ON
867 # native build or cross compilation
868 ifeq ($(TARGET_TRIPLET),)
869 TRIPLET=<%Config.targetTriple()%>
870 CC=<%makefileParams.ccompiler%>
871 CXX=<%makefileParams.cxxcompiler%>
872 ABI_CFLAG=
873 DLLEXT=<%makefileParams.dllext%>
874 PLATFORM=<%platformstr%>
875 else
876 TRIPLET=$(TARGET_TRIPLET)
877 CC=$(TRIPLET)-gcc
878 CXX=$(TRIPLET)-g++
879 ABI_CFLAG=-D_GLIBCXX_USE_CXX11_ABI=0
880 DLLEXT=$(if $(findstring mingw,$(TRIPLET)),.dll,.so)
881 WORDSIZE=$(if $(findstring x86_64,$(TRIPLET)),64,32)
882 PLATFORM=$(if $(findstring darwin,$(TRIPLET)),darwin,$(if $(findstring mingw,$(TRIPLET)),win,linux))$(WORDSIZE)
883 endif
884
885 CFLAGS_BASED_ON_INIT_FILE=<%extraCflags%>
886 FMU_CFLAGS=$(subst -DUSE_THREAD,,$(subst -O0,$(SIM_OPT_LEVEL),$(SYSTEM_CFLAGS))) $(ABI_CFLAG)
887 CFLAGS=$(CFLAGS_BASED_ON_INIT_FILE) -Winvalid-pch $(FMU_CFLAGS) -DFMU_BUILD -DRUNTIME_STATIC_LINKING -I"$(OMHOME)/include/omc/cpp" -I"$(UMFPACK_INCLUDE)" -I"$(SUNDIALS_INCLUDE)" <%makefileParams.includes ; separator=" "%> <%additionalCFlags_GCC%>
888
889 ifeq ($(USE_LOGGER),ON)
890 $(eval CFLAGS=$(CFLAGS) -DUSE_LOGGER)
891 endif
892
893 LDFLAGS=-L"$(OMHOME)/lib/$(TRIPLET)/omc/cpp" <%additionalLinkerFlags_GCC%> $(SYSTEM_LDFLAGS)
894 ifeq ($(findstring linux,$(PLATFORM)),linux)
895 LDFLAGS+=-Wl,--no-undefined
896 endif
897
898 CALCHELPERMAINFILE=OMCpp<%fileNamePrefix%>CalcHelperMain.cpp
899
900 # CVode can be used for Co-Simulation FMUs, Kinsol is available to handle non linear equation systems
901 OMCPP_SOLVER_LIBS=-lOMCppNewton_static -lOMCppDgesvSolver_static -lOMCppSolver_static
902 ifeq ($(USE_FMU_SUNDIALS),ON)
903 $(eval OMCPP_SOLVER_LIBS=$(OMCPP_SOLVER_LIBS) -lOMCppKinsol_static $(SUNDIALS_LIBRARIES))
904 $(eval CFLAGS=-DENABLE_SUNDIALS_STATIC $(CFLAGS))
905 endif
906
907 CPPFLAGS=$(CFLAGS)
908
909 BINARIES=<%fileNamePrefix%>$(DLLEXT)
910
911 OMCPP_LIBS=-lOMCppSystem_static -lOMCppMath_static -lOMCppFMU_static $(OMCPP_SOLVER_LIBS) -lOMCppExtensionUtilities_static
912 MODELICA_UTILITIES_LIB=-lOMCppModelicaUtilities_static
913 EXTRA_LIBS=<%dirExtra%> <%libsExtra%>
914 LIBS=$(EXTRA_LIBS) $(OMCPP_LIBS) $(MODELICA_UTILITIES_LIB) $(BASE_LIB)
915
916 # link with simple dgesv or full lapack
917 ifeq ($(USE_DGESV),ON)
918 $(eval LIBS=$(LIBS) -lOMCppDgesv_static)
919 else
920 $(eval LIBS=$(LIBS) -L$(LAPACK_LIBS) $(LAPACK_LIBRARIES))
921 $(eval BINARIES=$(BINARIES) <%lapackbins%>)
922 endif
923
924 # link static libs to avoid dependencies; can't link all static under Linux
925 ifeq ($(findstring gcc,$(CC)),gcc)
926 $(eval LIBS=$(LIBS) $(if $(findstring linux,$(PLATFORM)),-static-libstdc++ -static-libgcc))
927 else ifeq ($(findstring clang,$(CC)),clang)
928 $(eval LIBS=$(LIBS) $(if $(findstring linux,$(PLATFORM)),-static-libstdc++ -static-libgcc))
929 endif
930 ifeq ($(findstring linux,$(PLATFORM))$(findstring darwin,$(PLATFORM)),)
931 $(eval LIBS=$(LIBS) -static)
932 endif
933
934 CPPFILES=$(CALCHELPERMAINFILE)
935 OFILES=$(CPPFILES:.cpp=.o)
936
937 .PHONY: <%fmuTargetName%>.fmu $(CPPFILES) clean
938
939 <%fmuTargetName%>.fmu: $(OFILES)
940 <%\t%>$(CXX) -shared -o <%fileNamePrefix%>$(DLLEXT) $(OFILES) $(LDFLAGS) $(LIBS)
941 <%\t%><%mkdir%> -p "binaries/$(PLATFORM)"
942 # copy (do not move): $(BINARIES) includes shared dependency DLLs such as
943 # libopenblas.dll taken from <omhome>/bin; moving them out would break a
944 # second FMU export in the same session (the C target copies here too).
945 <%\t%>cp $(BINARIES) "binaries/$(PLATFORM)/"
946 <%\t%>rm -rf sources
947 <%\t%><%mkdir%> -p sources
948 <%\t%>install -p OMCpp<%fileNamePrefix%>*.h OMCpp<%fileNamePrefix%>*.cpp <%fileNamePrefix%>_init.xml <%fileNamePrefix%>_FMU.makefile sources/
949 ifeq ($(USE_FMU_SUNDIALS),ON)
950 <%\t%>rm -rf documentation
951 <%\t%><%mkdir%> -p "documentation"
952 <%\t%>cp $(SUNDIALS_LIBRARIES_KINSOL) "binaries/$(PLATFORM)/"
953 <%\t%>cp "$(OMHOME)/share/omc/runtime/cpp/licenses/sundials.license" "documentation/"
954 endif
955 <%\t%>rm -f <%fmuTargetName%>.fmu
956 ifeq ($(ZIP_FMU),ON)
957 ifeq ($(USE_FMU_SUNDIALS),ON)
958 <%\t%>zip -r "<%fmuTargetName%>.fmu" modelDescription.xml binaries sources documentation
959 <%\t%>rm -rf documentation
960 else
961 <%\t%>zip -r "<%fmuTargetName%>.fmu" modelDescription.xml binaries sources
962 endif
963 endif
964 ifneq ("<%extraAnnotations%>","")
965 <%\t%><%mkdir%> -p extra/org.openmodelica
966 ifneq ("$(wildcard <%fileNamePrefix%>_modelInstance.json)","")
967 <%\t%>jq --arg regex "<%extraAnnotations%>" -f "$(OMHOME)/share/omc/scripts/filter-annotations.jq" <%fileNamePrefix%>_modelInstance.json > extra/org.openmodelica/modelAnnotations.json
968 endif
969 ifeq ($(ZIP_FMU),ON)
970 <%\t%>zip -ur "<%fmuTargetName%>.fmu" extra
971 endif
972 endif
973
974 ifeq ($(ZIP_FMU),OFF)
975 <%\t%>rm -f OMCpp<%fileNamePrefix%>* <%fileNamePrefix%>_FMU.* <%fileNamePrefix%>.def <%fileNamePrefix%>.sh <%fileNamePrefix%>.bat <%fileNamePrefix%>.makefile <%fileNamePrefix%>_init.xml
976 <%\t%>rm -f <%fileNamePrefix%>_modelInstance.json
977 endif
978
979 clean:
980 <%\t%>rm -f OMCpp<%fileNamePrefix%>* <%fileNamePrefix%>_FMU.* <%fileNamePrefix%>.def <%fileNamePrefix%>.sh <%fileNamePrefix%>.bat <%fileNamePrefix%>.makefile <%fileNamePrefix%>_init.xml
981 <%\t%>rm -rf modelDescription.xml binaries sources documentation extra <%fileNamePrefix%>_modelInstance.json
982
983 >>
984 end fmuMakefile;
985
986 annotation(__OpenModelica_Interface="codegen_cpp_ext");
987 end CodegenFMUCpp;
988
989 // vim: filetype=susan sw=2 sts=2
990