Skip to content

Commit e999385

Browse files
DvoraNovogrotzkiChedvaErblich
authored andcommitted
GUI: Parallelized project compilation using QThread
- Refactored the compilation logic to utilize QThread for parallel execution. - Added a Compiler class to handle individual project compilation in separate threads. - Ensured that previous compilation processes are terminated before starting new ones. - Handled shell script and CMake project compilation with proper error logging. - Improved performance by running multiple compilation tasks concurrently.
1 parent a5b9bb9 commit e999385

4 files changed

Lines changed: 131 additions & 165 deletions

File tree

gui/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
2222
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
2323

2424
# Find the Qt5 library
25-
find_package(Qt5 REQUIRED COMPONENTS Widgets Core Gui Test)
25+
find_package(Qt5 REQUIRED COMPONENTS Concurrent Widgets Core Gui Test)
2626

2727
# Find the BSON library using pkg-config
2828
find_package(PkgConfig REQUIRED)
@@ -37,6 +37,7 @@ add_library(VehicleComputingSimulatorLib
3737
src/simulation_state_manager.cpp
3838
src/log_handler.cpp
3939
src/frames.cpp
40+
src/compiler.cpp
4041
../logger/logger.cpp
4142
)
4243

@@ -48,6 +49,7 @@ target_sources(VehicleComputingSimulatorLib PRIVATE
4849
include/simulation_state_manager.h
4950
include/log_handler.h
5051
include/frames.h
52+
include/compiler.h
5153
../logger/logger.h
5254
)
5355

@@ -59,7 +61,7 @@ target_include_directories(VehicleComputingSimulatorLib PRIVATE
5961
)
6062

