From a0e2113c5386510d82a650fd6da38761a21d14ec Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Mon, 12 Aug 2024 11:27:29 +0200 Subject: [PATCH] Add BuildPlatformBinaryThread.cpp --- fmusim-gui/BuildPlatformBinaryThread.cpp | 171 ++++++++++++++++++++ fmusim-gui/BuildPlatformBinaryThread.h | 35 ++++ fmusim-gui/CMakeLists.txt | 1 + fmusim-gui/MainWindow.cpp | 194 ++++------------------- fmusim-gui/MainWindow.h | 3 + 5 files changed, 240 insertions(+), 164 deletions(-) create mode 100644 fmusim-gui/BuildPlatformBinaryThread.cpp create mode 100644 fmusim-gui/BuildPlatformBinaryThread.h diff --git a/fmusim-gui/BuildPlatformBinaryThread.cpp b/fmusim-gui/BuildPlatformBinaryThread.cpp new file mode 100644 index 00000000..e057efb4 --- /dev/null +++ b/fmusim-gui/BuildPlatformBinaryThread.cpp @@ -0,0 +1,171 @@ +#include +#include +#include "BuildPlatformBinaryThread.h" + + +BuildPlatformBinaryThread::BuildPlatformBinaryThread(QObject *parent) + : QThread{parent} +{} + +static QString wslPath(const QString& path) { + + QString canonicalPath = path; + + canonicalPath = canonicalPath.replace('\\', '/'); + + QProcess process; + + process.start("wsl", {"wslpath", "-a", canonicalPath}); + + process.waitForFinished(); + + QString p(process.readAllStandardOutput()); + + return p.trimmed(); +} + +void BuildPlatformBinaryThread::run() { + + QString modelIdentifier; + + QTemporaryDir buildDirectory; + + buildDirectory.setAutoRemove(removeBuilDirectory); + + QFile::copy(":/resources/CMakeLists.txt", buildDirectory.filePath("CMakeLists.txt")); + + 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; + + if (modelDescription->coSimulation) { + modelIdentifier = modelDescription->coSimulation->modelIdentifier; + nSourceFiles = modelDescription->coSimulation->nSourceFiles; + sourceFiles = modelDescription->coSimulation->sourceFiles; + } else { + modelIdentifier = modelDescription->modelExchange->modelIdentifier; + nSourceFiles = modelDescription->modelExchange->nSourceFiles; + sourceFiles = modelDescription->modelExchange->sourceFiles; + } + + QStringList definitions; + + if (modelDescription->fmiMajorVersion == 3) { + definitions << "FMI3_OVERRIDE_FUNCTION_PREFIX"; + } + + if (buildDescription) { + + if (buildDescription->nBuildConfigurations > 1) { + emit newMessage("Multiple Build Configurations are not supported.\n"); + return; + } + + const FMIBuildConfiguration* buildConfiguration = buildDescription->buildConfigurations[0]; + + if (buildConfiguration->nSourceFileSets > 1) { + emit newMessage("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 = compileWithWSL ? wslPath(buildDirectory.path()) : buildDirectory.path(); + QString unzipdirPath = compileWithWSL ? wslPath(unzipdir) : unzipdir; + + QStringList sources; + + for (size_t i = 0; i < nSourceFiles; i++) { + sources << QDir(unzipdirPath).filePath("sources/" + QString(sourceFiles[i])); + } + + QStringList includeDirectories = { + buildDirPath, + QDir(unzipdirPath).filePath("sources") + }; + + + emit newMessage("Generating CMake project...\n"); + + QString program; + + QProcess process; + QStringList arguments; + + if (compileWithWSL) { + program = "wsl"; + arguments << cmakeCommand; + } else { + program = cmakeCommand; + } + + if (!cmakeGenerator.isEmpty()) { + arguments << "-G" + cmakeGenerator; + } + + 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 + "'"; + + process.start(program, arguments); + + bool success = process.waitForFinished(); + + emit newMessage(process.readAllStandardOutput()); + emit newMessage(process.readAllStandardError()); + + if (!success) { + return; + } + + emit newMessage("Building CMake project...\n"); + + arguments.clear(); + + if (compileWithWSL) { + arguments << cmakeCommand; + } + + arguments << "--build" << buildDirPath; + arguments << "--target" << "install"; + arguments << "--config" << buildConfiguration; + + process.start(program, arguments); + + success = process.waitForFinished(); + + emit newMessage(process.readAllStandardOutput()); + emit newMessage(process.readAllStandardError()); +} diff --git a/fmusim-gui/BuildPlatformBinaryThread.h b/fmusim-gui/BuildPlatformBinaryThread.h new file mode 100644 index 00000000..2746e708 --- /dev/null +++ b/fmusim-gui/BuildPlatformBinaryThread.h @@ -0,0 +1,35 @@ +#ifndef BUILDPLATFORMBINARYTHREAD_H +#define BUILDPLATFORMBINARYTHREAD_H + +#include +#include + +extern "C" { +#include "FMIModelDescription.h" +#include "FMIBuildDescription.h" +} + +class BuildPlatformBinaryThread : public QThread +{ + Q_OBJECT + +public: + explicit BuildPlatformBinaryThread(QObject *parent = nullptr); + + QString unzipdir; + FMIModelDescription* modelDescription; + FMIBuildDescription* buildDescription; + QString cmakeCommand; + QString cmakeGenerator; + QString buildConfiguration; + bool compileWithWSL; + bool removeBuilDirectory; + + void run() override; + +signals: + void newMessage(QString message); + +}; + +#endif // BUILDPLATFORMBINARYTHREAD_H diff --git a/fmusim-gui/CMakeLists.txt b/fmusim-gui/CMakeLists.txt index 691d2b60..ced4c6e5 100644 --- a/fmusim-gui/CMakeLists.txt +++ b/fmusim-gui/CMakeLists.txt @@ -95,6 +95,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) SimulationThread.h SimulationThread.cpp resources.qrc BuildPlatformBinaryDialog.h BuildPlatformBinaryDialog.cpp BuildPlatformBinaryDialog.ui + BuildPlatformBinaryThread.h BuildPlatformBinaryThread.cpp ) diff --git a/fmusim-gui/MainWindow.cpp b/fmusim-gui/MainWindow.cpp index ebc762a3..b17bb8e4 100644 --- a/fmusim-gui/MainWindow.cpp +++ b/fmusim-gui/MainWindow.cpp @@ -11,11 +11,10 @@ #include #include #include -#include -#include #include "ModelVariablesItemModel.h" #include "VariablesFilterModel.h" #include "SimulationThread.h" +#include "BuildPlatformBinaryThread.h" #include "BuildPlatformBinaryDialog.h" extern "C" { @@ -31,7 +30,9 @@ extern "C" { MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) -{ +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); simulationThread = new SimulationThread(this); @@ -40,8 +41,7 @@ MainWindow::MainWindow(QWidget *parent) progressDialog->setWindowTitle("FMUSim"); progressDialog->setLabelText("Simulating..."); - progressDialog->setMinimum(0); - progressDialog->setMaximum(100); + progressDialog->setRange(0, 100); progressDialog->setMinimumDuration(1000); progressDialog->setWindowModality(Qt::WindowModal); @@ -56,7 +56,21 @@ MainWindow::MainWindow(QWidget *parent) connect(simulationThread, &SimulationThread::finished, this, &MainWindow::simulationFinished); connect(progressDialog, &QProgressDialog::canceled, simulationThread, &SimulationThread::stop); - ui->setupUi(this); + buildPlatformBinaryThread = new BuildPlatformBinaryThread(this); + + buildPlatformBinaryProgressDialog = new QProgressDialog(this); + + buildPlatformBinaryProgressDialog->setWindowTitle("FMUSim"); + buildPlatformBinaryProgressDialog->setLabelText("Building Platform Binary..."); + buildPlatformBinaryProgressDialog->setRange(0, 0); + buildPlatformBinaryProgressDialog->setWindowModality(Qt::WindowModal); + buildPlatformBinaryProgressDialog->setCancelButton(nullptr); + + buildPlatformBinaryProgressDialog->setWindowFlags(flags); + buildPlatformBinaryProgressDialog->reset(); + + connect(buildPlatformBinaryThread, &BuildPlatformBinaryThread::newMessage, ui->logPlainTextEdit, &QPlainTextEdit::appendPlainText); + connect(buildPlatformBinaryThread, &BuildPlatformBinaryThread::finished, buildPlatformBinaryProgressDialog, &QProgressDialog::reset); setColorScheme(QGuiApplication::styleHints()->colorScheme()); @@ -875,23 +889,6 @@ void MainWindow::simulationFinished() { } } -static QString wslPath(const QString& path) { - - QString canonicalPath = path; - - canonicalPath = canonicalPath.replace('\\', '/'); - - QProcess process; - - process.start("wsl", {"wslpath", "-a", canonicalPath}); - - process.waitForFinished(); - - QString p(process.readAllStandardOutput()); - - return p.trimmed(); -} - void MainWindow::buildPlatformBinary() { BuildPlatformBinaryDialog dialog(this); @@ -900,151 +897,20 @@ void MainWindow::buildPlatformBinary() { return; } - const bool wsl = dialog.compileWithWSL(); - - QString modelIdentifier; - - QTemporaryDir buildDirectory; - - buildDirectory.setAutoRemove(dialog.removeBuilDirectory()); - - QFile::copy(":/resources/CMakeLists.txt", buildDirectory.filePath("CMakeLists.txt")); - - 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; - - if (modelDescription->coSimulation) { - modelIdentifier = modelDescription->coSimulation->modelIdentifier; - nSourceFiles = modelDescription->coSimulation->nSourceFiles; - sourceFiles = modelDescription->coSimulation->sourceFiles; - } else { - modelIdentifier = modelDescription->modelExchange->modelIdentifier; - nSourceFiles = modelDescription->modelExchange->nSourceFiles; - 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; - - QStringList sources; - - for (size_t i = 0; i < nSourceFiles; i++) { - sources << QDir(unzipdirPath).filePath("sources/" + QString(sourceFiles[i])); - } - - QStringList includeDirectories = { - buildDirPath, - QDir(unzipdirPath).filePath("sources") - }; - ui->logPlainTextEdit->clear(); setCurrentPage(ui->logPage); - ui->logPlainTextEdit->appendPlainText("Generating CMake project...\n"); - - QString program; - - QProcess process; - QStringList arguments; - - if (wsl) { - program = "wsl"; - arguments << dialog.cmakeCommand(); - } else { - program = dialog.cmakeCommand(); - } - - if (!dialog.cmakeGenerator().isEmpty()) { - arguments << "-G" + dialog.cmakeGenerator(); - } - - 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 + "'"; - - process.start(program, arguments); - - bool success = process.waitForFinished(); - - ui->logPlainTextEdit->appendPlainText(process.readAllStandardOutput()); - ui->logPlainTextEdit->appendPlainText(process.readAllStandardError()); - - if (!success) { - return; - } - - ui->logPlainTextEdit->appendPlainText("Building CMake project...\n"); - - arguments.clear(); - - if (wsl) { - arguments << dialog.cmakeCommand(); - } - - arguments << "--build" << buildDirPath; - arguments << "--target" << "install"; - arguments << "--config" << dialog.buildConfiguration(); - - process.start(program, arguments); + buildPlatformBinaryProgressDialog->show(); - success = process.waitForFinished(); + buildPlatformBinaryThread->unzipdir = unzipdir; + buildPlatformBinaryThread->modelDescription = modelDescription; + buildPlatformBinaryThread->buildDescription = buildDescription; + buildPlatformBinaryThread->cmakeCommand = dialog.cmakeCommand(); + buildPlatformBinaryThread->cmakeGenerator = dialog.cmakeGenerator(); + buildPlatformBinaryThread->buildConfiguration = dialog.buildConfiguration(); + buildPlatformBinaryThread->compileWithWSL = dialog.compileWithWSL(); + buildPlatformBinaryThread->removeBuilDirectory = dialog.removeBuilDirectory(); - ui->logPlainTextEdit->appendPlainText(process.readAllStandardOutput()); - ui->logPlainTextEdit->appendPlainText(process.readAllStandardError()); + buildPlatformBinaryThread->start(); } diff --git a/fmusim-gui/MainWindow.h b/fmusim-gui/MainWindow.h index 2b1cdd5d..0e72007a 100644 --- a/fmusim-gui/MainWindow.h +++ b/fmusim-gui/MainWindow.h @@ -22,6 +22,7 @@ extern "C" { class ModelVariablesItemModel; class VariablesFilterModel; class SimulationThread; +class BuildPlatformBinaryThread; class QProgressDialog; class MainWindow : public QMainWindow @@ -54,7 +55,9 @@ class MainWindow : public QMainWindow ModelVariablesItemModel* variablesListModel = nullptr; VariablesFilterModel* variablesFilterModel = nullptr; SimulationThread* simulationThread = nullptr; + BuildPlatformBinaryThread* buildPlatformBinaryThread = nullptr; QProgressDialog* progressDialog; + QProgressDialog* buildPlatformBinaryProgressDialog; static MainWindow* currentMainWindow; static void logMessage(const char* message, va_list args);