Skip to content

Commit

Permalink
OMEdit: Add post compilation command option (#9606)
Browse files Browse the repository at this point in the history
  • Loading branch information
jschueller committed Nov 1, 2022
1 parent 6aa9a2a commit b5d9da4
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 5 deletions.
1 change: 1 addition & 0 deletions OMEdit/OMEditLIB/Options/OptionsDefaults.h
Expand Up @@ -161,6 +161,7 @@ namespace OptionsDefaults
QString cCompiler; // this value is set in SimulationPage constructor.
QString cxxCompiler; // this value is set in SimulationPage constructor.
bool useStaticLinking = false;
QString postCompilationCommand = "";
bool ignoreCommandLineOptionsAnnotation = false;
bool ignoreSimulationFlagsAnnotation = false;
bool saveClassBeforeSimulation = true;
Expand Down
19 changes: 19 additions & 0 deletions OMEdit/OMEditLIB/Options/OptionsDialog.cpp
Expand Up @@ -936,6 +936,12 @@ void OptionsDialog::readSimulationSettings()
}
#endif

if (mpSettings->contains("simulation/postCompilationCommand")) {
mpSimulationPage->setPostCompilationCommand(mpSettings->value("simulation/postCompilationCommand").toString());
} else {
mpSimulationPage->setPostCompilationCommand(OptionsDefaults::Simulation::postCompilationCommand);
}

