pythonfmu3 0.3.3__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. pythonfmu3/_version.py +1 -1
  2. pythonfmu3/builder.py +96 -24
  3. pythonfmu3/fmi3slave.py +80 -40
  4. pythonfmu3/modelexchange.py +17 -2
  5. pythonfmu3/osutil.py +34 -9
  6. pythonfmu3/pythonfmu-export/CMakeLists.txt +36 -4
  7. pythonfmu3/pythonfmu-export/generate_shim.py +88 -0
  8. pythonfmu3/pythonfmu-export/src/CMakeLists.txt +41 -13
  9. pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp +3 -0
  10. pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp +20 -10
  11. pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp +20 -10
  12. pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp +16 -14
  13. pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp +570 -570
  14. pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp +30 -17
  15. pythonfmu3/pythonfmu-export/src/shim/fmi3_forwarders.cpp +612 -0
  16. pythonfmu3/pythonfmu-export/src/shim/shim_loader.cpp +157 -0
  17. pythonfmu3/pythonfmu-export/src/shim/shim_loader.hpp +29 -0
  18. pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-backend.so +0 -0
  19. pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so +0 -0
  20. pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll +0 -0
  21. pythonfmu3/tests/data/fmi3_host.c +31 -0
  22. pythonfmu3/tests/fmi3_ctypes_driver.py +137 -0
  23. pythonfmu3/tests/slaves/pythonslave_arraytypes.py +80 -0
  24. pythonfmu3/tests/test_builder.py +48 -2
  25. pythonfmu3/tests/test_docs.py +70 -61
  26. pythonfmu3/tests/test_integration.py +106 -0
  27. pythonfmu3/tests/test_non_python_host.py +75 -0
  28. pythonfmu3/tests/test_osutil.py +23 -0
  29. pythonfmu3/tests/test_variables.py +1 -1
  30. pythonfmu3/tests/test_wrapper_ctypes.py +61 -0
  31. pythonfmu3/variables.py +72 -47
  32. {pythonfmu3-0.3.3.dist-info → pythonfmu3-1.0.0.dist-info}/METADATA +61 -25
  33. {pythonfmu3-0.3.3.dist-info → pythonfmu3-1.0.0.dist-info}/RECORD +37 -26
  34. {pythonfmu3-0.3.3.dist-info → pythonfmu3-1.0.0.dist-info}/WHEEL +1 -1
  35. {pythonfmu3-0.3.3.dist-info → pythonfmu3-1.0.0.dist-info}/entry_points.txt +0 -0
  36. {pythonfmu3-0.3.3.dist-info → pythonfmu3-1.0.0.dist-info}/licenses/LICENSE +0 -0
  37. {pythonfmu3-0.3.3.dist-info → pythonfmu3-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,88 @@
1
+ """Generate src/shim/fmi3_forwarders.cpp from src/fmi/fmi3FunctionTypes.h.
2
+
3
+ The shim is the library the importer loads on Linux/macOS. It has no link-time
4
+ dependency on libpython: on instantiation it loads libpython (unless the host process
5
+ already provides it, e.g. when the importer is itself written in Python) and then the
6
+ real implementation (the "backend" library), and forwards every FMI call to it.
7
+
8
+ Re-run this script after updating the FMI headers:
9
+ python generate_shim.py
10
+ """
11
+ import re
12
+ from pathlib import Path
13
+
14
+ HERE = Path(__file__).parent
15
+ TYPES_HEADER = HERE / "src" / "fmi" / "fmi3FunctionTypes.h"
16
+ OUTPUT = HERE / "src" / "shim" / "fmi3_forwarders.cpp"
17
+
18
+ TYPEDEF_RE = re.compile(r"typedef\s+([\w\s\*]+?)\s*\b(fmi3\w+)TYPE\s*\((.*?)\)\s*;", re.S)
19
+ INSTANTIATE = {
20
+ "fmi3InstantiateModelExchange",
21
+ "fmi3InstantiateCoSimulation",
22
+ "fmi3InstantiateScheduledExecution",
23
+ }
24
+
25
+
26
+ def param_names(params: str):
27
+ params = " ".join(params.split())
28
+ if params in ("", "void"):
29
+ return []
30
+ return [re.findall(r"\w+", p.replace("[]", ""))[-1] for p in params.split(",")]
31
+
32
+
33
+ def main():
34
+ functions = [
35
+ (" ".join(ret.split()), name, " ".join(params.split()))
36
+ for ret, name, params in TYPEDEF_RE.findall(TYPES_HEADER.read_text())
37
+ ]
38
+ forwarded = [f for f in functions if f[1] != "fmi3GetVersion"]
39
+
40
+ out = [
41
+ "// GENERATED by generate_shim.py from fmi/fmi3FunctionTypes.h - do not edit by hand.",
42
+ '#include "shim/shim_loader.hpp"',
43
+ "",
44
+ "namespace pythonfmu_shim",
45
+ "{",
46
+ "const char* const kFunctionNames[] = {",
47
+ *[f' "{name}",' for _, name, _ in forwarded],
48
+ "};",
49
+ f"const std::size_t kFunctionCount = {len(forwarded)};",
50
+ "} // namespace pythonfmu_shim",
51
+ "",
52
+ 'extern "C" {',
53
+ "",
54
+ "FMI3_Export const char* fmi3GetVersion(void)",
55
+ "{",
56
+ " return fmi3Version;",
57
+ "}",
58
+ "",
59
+ ]
60
+ for index, (ret, name, params) in enumerate(forwarded):
61
+ names = param_names(params)
62
+ args = ", ".join(names)
63
+ out.append(f"FMI3_Export {ret} {name}({params})")
64
+ out.append("{")
65
+ if name in INSTANTIATE:
66
+ out.append(
67
+ " if (!pythonfmu_shim::ensureBackendLoaded(resourcePath, instanceEnvironment, logMessage)) return nullptr;"
68
+ )
69
+ out.append(f" const auto fn = reinterpret_cast<{name}TYPE*>(pythonfmu_shim::function({index}));")
70
+ if ret == "void":
71
+ out.append(f" if (fn) fn({args});")
72
+ elif ret == "fmi3Status":
73
+ out.append(" if (!fn) return fmi3Error;")
74
+ out.append(f" return fn({args});")
75
+ else:
76
+ out.append(" if (!fn) return nullptr;")
77
+ out.append(f" return fn({args});")
78
+ out.append("}")
79
+ out.append("")
80
+ out.append('} // extern "C"')
81
+ out.append("")
82
+ OUTPUT.parent.mkdir(exist_ok=True)
83
+ OUTPUT.write_text("\n".join(out))
84
+ print(f"wrote {OUTPUT.relative_to(HERE)} ({len(functions)} functions)")
85
+
86
+
87
+ if __name__ == "__main__":
88
+ main()
@@ -1,4 +1,3 @@
1
-
2
1
  set(headers
3
2
  cppfmu/cppfmu_cs.hpp
4
3
  cppfmu/cppfmu_common.hpp
@@ -17,29 +16,58 @@ set(sources
17
16
  pythonfmu/PySlaveInstance.cpp
18
17
  )
19
18
 
20
- add_library(pythonfmu-export ${sources} ${headers})
21
- target_compile_features(pythonfmu-export PUBLIC "cxx_std_17")
19
+ set(BINARY_OUTPUT_DIR "${CMAKE_SOURCE_DIR}/../resources/binaries/${TARGET_PLATFORM}")
22
20
 
23
- target_include_directories(pythonfmu-export
21
+ if (WIN32)
22
+ # Windows: a single library, linked against the version-independent python3.dll.
23
+ set(PYTHONFMU_IMPL_TARGET pythonfmu-export)
24
+ else ()
25
+ # Linux/macOS: the Python-dependent implementation lives in a "backend" library
26
+ # (FMI functions renamed with a prefix). The FMU library itself (pythonfmu-export,
27
+ # renamed to <modelIdentifier> by the builder) is a small shim with no link-time
28
+ # dependency on libpython, so non-Python importers can load it. See shim/shim_loader.cpp.
29
+ set(PYTHONFMU_IMPL_TARGET pythonfmu-backend)
30
+ endif ()
31
+
32
+ add_library(${PYTHONFMU_IMPL_TARGET} ${sources} ${headers})
33
+ target_compile_features(${PYTHONFMU_IMPL_TARGET} PUBLIC "cxx_std_17")
34
+ target_include_directories(${PYTHONFMU_IMPL_TARGET}
24
35
  PRIVATE
25
36
  "${Python3_INCLUDE_DIRS}"
26
37
  "${CMAKE_CURRENT_SOURCE_DIR}"
27
38
  )
28
39
 
29
40
  if (WIN32)
30
- target_link_libraries(pythonfmu-export PRIVATE ${Python3_LIBRARIES})
31
- elseif (APPLE)
32
- set_target_properties(pythonfmu-export PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
33
- endif ()
34
-
35
- if (WIN32)
36
- set_target_properties(pythonfmu-export
41
+ target_link_libraries(${PYTHONFMU_IMPL_TARGET} PRIVATE ${Python3_LIBRARIES})
42
+ set_target_properties(${PYTHONFMU_IMPL_TARGET}
37
43
  PROPERTIES
38
- RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/../resources/binaries/${TARGET_PLATFORM}"
44
+ RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BINARY_OUTPUT_DIR}"
39
45
  )
40
46
  else ()
47
+ # Python symbols are resolved at load time against the process (the host Python, or
48
+ # the libpython the shim opened with RTLD_GLOBAL).
49
+ target_compile_definitions(${PYTHONFMU_IMPL_TARGET} PRIVATE FMI3_FUNCTION_PREFIX=pythonfmu_backend_)
50
+ if (APPLE)
51
+ set_target_properties(${PYTHONFMU_IMPL_TARGET} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
52
+ endif ()
53
+ set_target_properties(${PYTHONFMU_IMPL_TARGET}
54
+ PROPERTIES
55
+ LIBRARY_OUTPUT_DIRECTORY "${BINARY_OUTPUT_DIR}"
56
+ )
57
+
58
+ add_library(pythonfmu-export
59
+ shim/shim_loader.cpp
60
+ shim/shim_loader.hpp
61
+ shim/fmi3_forwarders.cpp
62
+ )
63
+ target_compile_features(pythonfmu-export PUBLIC "cxx_std_17")
64
+ target_include_directories(pythonfmu-export PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
65
+ target_link_libraries(pythonfmu-export PRIVATE ${CMAKE_DL_LIBS})
41
66
  set_target_properties(pythonfmu-export
42
67
  PROPERTIES
43
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/../resources/binaries/${TARGET_PLATFORM}"
68
+ LIBRARY_OUTPUT_DIRECTORY "${BINARY_OUTPUT_DIR}"
69
+ # Only the FMI functions (marked FMI3_Export) are exported
70
+ CXX_VISIBILITY_PRESET hidden
71
+ VISIBILITY_INLINES_HIDDEN ON
44
72
  )
45
73
  endif ()
@@ -121,6 +121,9 @@ public:
121
121
  FMIString message,
122
122
  Args&&... args) CPPFMU_NOEXCEPT
123
123
  {
124
+ if (m_fmiLogger == nullptr) {
125
+ return; // FMI 3.0 allows instantiating without a logger callback
126
+ }
124
127
  if (m_settings->loggedCategories.empty() ||
125
128
  detail::CanFind(m_settings->loggedCategories, category)) {
126
129
  m_fmiLogger(
@@ -66,7 +66,8 @@ void SlaveInstance::SetFloat64(
66
66
  void SlaveInstance::SetInt32(
67
67
  const FMIValueReference /*vr*/[],
68
68
  std::size_t nvr,
69
- const FMIInt32 /*value*/[])
69
+ const FMIInt32 /*value*/[],
70
+ std::size_t nValues)
70
71
  {
71
72
  if (nvr != 0) {
72
73
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -76,7 +77,8 @@ void SlaveInstance::SetInt32(
76
77
  void SlaveInstance::SetInt64(
77
78
  const FMIValueReference /*vr*/[],
78
79
  std::size_t nvr,
79
- const FMIInt64 /*value*/[])
80
+ const FMIInt64 /*value*/[],
81
+ std::size_t nValues)
80
82
  {
81
83
  if (nvr != 0) {
82
84
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -86,7 +88,8 @@ void SlaveInstance::SetInt64(
86
88
  void SlaveInstance::SetUInt64(
87
89
  const FMIValueReference /*vr*/[],
88
90
  std::size_t nvr,
89
- const FMIUInt64 /*value*/[])
91
+ const FMIUInt64 /*value*/[],
92
+ std::size_t nValues)
90
93
  {
91
94
  if (nvr != 0) {
92
95
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -97,7 +100,8 @@ void SlaveInstance::SetUInt64(
97
100
  void SlaveInstance::SetBoolean(
98
101
  const FMIValueReference /*vr*/[],
99
102
  std::size_t nvr,
100
- const FMIBoolean /*value*/[])
103
+ const FMIBoolean /*value*/[],
104
+ std::size_t nValues)
101
105
  {
102
106
  if (nvr != 0) {
103
107
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -108,7 +112,8 @@ void SlaveInstance::SetBoolean(
108
112
  void SlaveInstance::SetString(
109
113
  const FMIValueReference /*vr*/[],
110
114
  std::size_t nvr,
111
- const FMIString /*value*/[])
115
+ const FMIString /*value*/[],
116
+ std::size_t nValues)
112
117
  {
113
118
  if (nvr != 0) {
114
119
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -131,7 +136,8 @@ void SlaveInstance::GetFloat64(
131
136
  void SlaveInstance::GetInt32(
132
137
  const FMIValueReference /*vr*/[],
133
138
  std::size_t nvr,
134
- FMIInt32 /*value*/[]) const
139
+ FMIInt32 /*value*/[],
140
+ std::size_t nValues) const
135
141
  {
136
142
  if (nvr != 0) {
137
143
  throw std::logic_error("Attempted to get nonexistent variable");
@@ -142,7 +148,8 @@ void SlaveInstance::GetInt32(
142
148
  void SlaveInstance::GetInt64(
143
149
  const FMIValueReference /*vr*/[],
144
150
  std::size_t nvr,
145
- FMIInt64 /*value*/[]) const
151
+ FMIInt64 /*value*/[],
152
+ std::size_t nValues) const
146
153
  {
147
154
  if (nvr != 0) {
148
155
  throw std::logic_error("Attempted to get nonexistent variable");
@@ -153,7 +160,8 @@ void SlaveInstance::GetInt64(
153
160
  void SlaveInstance::GetUInt64(
154
161
  const FMIValueReference /*vr*/[],
155
162
  std::size_t nvr,
156
- FMIUInt64 /*value*/[]) const
163
+ FMIUInt64 /*value*/[],
164
+ std::size_t nValues) const
157
165
  {
158
166
  if (nvr != 0) {
159
167
  throw std::logic_error("Attempted to get nonexistent variable");
@@ -164,7 +172,8 @@ void SlaveInstance::GetUInt64(
164
172
  void SlaveInstance::GetBoolean(
165
173
  const FMIValueReference /*vr*/[],
166
174
  std::size_t nvr,
167
- FMIBoolean /*value*/[]) const
175
+ FMIBoolean /*value*/[],
176
+ std::size_t nValues) const
168
177
  {
169
178
  if (nvr != 0) {
170
179
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -175,7 +184,8 @@ void SlaveInstance::GetBoolean(
175
184
  void SlaveInstance::GetString(
176
185
  const FMIValueReference /*vr*/[],
177
186
  std::size_t nvr,
178
- FMIString /*value*/[]) const
187
+ FMIString /*value*/[],
188
+ std::size_t nValues) const
179
189
  {
180
190
  if (nvr != 0) {
181
191
  throw std::logic_error("Attempted to set nonexistent variable");
@@ -76,23 +76,28 @@ public:
76
76
  virtual void SetInt32(
77
77
  const FMIValueReference vr[],
78
78
  std::size_t nvr,
79
- const FMIInt32 value[]);
79
+ const FMIInt32 value[],
80
+ std::size_t nValues);
80
81
  virtual void SetInt64(
81
82
  const FMIValueReference vr[],
82
83
  std::size_t nvr,
83
- const FMIInt64 value[]);
84
+ const FMIInt64 value[],
85
+ std::size_t nValues);
84
86
  virtual void SetUInt64(
85
87
  const FMIValueReference vr[],
86
88
  std::size_t nvr,
87
- const FMIUInt64 value[]);
89
+ const FMIUInt64 value[],
90
+ std::size_t nValues);
88
91
  virtual void SetBoolean(
89
92
  const FMIValueReference vr[],
90
93
  std::size_t nvr,
91
- const FMIBoolean value[]);
94
+ const FMIBoolean value[],
95
+ std::size_t nValues);
92
96
  virtual void SetString(
93
97
  const FMIValueReference vr[],
94
98
  std::size_t nvr,
95
- const FMIString value[]);
99
+ const FMIString value[],
100
+ std::size_t nValues);
96
101
 
97
102
  /* Called from fmi3GetXxx()/fmiGetXxx().
98
103
  * Throws std::logic_error by default.
@@ -105,23 +110,28 @@ public:
105
110
  virtual void GetInt32(
106
111
  const FMIValueReference vr[],
107
112
  std::size_t nvr,
108
- FMIInt32 value[]) const;
113
+ FMIInt32 value[],
114
+ std::size_t nValues) const;
109
115
  virtual void GetInt64(
110
116
  const FMIValueReference vr[],
111
117
  std::size_t nvr,
112
- FMIInt64 value[]) const;
118
+ FMIInt64 value[],
119
+ std::size_t nValues) const;
113
120
  virtual void GetUInt64(
114
121
  const FMIValueReference vr[],
115
122
  std::size_t nvr,
116
- FMIUInt64 value[]) const;
123
+ FMIUInt64 value[],
124
+ std::size_t nValues) const;
117
125
  virtual void GetBoolean(
118
126
  const FMIValueReference vr[],
119
127
  std::size_t nvr,
120
- FMIBoolean value[]) const;
128
+ FMIBoolean value[],
129
+ std::size_t nValues) const;
121
130
  virtual void GetString(
122
131
  const FMIValueReference vr[],
123
132
  std::size_t nvr,
124
- FMIString value[]) const;
133
+ FMIString value[],
134
+ std::size_t nValues) const;
125
135
 
126
136
  // Called from fmi3DoStep()/fmiDoStep(). Must be implemented in model code.
127
137
  virtual FMIStatus DoStep(
@@ -95,7 +95,8 @@ fmi3Instance fmi3InstantiateCoSimulation(
95
95
  fmi3IntermediateUpdateCallback intermediateUpdate )
96
96
  {
97
97
  try {
98
- auto component = new Component(
98
+ // Owned until fully constructed, so a failing instantiation does not leak it.
99
+ auto component = std::make_unique<Component>(
99
100
  environment,
100
101
  logMessage,
101
102
  loggingOn);
@@ -108,7 +109,7 @@ fmi3Instance fmi3InstantiateCoSimulation(
108
109
  visible,
109
110
  cppfmu::FMIFalse,
110
111
  component->logger);
111
- return component;
112
+ return component.release();
112
113
  } catch (const cppfmu::FatalError& e) {
113
114
  if (logMessage)
114
115
  {
@@ -134,7 +135,8 @@ fmi3Instance fmi3InstantiateModelExchange(
134
135
  fmi3LogMessageCallback logMessage)
135
136
  {
136
137
  try {
137
- auto component = new Component(
138
+ // Owned until fully constructed, so a failing instantiation does not leak it.
139
+ auto component = std::make_unique<Component>(
138
140
  environment,
139
141
  logMessage,
140
142
  loggingOn);
@@ -147,7 +149,7 @@ fmi3Instance fmi3InstantiateModelExchange(
147
149
  visible,
148
150
  cppfmu::FMIFalse,
149
151
  component->logger);
150
- return component;
152
+ return component.release();
151
153
  } catch (const cppfmu::FatalError& e) {
152
154
  if (logMessage)
153
155
  {
@@ -334,7 +336,7 @@ fmi3Status fmi3GetInt32(
334
336
  {
335
337
  const auto component = reinterpret_cast<Component*>(c);
336
338
  try {
337
- component->slave->GetInt32(vr, nvr, values);
339
+ component->slave->GetInt32(vr, nvr, values, nValues);
338
340
  return fmi3OK;
339
341
  } catch (const cppfmu::FatalError& e) {
340
342
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -354,7 +356,7 @@ fmi3Status fmi3GetInt64(
354
356
  {
355
357
  const auto component = reinterpret_cast<Component*>(c);
356
358
  try {
357
- component->slave->GetInt64(vr, nvr, values);
359
+ component->slave->GetInt64(vr, nvr, values, nValues);
358
360
  return fmi3OK;
359
361
  } catch (const cppfmu::FatalError& e) {
360
362
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -374,7 +376,7 @@ fmi3Status fmi3GetUInt64(
374
376
  {
375
377
  const auto component = reinterpret_cast<Component*>(c);
376
378
  try {
377
- component->slave->GetUInt64(vr, nvr, values);
379
+ component->slave->GetUInt64(vr, nvr, values, nValues);
378
380
  return fmi3OK;
379
381
  } catch (const cppfmu::FatalError& e) {
380
382
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -394,7 +396,7 @@ fmi3Status fmi3GetBoolean(
394
396
  {
395
397
  const auto component = reinterpret_cast<Component*>(c);
396
398
  try {
397
- component->slave->GetBoolean(vr, nvr, values);
399
+ component->slave->GetBoolean(vr, nvr, values, nValues);
398
400
  return fmi3OK;
399
401
  } catch (const cppfmu::FatalError& e) {
400
402
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -414,7 +416,7 @@ fmi3Status fmi3GetString(
414
416
  {
415
417
  const auto component = reinterpret_cast<Component*>(c);
416
418
  try {
417
- component->slave->GetString(vr, nvr, values);
419
+ component->slave->GetString(vr, nvr, values, nValues);
418
420
  return fmi3OK;
419
421
  } catch (const cppfmu::FatalError& e) {
420
422
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -455,7 +457,7 @@ fmi3Status fmi3SetInt32(
455
457
  {
456
458
  const auto component = reinterpret_cast<Component*>(c);
457
459
  try {
458
- component->slave->SetInt32(vr, nvr, values);
460
+ component->slave->SetInt32(vr, nvr, values, nValues);
459
461
  return fmi3OK;
460
462
  } catch (const cppfmu::FatalError& e) {
461
463
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -475,7 +477,7 @@ fmi3Status fmi3SetInt64(
475
477
  {
476
478
  const auto component = reinterpret_cast<Component*>(c);
477
479
  try {
478
- component->slave->SetInt64(vr, nvr, values);
480
+ component->slave->SetInt64(vr, nvr, values, nValues);
479
481
  return fmi3OK;
480
482
  } catch (const cppfmu::FatalError& e) {
481
483
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -495,7 +497,7 @@ fmi3Status fmi3SetUInt64(
495
497
  {
496
498
  const auto component = reinterpret_cast<Component*>(c);
497
499
  try {
498
- component->slave->SetUInt64(vr, nvr, values);
500
+ component->slave->SetUInt64(vr, nvr, values, nValues);
499
501
  return fmi3OK;
500
502
  } catch (const cppfmu::FatalError& e) {
501
503
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -515,7 +517,7 @@ fmi3Status fmi3SetBoolean(
515
517
  {
516
518
  const auto component = reinterpret_cast<Component*>(c);
517
519
  try {
518
- component->slave->SetBoolean(vr, nvr, values);
520
+ component->slave->SetBoolean(vr, nvr, values, nValues);
519
521
  return fmi3OK;
520
522
  } catch (const cppfmu::FatalError& e) {
521
523
  component->logger.Log(fmi3Fatal, "", e.what());
@@ -535,7 +537,7 @@ fmi3Status fmi3SetString(
535
537
  {
536
538
  const auto component = reinterpret_cast<Component*>(c);
537
539
  try {
538
- component->slave->SetString(vr, nvr, values);
540
+ component->slave->SetString(vr, nvr, values, nValues);
539
541
  return fmi3OK;
540
542
  } catch (const cppfmu::FatalError& e) {
541
543
  component->logger.Log(fmi3Fatal, "", e.what());