6163
# Link the BSON library and Qt5 components to the library
62-
target_link_libraries(VehicleComputingSimulatorLib PRIVATE ${BSON_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets)
64+
target_link_libraries(VehicleComputingSimulatorLib PRIVATE ${BSON_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent)
6365

6466
# Create the main executable
6567
add_executable(VehicleComputingSimulator src/main.cpp)

gui/include/compiler.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef COMPILER_H
2+
#define COMPILER_H
3+
4+
#include <QThread>
5+
#include <QFile>
6+
#include <QProcess>
7+
#include <QDir>
8+
#include <QStringList>
9+
#include <QString>
10+
11+
class Compiler : public QThread {
12+
Q_OBJECT
13+
public:
14+
Compiler(QString cmakePath, bool *compileSuccessful,
15+
QObject *parent = nullptr);
16+
17+
protected:
18+
void run() override;
19+
20+
signals:
21+
void logMessage(const QString &message);
22+
23+
private:
24+
QString cmakePath;
25+
bool *compileSuccessful;
26+
};
27+
28+
#endif // COMPILER_H

gui/src/compiler.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "compiler.h"
2+
3+
Compiler::Compiler(QString cmakePath, bool *compileSuccessful, QObject *parent)
4+
: QThread(parent),
5+
cmakePath(cmakePath),
6+
compileSuccessful(compileSuccessful)
7+
{
8+
}
9+
10+
void Compiler::run()
11+
{
12+
if (cmakePath.endsWith(".sh")) { // Handle shell script compilation
13+
QFile scriptFile(cmakePath);
14+
if (!scriptFile.exists()) {
15+
emit logMessage("Shell script file does not exist: " + cmakePath);
16+
*compileSuccessful = false;
17+
return;
18+
}
19+
20+
// Make shell script executable if needed
21+
if ((scriptFile.permissions() & QFileDevice::ExeUser) == 0) {
22+
QProcess makeExecutableProcess;
23+
makeExecutableProcess.start("chmod", QStringList()
24+
<< "+x" << cmakePath);
25+
if (!makeExecutableProcess.waitForFinished()) {
26+
*compileSuccessful = false;
27+
return;
28+
}
29+
}
30+
31+
QProcess scriptProcess;
32+
scriptProcess.start("bash", QStringList() << cmakePath);
33+
scriptProcess.waitForFinished();
34+
}
35+
else { // Handle CMake compilation
36+
QDir cmakeDir =
37+
QFileInfo(cmakePath)
38+
.absolutePath(); // Get the directory of CMakeLists.txt
39+
QString buildDirPath = cmakeDir.absoluteFilePath("build");
40+
QDir buildDir(buildDirPath);
41+
42+
// Create build directory if it doesn't exist
43+
if (!buildDir.exists() && !buildDir.mkpath(".")) {
44+
emit logMessage("Failed to create build directory " + buildDirPath);
45+
*compileSuccessful = false;
46+
return;
47+
}
48+
49+
QProcess cmakeProcess;
50+
cmakeProcess.setWorkingDirectory(buildDirPath);
51+
cmakeProcess.start(
52+
"cmake",
53+
QStringList()
54+
<< cmakeDir.absolutePath()); // Use project dir, not just ".."
55+
56+
if (!cmakeProcess.waitForFinished()) {
57+
emit logMessage("Failed to run cmake in " + buildDirPath);
58+
*compileSuccessful = false;
59+
return;
60+
}
61+
62+
QProcess makeProcess;
63+
makeProcess.setWorkingDirectory(buildDirPath);
64+
makeProcess.start("make", QStringList());
65+
66+
if (!makeProcess.waitForFinished()) {
67+
emit logMessage("Failed to compile in " + buildDirPath);
68+
*compileSuccessful = false;
69+
}
70+
}
71+
}

gui/src/main_window.cpp

Lines changed: 28 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "process_dialog.h"
1212
#include "frames.h"
1313
#include "log_handler.h"
14+
#include "compiler.h"
1415

1516
int sizeSquare = 120;
1617
int rotationTimerIntervals = 100;
@@ -562,167 +563,32 @@ void MainWindow::compileProjects()
562563
runningProcesses.clear();
563564
bool compileSuccessful = true; // Track if all compilations succeed
564565

566+
QList<QThread *> threads;
567+
568+
QSet<QString> uniquePaths; // Set to hold unique paths
565569
for (DraggableSquare *square : squares) {
566570
QString executionFilePath = square->getProcess()->getExecutionFile();
567-
QFileInfo fileInfo(executionFilePath);
568-
QString directoryPath = fileInfo.absolutePath();
569-
570-
if (executionFilePath.endsWith(".sh")) {
571-
// Shell script processing
572-
QFile scriptFile(executionFilePath);
573-
if (!scriptFile.exists()) {
574-
guiLogger.logMessage(logger::LogLevel::ERROR,
575-
"Shell script file does not exist: " +
576-
executionFilePath.toStdString());
577-
578-
logOutput->append("Shell script file does not exist: " +
579-
executionFilePath);
580-
compileSuccessful = false;
581-
continue;
582-
}
583-
584-
if ((scriptFile.permissions() & QFileDevice::ExeUser) == 0) {
585-
// Make the script executable
586-
QProcess makeExecutableProcess;
587-
makeExecutableProcess.start("chmod", QStringList()
588-
<< "+x" << executionFilePath);
589-
if (!makeExecutableProcess.waitForFinished()) {
590-
logOutput->append("Failed to make the script executable: " +
591-
executionFilePath);
592-
compileSuccessful = false;
593-
continue;
594-
}
595-
guiLogger.logMessage(
596-
logger::LogLevel::INFO,
597-
"Script is now executable: " + executionFilePath.toStdString());
598-
logOutput->append("Script is now executable: " + executionFilePath);
599-
}
600-
601-
// Run the shell script
602-
QProcess *scriptProcess = new QProcess(this);
603-
scriptProcess->start("bash", QStringList() << executionFilePath);
604-
connect(
605-
scriptProcess,
606-
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
607-
this, &MainWindow::processFinished);
608-
connect(
609-
scriptProcess, &QProcess::readyReadStandardOutput,
610-
[this, scriptProcess]() {
611-
logOutput->append(scriptProcess->readAllStandardOutput());
612-
});
613-
connect(
614-
scriptProcess, &QProcess::readyReadStandardError,
615-
[this, scriptProcess]() {
616-
logOutput->append(scriptProcess->readAllStandardError());
617-
});
618-
}
619-
else {
620-
guiLogger.logMessage(logger::LogLevel::INFO,
621-
"Compiling " + executionFilePath.toStdString());
622-
623-
// CMake project processing
624-
logOutput->append("Compiling " + executionFilePath);
625-
QString buildDirPath = QDir(directoryPath).absoluteFilePath("build");
626-
QDir buildDir(buildDirPath);
571+
uniquePaths.insert(executionFilePath);
572+
}
627573

628-
if (buildDir.exists()) {
629-
QFileInfoList fileList = buildDir.entryInfoList(
630-
QDir::NoDotAndDotDot | QDir::AllEntries);
631-
foreach (const QFileInfo &fileInfo, fileList) {
632-
if (fileInfo.isDir()) {
633-
QDir dir(fileInfo.absoluteFilePath());
634-
if (!dir.removeRecursively()) {
635-
guiLogger.logMessage(
636-
logger::LogLevel::ERROR,
637-
"Failed to remove directory: " +
638-
fileInfo.absoluteFilePath().toStdString());
639-
640-
logOutput->append("Failed to remove directory: " +
641-
fileInfo.absoluteFilePath());
642-
compileSuccessful = false;
643-
continue;
644-
}
645-
}
646-
else {
647-
if (!QFile::remove(fileInfo.absoluteFilePath())) {
648-
guiLogger.logMessage(
649-
logger::LogLevel::ERROR,
650-
"Failed to remove file: " +
651-
fileInfo.absoluteFilePath().toStdString());
652-
logOutput->append("Failed to remove file: " +
653-
fileInfo.absoluteFilePath());
654-
compileSuccessful = false;
655-
continue;
656-
}
657-
}
658-
}
659-
}
660-
else {
661-
// Create the build directory
662-
if (!buildDir.mkpath(".")) {
574+
for (QString executionFilePath : uniquePaths) {
575+
Compiler *compiler =
576+
new Compiler(executionFilePath, &compileSuccessful, this);
577+
connect(compiler, &Compiler::logMessage, this,
578+
[this](const QString &message) {
663579
guiLogger.logMessage(logger::LogLevel::ERROR,
664-
"Failed to create build directory " +
665-
buildDirPath.toStdString());
666-
logOutput->append("Failed to create build directory " +
667-
buildDirPath);
668-
compileSuccessful = false;
669-
continue;
670-
}
671-
}
672-
673-
// Run CMake
674-
QProcess *cmakeProcess = new QProcess(this);
675-
cmakeProcess->setWorkingDirectory(buildDirPath);
676-
cmakeProcess->start("cmake", QStringList() << "..");
677-
connect(
678-
cmakeProcess,
679-
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
680-
this, &MainWindow::processFinished);
681-
682-
if (!cmakeProcess->waitForFinished()) {
683-
guiLogger.logMessage(
684-
logger::LogLevel::ERROR,
685-
"Failed to run cmake in " + buildDirPath.toStdString());
686-
logOutput->append("Failed to run cmake in " + buildDirPath);
687-
logOutput->append(cmakeProcess->readAllStandardError());
688-
delete cmakeProcess;
689-
compileSuccessful = false;
690-
continue;
691-
}
692-
logOutput->append(cmakeProcess->readAllStandardOutput());
693-
logOutput->append(cmakeProcess->readAllStandardError());
694-
delete cmakeProcess;
695-
696-
// Run make
697-
QProcess *makeProcess = new QProcess(this);
698-
makeProcess->setWorkingDirectory(buildDirPath);
699-
makeProcess->start("make", QStringList());
700-
connect(
701-
makeProcess,
702-
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
703-
this, &MainWindow::processFinished);
580+
message.toStdString());
581+
});
582+
compiler->start();
583+
threads.append(compiler);
584+
}
704585

705-
if (!makeProcess->waitForFinished()) {
706-
guiLogger.logMessage(
707-
logger::LogLevel::ERROR,
708-
"Failed to compile in " + buildDirPath.toStdString());
709-
logOutput->append("Failed to compile in " + buildDirPath);
710-
logOutput->append(makeProcess->readAllStandardError());
711-
delete makeProcess;
712-
compileSuccessful = false;
713-
continue;
714-
}
715-
logOutput->append(makeProcess->readAllStandardOutput());
716-
logOutput->append(makeProcess->readAllStandardError());
717-
guiLogger.logMessage(
718-
logger::LogLevel::INFO,
719-
"Successfully compiled " + buildDirPath.toStdString());
720-
logOutput->append("Successfully compiled " + buildDirPath);
721-
delete makeProcess;
722-
}
586+
// Wait for all threads to finish
587+
for (QThread *thread : threads) {
588+
thread->wait();
589+
delete thread; // Clean up threads after completion
723590
}
724591

725-
// Enable the run button only if the compilation was successful
726592
if (compileSuccessful) {
727593
runButton->setEnabled(true);
728594
logOutput->append(
@@ -743,7 +609,6 @@ void MainWindow::runProjects()
743609
QString executionFilePath = square->getProcess()->getExecutionFile();
744610

745611
if (executionFilePath.endsWith(".sh")) {
746-
// Run the shell script
747612
QProcess *scriptProcess = new QProcess(this);
748613
scriptProcess->start("bash", QStringList() << executionFilePath);
749614
connect(
@@ -758,13 +623,15 @@ void MainWindow::runProjects()
758623
});
759624
}
760625
else {
761-
// Run the compiled program
762-
QDir cmakeDir = QFileInfo(executionFilePath).absoluteDir();
763-
QString buildDirPath = cmakeDir.absoluteFilePath("build");
626+
QDir cmakeDir(
627+
QFileInfo(executionFilePath)
628+
.absolutePath()); // Get the directory containing CMakeLists.txt
629+
QString buildDirPath = cmakeDir.absoluteFilePath(
630+
"build"); // Updated build directory outside the source
631+
QDir buildDir(buildDirPath);
764632

765-
if (!QDir(buildDirPath).exists()) {
766-
// Create the build directory if it does not exist
767-
if (!cmakeDir.mkpath(buildDirPath)) {
633+
if (!buildDir.exists()) {
634+
if (!buildDir.mkpath(buildDirPath)) {
768635
guiLogger.logMessage(logger::LogLevel::ERROR,
769636
"Failed to create build directory: " +
770637
buildDirPath.toStdString());
@@ -774,12 +641,10 @@ void MainWindow::runProjects()
774641
}
775642
}
776643

777-
QDir buildDir(buildDirPath);
778644
QString exeFile = getExecutableName(buildDirPath);
779645
QString executablePath = buildDir.absoluteFilePath(exeFile);
780646
QProcess *runProcess = new QProcess(this);
781647
runProcess->setWorkingDirectory(buildDirPath);
782-
783648
connect(runProcess, &QProcess::readyReadStandardOutput,
784649
[this, runProcess]() {
785650
logOutput->append(runProcess->readAllStandardOutput());

0 commit comments

Comments
 (0)