if (mpSettings->contains("simulation/ignoreCommandLineOptionsAnnotation")) {
mpSimulationPage->getIgnoreCommandLineOptionsAnnotationCheckBox()->setChecked(mpSettings->value("simulation/ignoreCommandLineOptionsAnnotation").toBool());
} else {
Expand Down Expand Up @@ -2510,6 +2516,13 @@ void OptionsDialog::saveGlobalSimulationSettings()
mpSettings->setValue("simulation/useStaticLinking", useStaticLinking);
}
#endif
// post compilation command
const QString postCompilationCommand = mpSimulationPage->getPostCompilationCommand();
if (postCompilationCommand == OptionsDefaults::Simulation::postCompilationCommand) {
mpSettings->remove("simulation/postCompilationCommand");
} else {
mpSettings->setValue("simulation/postCompilationCommand", postCompilationCommand);
}
// save ignore command line options
bool ignoreCommandLineOptionsAnnotation = mpSimulationPage->getIgnoreCommandLineOptionsAnnotationCheckBox()->isChecked();
if (ignoreCommandLineOptionsAnnotation == OptionsDefaults::Simulation::ignoreCommandLineOptionsAnnotation) {
Expand Down Expand Up @@ -5529,6 +5542,11 @@ SimulationPage::SimulationPage(OptionsDialog *pOptionsDialog)
mpUseStaticLinkingCheckBox = new QCheckBox(tr("Use static Linking"));
mpUseStaticLinkingCheckBox->setToolTip(tr("Enables static linking for the simulation executable. Default is dynamic linking."));
#endif
// post compilation command line edit
mpPostCompilationCommandLineEdit = new QLineEdit;
QLayout * mpPostCompilationCommandLayout = new QHBoxLayout;
mpPostCompilationCommandLayout->addWidget(new Label(tr("Post compilation command:")));
mpPostCompilationCommandLayout->addWidget(mpPostCompilationCommandLineEdit);
// ignore command line options annotation checkbox
mpIgnoreCommandLineOptionsAnnotationCheckBox = new QCheckBox(tr("Ignore __OpenModelica_commandLineOptions annotation"));
// ignore simulation flags annotation checkbox
Expand Down Expand Up @@ -5597,6 +5615,7 @@ SimulationPage::SimulationPage(OptionsDialog *pOptionsDialog)
#ifdef Q_OS_WIN
pSimulationLayout->addWidget(mpUseStaticLinkingCheckBox, row++, 0, 1, 2);
#endif
pSimulationLayout->addLayout(mpPostCompilationCommandLayout, row++, 0, 1, 2);
pSimulationLayout->addWidget(mpIgnoreCommandLineOptionsAnnotationCheckBox, row++, 0, 1, 2);
pSimulationLayout->addWidget(mpIgnoreSimulationFlagsAnnotationCheckBox, row++, 0, 1, 2);
pSimulationLayout->addWidget(mpSaveClassBeforeSimulationCheckBox, row++, 0, 1, 2);
Expand Down
3 changes: 3 additions & 0 deletions OMEdit/OMEditLIB/Options/OptionsDialog.h
Expand Up @@ -663,6 +663,8 @@ class SimulationPage : public QWidget
#ifdef Q_OS_WIN
QCheckBox* getUseStaticLinkingCheckBox() {return mpUseStaticLinkingCheckBox;}
#endif
void setPostCompilationCommand(const QString & cmd) {mpPostCompilationCommandLineEdit->setText(cmd);}
QString getPostCompilationCommand() {return mpPostCompilationCommandLineEdit->text().trimmed();}
QCheckBox* getIgnoreCommandLineOptionsAnnotationCheckBox() {return mpIgnoreCommandLineOptionsAnnotationCheckBox;}
QCheckBox* getIgnoreSimulationFlagsAnnotationCheckBox() {return mpIgnoreSimulationFlagsAnnotationCheckBox;}
QCheckBox* getSaveClassBeforeSimulationCheckBox() {return mpSaveClassBeforeSimulationCheckBox;}
Expand All @@ -689,6 +691,7 @@ class SimulationPage : public QWidget
#ifdef Q_OS_WIN
QCheckBox *mpUseStaticLinkingCheckBox;
#endif
QLineEdit *mpPostCompilationCommandLineEdit;
QCheckBox *mpIgnoreCommandLineOptionsAnnotationCheckBox;
QCheckBox *mpIgnoreSimulationFlagsAnnotationCheckBox;
QCheckBox *mpSaveClassBeforeSimulationCheckBox;
Expand Down
145 changes: 140 additions & 5 deletions OMEdit/OMEditLIB/Simulation/SimulationOutputWidget.cpp
Expand Up @@ -406,6 +406,9 @@ SimulationOutputWidget::SimulationOutputWidget(SimulationOptions simulationOptio
mpCompilationProcess = 0;
setCompilationProcessKilled(false);
mIsCompilationProcessRunning = false;
mpPostCompilationProcess = 0;
setPostCompilationProcessKilled(false);
mIsPostCompilationProcessRunning = false;
mpSimulationProcess = 0;
setSimulationProcessKilled(false);
mIsSimulationProcessRunning = false;
Expand All @@ -427,6 +430,11 @@ SimulationOutputWidget::~SimulationOutputWidget()
mpCompilationProcess->kill();
mpCompilationProcess->deleteLater();
}
// post compilation process
if (mpPostCompilationProcess && isPostCompilationProcessRunning()) {
mpPostCompilationProcess->kill();
mpPostCompilationProcess->deleteLater();
}
// simulation process
if (mpSimulationProcess && isSimulationProcessRunning()) {
mpSimulationProcess->kill();
Expand Down Expand Up @@ -575,6 +583,128 @@ void SimulationOutputWidget::compileModel()
}


/*!
* \brief SimulationOutputWidget::runPostCompilation
* Runs the post compilation command after the compilation of the model.
*/
void SimulationOutputWidget::runPostCompilation()
{
const QString postCompilationCommand = OptionsDialog::instance()->getSimulationPage()->getPostCompilationCommand();
if (postCompilationCommand.size())
{
mpPostCompilationProcess = new QProcess;
mpPostCompilationProcess->setWorkingDirectory(mSimulationOptions.getWorkingDirectory());
connect(mpPostCompilationProcess, SIGNAL(started()), SLOT(postCompilationProcessStarted()));
connect(mpPostCompilationProcess, SIGNAL(readyReadStandardOutput()), SLOT(readPostCompilationStandardOutput()));
connect(mpPostCompilationProcess, SIGNAL(readyReadStandardError()), SLOT(readPostCompilationStandardError()));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
connect(mpPostCompilationProcess, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(postCompilationProcessError(QProcess::ProcessError)));
#else
connect(mpPostCompilationProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(postCompilationProcessError(QProcess::ProcessError)));
#endif
connect(mpPostCompilationProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(postCompilationProcessFinished(int, QProcess::ExitStatus)));
writeCompilationOutput(QString("%1\n").arg(postCompilationCommand), Qt::blue);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QStringList args(QProcess::splitCommand(postCompilationCommand));
const QString program(args.takeFirst());
mpPostCompilationProcess->start(program, args);
#else
mpPostCompilationProcess->start(postCompilationCommand);
#endif
}
else
{
// no post-compilation step, run directly the simulation
if (!mSimulationOptions.getBuildOnly() && !mSimulationOptions.getLaunchAlgorithmicDebugger()) {
runSimulationExecutable();
}
}
}

/*!
* \brief SimulationOutputWidget::postCompilationProcessStarted
* Slot activated when mpPostCompilationProcess started signal is raised.\n
* Updates the progress label, bar and button controls.
*/
void SimulationOutputWidget::postCompilationProcessStarted()
{
mIsPostCompilationProcessRunning = true;
mpProgressLabel->setText(tr("Post compiling %1.").arg(mSimulationOptions.getClassName()));
mpProgressBar->setRange(0, 0);
mpProgressBar->setTextVisible(false);
mpCancelButton->setText(tr("Cancel Compilation"));
mpCancelButton->setEnabled(true);
}

/*!
* \brief SimulationOutputWidget::readPostCompilationStandardOutput
* Slot activated when mpPostCompilationProcess readyReadStandardOutput signal is raised.\n
*/
void SimulationOutputWidget::readPostCompilationStandardOutput()
{
writeCompilationOutput(QString(mpPostCompilationProcess->readAllStandardOutput()), Qt::black);
}

/*!
* \brief SimulationOutputWidget::readPostCompilationStandardError
* Slot activated when mpPostCompilationProcess readyReadStandardError signal is raised.\n
*/
void SimulationOutputWidget::readPostCompilationStandardError()
{
writeCompilationOutput(QString(mpPostCompilationProcess->readAllStandardError()), Qt::red);
}

/*!
* \brief SimulationOutputWidget::postCompilationProcessError
* Slot activated when mpPostCompilationProcess errorOccurred signal is raised.\n
* \param error
*/
void SimulationOutputWidget::postCompilationProcessError(QProcess::ProcessError error)
{
Q_UNUSED(error);
mIsPostCompilationProcessRunning = false;
/* this signal is raised when we kill the compilation process forcefully. */
if (isPostCompilationProcessKilled()) {
return;
}
writeCompilationOutput(mpPostCompilationProcess->errorString(), Qt::red);
}

/*!
* \brief SimulationOutputWidget::postCompilationProcessFinished
* Slot activated when mpPostCompilationProcess finished signal is raised.\n
* If the mpPostCompilationProcess finished normally then run the simulation executable.\n
* \param exitCode
* \param exitStatus
*/
void SimulationOutputWidget::postCompilationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
mIsPostCompilationProcessRunning = false;
QString exitCodeStr = tr("Post compilation process failed. Exited with code %1.").arg(Utilities::formatExitCode(exitCode));
if (exitStatus == QProcess::NormalExit && exitCode == 0) {
writeCompilationOutput(tr("Post compilation process finished successfully.\n"), Qt::blue);
postCompilationProcessFinishedHelper(exitCode, exitStatus);
// if not build only and launch the algorithmic debugger is false then run the simulation process.
if (!mSimulationOptions.getBuildOnly() && !mSimulationOptions.getLaunchAlgorithmicDebugger()) {
runSimulationExecutable();
}
} else if (mpCompilationProcess->error() == QProcess::UnknownError) {
writeCompilationOutput(exitCodeStr, Qt::red);
postCompilationProcessFinishedHelper(exitCode, exitStatus);
} else {
writeCompilationOutput(mpCompilationProcess->errorString() + "\n" + exitCodeStr, Qt::red);
postCompilationProcessFinishedHelper(exitCode, exitStatus);
}
}

