From 282278625e739f3c94bf2df2cbf77e2c7a93bac3 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Fri, 9 Aug 2024 14:38:26 +0200 Subject: [PATCH] Build FMI 3.0 FMUs --- fmusim-gui/CMakeLists.txt | 2 + fmusim-gui/MainWindow.cpp | 79 +++++++++++++++++++++++++++-- fmusim-gui/MainWindow.h | 4 +- fmusim-gui/resources/CMakeLists.txt | 14 +++-- 4 files changed, 86 insertions(+), 13 deletions(-) diff --git a/fmusim-gui/CMakeLists.txt b/fmusim-gui/CMakeLists.txt index 3e8ce849..691d2b60 100644 --- a/fmusim-gui/CMakeLists.txt +++ b/fmusim-gui/CMakeLists.txt @@ -34,6 +34,8 @@ set(PROJECT_SOURCES ${ZLIB_SRC_DIR}/contrib/minizip/iowin32.c ../fmusim/FMIModelDescription.c ../fmusim/FMIModelDescription.h + ../fmusim/FMIBuildDescription.c + ../fmusim/FMIBuildDescription.h ../src/structured_variable_name.tab.c ../src/structured_variable_name.yy.c ) diff --git a/fmusim-gui/MainWindow.cpp b/fmusim-gui/MainWindow.cpp index 1a44b8bc..0a72b870 100644 --- a/fmusim-gui/MainWindow.cpp +++ b/fmusim-gui/MainWindow.cpp @@ -264,6 +264,13 @@ void MainWindow::loadFMU(const QString &filename) { return; } + const QString buildDescriptionPath = QDir(unzipdir).filePath("sources/buildDescription.xml"); + + if (QFileInfo::exists(buildDescriptionPath)) { + QByteArray ba = buildDescriptionPath.toLocal8Bit(); + buildDescription = FMIReadBuildDescription(ba.data()); + } + // update the GUI startValues.clear(); @@ -348,6 +355,17 @@ void MainWindow::loadFMU(const QString &filename) { // enable widgets ui->showSideBarAction->setEnabled(true); ui->showSideBarAction->setChecked(true); + + bool hasSourceCode = false; + + if ((modelDescription->coSimulation && modelDescription->coSimulation->nSourceFiles > 0) || + (modelDescription->modelExchange && modelDescription->modelExchange->nSourceFiles > 0) || + buildDescription) { + hasSourceCode = true; + } + + ui->compilePlatformBinaryAction->setEnabled(hasSourceCode); + ui->showInfoAction->setEnabled(true); ui->showSettingsAction->setEnabled(true); ui->showFilesAction->setEnabled(true); @@ -778,6 +796,11 @@ void MainWindow::unloadFMU() { modelDescription = nullptr; } + if (buildDescription) { + FMIFreeBuildDescription(buildDescription); + buildDescription = nullptr; + } + if (!unzipdir.isEmpty()) { QByteArray bytes = unzipdir.toLocal8Bit(); const char *cstr = bytes.data(); @@ -799,6 +822,7 @@ void MainWindow::unloadFMU() { ui->dockWidget->setHidden(true); + ui->compilePlatformBinaryAction->setEnabled(false); ui->showInfoAction->setEnabled(false); ui->showSettingsAction->setEnabled(false); ui->showFilesAction->setEnabled(false); @@ -885,9 +909,16 @@ void MainWindow::compilePlatformBinary() { buildDirectory.setAutoRemove(dialog.removeBuilDirectory()); QFile::copy(":/resources/CMakeLists.txt", buildDirectory.filePath("CMakeLists.txt")); - QFile::copy(":/resources/fmi2Functions.h", buildDirectory.filePath("fmi2Functions.h")); - QFile::copy(":/resources/fmi2FunctionTypes.h", buildDirectory.filePath("fmi2FunctionTypes.h")); - QFile::copy(":/resources/fmi2TypesPlatform.h", buildDirectory.filePath("fmi2TypesPlatform.h")); + + if (modelDescription->fmiMajorVersion == 2) { + QFile::copy(":/resources/fmi2Functions.h", buildDirectory.filePath("fmi2Functions.h")); + QFile::copy(":/resources/fmi2FunctionTypes.h", buildDirectory.filePath("fmi2FunctionTypes.h")); + QFile::copy(":/resources/fmi2TypesPlatform.h", buildDirectory.filePath("fmi2TypesPlatform.h")); + } else { + QFile::copy(":/resources/fmi3Functions.h", buildDirectory.filePath("fmi3Functions.h")); + QFile::copy(":/resources/fmi3FunctionTypes.h", buildDirectory.filePath("fmi3FunctionTypes.h")); + QFile::copy(":/resources/fmi3PlatformTypes.h", buildDirectory.filePath("fmi3PlatformTypes.h")); + } size_t nSourceFiles; const char** sourceFiles; @@ -902,6 +933,46 @@ void MainWindow::compilePlatformBinary() { sourceFiles = modelDescription->modelExchange->sourceFiles; } + QStringList definitions; + + if (modelDescription->fmiMajorVersion == 3) { + definitions << "FMI3_OVERRIDE_FUNCTION_PREFIX"; + } + + if (buildDescription) { + + if (buildDescription->nBuildConfigurations > 1) { + ui->logPlainTextEdit->appendPlainText("Multiple Build Configurations are not supported.\n"); + return; + } + + const FMIBuildConfiguration* buildConfiguration = buildDescription->buildConfigurations[0]; + + if (buildConfiguration->nSourceFileSets > 1) { + ui->logPlainTextEdit->appendPlainText("Multiple Source File Sets are not supported.\n"); + return; + } + + const FMISourceFileSet* sourceFileSet = buildConfiguration->sourceFileSets[0]; + + nSourceFiles = sourceFileSet->nSourceFiles; + sourceFiles = sourceFileSet->sourceFiles; + + for (size_t i = 0; i < sourceFileSet->nPreprocessorDefinitions; i++) { + + FMIPreprocessorDefinition* preprocessorDefinition = sourceFileSet->preprocessorDefinitions[i]; + + QString definition = preprocessorDefinition->name; + + if (preprocessorDefinition->value) { + definition += "="; + definition += preprocessorDefinition->value; + } + + definitions << definition; + } + } + QString buildDirPath = wsl ? wslPath(buildDirectory.path()) : buildDirectory.path(); QString unzipdirPath = wsl ? wslPath(unzipdir) : unzipdir; @@ -940,8 +1011,10 @@ void MainWindow::compilePlatformBinary() { arguments << "-S" + buildDirPath; arguments << "-B" + buildDirPath; + arguments << "-DFMI_MAJOR_VERSION=" + QString::number(modelDescription->fmiMajorVersion); arguments << "-DMODEL_IDENTIFIER=" + modelIdentifier; arguments << "-DINCLUDE='" + includeDirectories.join(';') + "'"; + arguments << "-DDEFINITIONS='" + definitions.join(';') + "'"; arguments << "-DSOURCES='" + sources.join(';') + "'"; arguments << "-DUNZIPDIR='" + unzipdirPath + "'"; diff --git a/fmusim-gui/MainWindow.h b/fmusim-gui/MainWindow.h index df3a7881..f224da60 100644 --- a/fmusim-gui/MainWindow.h +++ b/fmusim-gui/MainWindow.h @@ -16,8 +16,7 @@ QT_END_NAMESPACE extern "C" { #include "FMIModelDescription.h" -struct FMIRecorder; -struct FMISimulationSettings; +#include "FMIBuildDescription.h" } class ModelVariablesItemModel; @@ -48,6 +47,7 @@ class MainWindow : public QMainWindow QFileSystemModel filesModel; QComboBox* interfaceTypeComboBox; FMIModelDescription* modelDescription = nullptr; + FMIBuildDescription* buildDescription = nullptr; QString unzipdir; QMap startValues; QList plotVariables; diff --git a/fmusim-gui/resources/CMakeLists.txt b/fmusim-gui/resources/CMakeLists.txt index c0c6e02c..791a113d 100644 --- a/fmusim-gui/resources/CMakeLists.txt +++ b/fmusim-gui/resources/CMakeLists.txt @@ -2,21 +2,17 @@ cmake_minimum_required (VERSION 3.15) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") -set(FMI_VERSION 2 CACHE STRING "FMI Version") -set_property(CACHE FMI_VERSION PROPERTY STRINGS 2 3) +set(FMI_MAJOR_VERSION 2 CACHE STRING "FMI Major Version") +set_property(CACHE FMI_MAJOR_VERSION PROPERTY STRINGS 2 3) set (MODEL_IDENTIFIER CACHE STRING "Model Identifier") set (INCLUDE CACHE STRING "Include directories") +set (DEFINITIONS CACHE STRING "Precompiler definitions") set (SOURCES CACHE STRING "Source files") set (UNZIPDIR CACHE STRING "Unzip directory") project (${MODEL_IDENTIFIER}) -#message(STATUS "MODEL_IDENTIFIER: ${MODEL_IDENTIFIER}") -#message(STATUS "INCLUDE: ${INCLUDE}") -#message(STATUS "SOURCES: ${SOURCES}") -#message(STATUS "UNZIPDIR: ${UNZIPDIR}") - if (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "AMD64|x86_64") set(FMI_ARCHITECTURE "x86_64") elseif (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "aarch64") @@ -25,7 +21,7 @@ else () message(FATAL_ERROR "Unknown system architecture: ${CMAKE_SYSTEM_PROCESSOR}") endif () -if (${FMI_VERSION} GREATER 2) +if (${FMI_MAJOR_VERSION} GREATER 2) if (WIN32) set(FMI_PLATFORM "${FMI_ARCHITECTURE}-windows") @@ -59,6 +55,8 @@ add_library(${MODEL_IDENTIFIER} SHARED ${SOURCES}) target_include_directories(${MODEL_IDENTIFIER} PUBLIC ${INCLUDE}) +target_compile_definitions(${MODEL_IDENTIFIER} PUBLIC ${DEFINITIONS}) + set_target_properties(${MODEL_IDENTIFIER} PROPERTIES PREFIX "") install(TARGETS ${MODEL_IDENTIFIER} DESTINATION "${UNZIPDIR}/binaries/${FMI_PLATFORM}")