void SimulationOutputWidget::postCompilationProcessFinishedHelper(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/)
{
mpProgressLabel->setText(tr("Post compilation of %1 is finished.").arg(mSimulationOptions.getClassName()));
mpProgressBar->setRange(0, 1);
mpProgressBar->setValue(1);
mpCancelButton->setEnabled(false);
}

/*!
* \brief getPathsFromBatFile
* Parses the fileName.bat file to get the necessary paths.
Expand Down Expand Up @@ -822,6 +952,14 @@ void SimulationOutputWidget::cancelCompilationOrSimulation()
mpProgressBar->setValue(1);
mpCancelButton->setEnabled(false);
mpArchivedSimulationItem->setStatus(Helper::finished);
} else if (isPostCompilationProcessRunning()) {
setPostCompilationProcessKilled(true);
mpPostCompilationProcess->kill();
mpProgressLabel->setText(tr("Post compilation of %1 is cancelled.").arg(mSimulationOptions.getClassName()));
mpProgressBar->setRange(0, 1);
mpProgressBar->setValue(1);
mpCancelButton->setEnabled(false);
mpArchivedSimulationItem->setStatus(Helper::finished);
} else if (isSimulationProcessRunning()) {
setSimulationProcessKilled(true);
mpSimulationProcess->kill();
Expand Down Expand Up @@ -982,12 +1120,9 @@ void SimulationOutputWidget::compilationProcessFinished(int exitCode, QProcess::
exitCodeStr.append("\nTry compiling with the default MinGW compiler. Select \"MinGW\" in \"Tools->Options->Simulation->Target Build\".");
}
if (exitStatus == QProcess::NormalExit && exitCode == 0) {
writeCompilationOutput(tr("Compilation process finished successfully."), Qt::blue);
writeCompilationOutput(tr("Compilation process finished successfully.\n"), Qt::blue);
compilationProcessFinishedHelper(exitCode, exitStatus);
// if not build only and launch the algorithmic debugger is false then run the simulation process.
if (!mSimulationOptions.getBuildOnly() && !mSimulationOptions.getLaunchAlgorithmicDebugger()) {
runSimulationExecutable();
}
runPostCompilation();
} else if (mpCompilationProcess->error() == QProcess::UnknownError) {
writeCompilationOutput(exitCodeStr, Qt::red);
compilationProcessFinishedHelper(exitCode, exitStatus);
Expand Down
14 changes: 14 additions & 0 deletions OMEdit/OMEditLIB/Simulation/SimulationOutputWidget.h
Expand Up @@ -96,6 +96,10 @@ class SimulationOutputWidget : public QWidget
void setCompilationProcessKilled(bool killed) {mIsCompilationProcessKilled = killed;}
bool isCompilationProcessKilled() {return mIsCompilationProcessKilled;}
bool isCompilationProcessRunning() {return mIsCompilationProcessRunning;}
QProcess* getPostCompilationProcess() {return mpPostCompilationProcess;}
void setPostCompilationProcessKilled(bool killed) {mIsPostCompilationProcessKilled = killed;}
bool isPostCompilationProcessKilled() {return mIsPostCompilationProcessKilled;}
bool isPostCompilationProcessRunning() {return mIsPostCompilationProcessRunning;}
QProcess* getSimulationProcess() {return mpSimulationProcess;}
void setSimulationProcessKilled(bool killed) {mIsSimulationProcessKilled = killed;}
bool isSimulationProcessKilled() {return mIsSimulationProcessKilled;}
Expand Down Expand Up @@ -127,12 +131,17 @@ class SimulationOutputWidget : public QWidget
QProcess *mpCompilationProcess;
bool mIsCompilationProcessKilled;
bool mIsCompilationProcessRunning;
QProcess *mpPostCompilationProcess;
bool mIsPostCompilationProcessKilled;
bool mIsPostCompilationProcessRunning;
QProcess *mpSimulationProcess;
bool mIsSimulationProcessKilled;
bool mIsSimulationProcessRunning;
QDateTime mResultFileLastModifiedDateTime;

void compileModel();
void runPostCompilation();
void postCompilationProcessFinishedHelper(int exitCode, QProcess::ExitStatus exitStatus);
void runSimulationExecutable();
void writeCompilationOutput(QString output, QColor color);
void compilationProcessFinishedHelper(int exitCode, QProcess::ExitStatus exitStatus);
Expand All @@ -152,6 +161,11 @@ private slots:
void readCompilationStandardError();
void compilationProcessError(QProcess::ProcessError error);
void compilationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void postCompilationProcessStarted();
void readPostCompilationStandardOutput();
void readPostCompilationStandardError();
void postCompilationProcessError(QProcess::ProcessError error);
void postCompilationProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void simulationProcessStarted();
void readSimulationStandardOutput();
void readSimulationStandardError();
Expand Down
5 changes: 5 additions & 0 deletions doc/UsersGuide/source/omedit.rst
Expand Up @@ -1414,6 +1414,11 @@ Simulation
- *Use static linking* – if true then static linking is used for simulation executable.
The default is dynamic linking. This option is only available on Windows.

- *Post compilation command* - if not empty allows to run a command after the compilation step.
A possible use-case is to be able to sign the binaries before execution to comply with the security policy.
The command is run in the same folder where the simulation executable is created.
The interpreter executable must be passed to run shell scripts, eg on Windows: `powershell.exe -File C:\script.ps1`

- *Ignore __OpenModelica_commandLineOptions annotation* – if true then ignores the __OpenModelica_commandLineOptions
annotation while running the simulation.

Expand Down

0 comments on commit b5d9da4

Please sign in to comment.