Handle space characters in compiler paths
Also forwards compiler verification error messages to the UI.
MODIFY
src/ccmanager.cpp
src/ccmanager.cpp
@@ -13,20 +13,6 @@ const static std::vector<QString> s_validAutodetectedCCs = {"riscv64-unknown-elf
"riscv64-unknown-elf-c++"};
const static QString s_testprogram = "int main() { return 0; }";
-/**
- * @brief s_baseCC
- * Base compiler command.
- * - %1: path to compiler executable
- * - %2: machine architecture
- * - %3: machine ABI
- * - %4: user compiler arguments
- * - -x c: Enforce compilation as C language (allows us to use C++ compilers)
- * - %5: input source file
- * - %6: output executable
- * - %7: user linker arguments
- */
-const static QString s_baseCC = "%1 -march=%2 -mabi=%3 %4 -x c %5 -o %6 %7";
-
CCManager::CCManager() {
if (RipesSettings::value(RIPES_SETTING_CCPATH) == "") {
// No previous compiler path has been set. Try to autodetect a valid compiler within the current path
@@ -63,14 +49,14 @@ QString CCManager::tryAutodetectCC() {
}
bool CCManager::trySetCC(const QString& CC) {
- const bool success = verifyCC(CC);
- if (success) {
+ const auto res = verifyCC(CC);
+ if (res.success) {
m_currentCC = CC;
} else {
m_currentCC = QString();
}
- emit ccChanged(success);
- return success;
+ emit ccChanged(res);
+ return res.success;
}
CCManager::CCRes CCManager::compileRaw(const QString& rawsource, QString outname, bool showProgressdiag) {
@@ -144,58 +130,96 @@ QString CCManager::getError() {
return get().m_process.readAllStandardError();
}
+namespace {
+
+QStringList sanitizedArguments(const QString& args) {
+ QStringList arglist = args.split(" ");
+ for (const auto invArg : {"", " ", "-"}) {
+ arglist.removeAll(invArg);
+ }
+ return arglist;
+}
+
+} // namespace
+
std::pair<QString, QStringList> CCManager::createCompileCommand(const QString& filename, const QString& outname) const {
const auto& currentISA = ProcessorHandler::get()->currentISA();
- // Generate compile command
- QString s_cc = s_baseCC;
+ /**
+ * @brief s_baseCC
+ * Base compiler command.
+ * - %1: path to compiler executable
+ * - %2: machine architecture
+ * - %3: machine ABI
+ * - %4: user compiler arguments
+ * - -x c: Enforce compilation as C language (allows us to use C++ compilers)
+ * - %5: input source file
+ * - %6: output executable
+ * - %7: user linker arguments
+ */
+ const static QString s_baseCC = "%1 -march=%2 -mabi=%3 %4 -x c %5 -o %6 %7";
+
+ QStringList compileCommand;
- // Substitute compiler path
- s_cc = s_cc.arg(m_currentCC);
+ // Compiler path
+ compileCommand << m_currentCC;
// Substitute machine architecture
- s_cc = s_cc.arg(currentISA->CCmarch());
+ compileCommand << (QString("-march=") + currentISA->CCmarch());
// Substitute machine ABI
- s_cc = s_cc.arg(currentISA->CCmabi());
+ compileCommand << (QString("-mabi=") + currentISA->CCmabi());
// Substitute additional CC arguments
- s_cc = s_cc.arg(RipesSettings::value(RIPES_SETTING_CCARGS).toString());
+ compileCommand << sanitizedArguments(RipesSettings::value(RIPES_SETTING_CCARGS).toString());
+
+ // Enforce compilation as C language (allows us to use C++ compilers)
+ compileCommand << "-x"
+ << "c";
// Substitute in and out files
- s_cc = s_cc.arg(filename).arg(outname);
+ compileCommand << filename << "-o" << outname;
// Substitute additional linker arguments
- s_cc = s_cc.arg(RipesSettings::value(RIPES_SETTING_LDARGS).toString());
+ compileCommand << sanitizedArguments(RipesSettings::value(RIPES_SETTING_LDARGS).toString());
- auto arglist = s_cc.split(" ");
+ return {compileCommand[0], compileCommand.mid(1)};
+}
- // Sanitize the arguments
- for (const auto invArg : {"", " ", "-"}) {
- arglist.removeAll(invArg);
+CCManager::CCRes CCManager::verifyCC(const QString& CCPath) {
+ // Try to set CCPath as current compiler, and compile test program
+ m_currentCC = CCPath;
+
+ CCRes res;
+ const auto compilerExecInfo = QFileInfo(m_currentCC);
+ auto abs = compilerExecInfo.absolutePath();
+
+ if (m_currentCC.isEmpty()) {
+ res.errorMessage = "No path specified";
+ res.success = false;
+ goto verifyCC_end;
}
- return {arglist[0], arglist.mid(1)};
+ if (!compilerExecInfo.isExecutable()) {
+ res.errorMessage = "'" + m_currentCC + "' is not an executable file.";
+ res.success = false;
+ goto verifyCC_end;
}
-bool CCManager::verifyCC(const QString& CCPath) {
- // Try to set CCPath as current compiler, and compile test program
- m_currentCC = CCPath;
- auto res = compileRaw(s_testprogram, QString(), false);
+ res = compileRaw(s_testprogram, QString(), false);
-#ifdef QT_DEBUG
if (!res.success) {
- qDebug() << "Failed to compile test program";
- qDebug() << "CC output: ";
- qDebug() << "Standard output: " << m_process.readAllStandardOutput();
- qDebug() << "Standard error: " << m_process.readAllStandardError();
+ res.errorMessage += "Failed to compile test program.\n";
+ res.errorMessage += "Compiler output:\n";
+ res.errorMessage += "\tstdout: " + QString(m_process.readAllStandardOutput()) + "\n";
+ res.errorMessage += "\tstderr: " + QString(m_process.readAllStandardError()) + "\n";
}
-#endif
// Cleanup
res.clean();
- return res.success;
+verifyCC_end:
+ return res;
}
} // namespace Ripes

MODIFY
src/ccmanager.h
src/ccmanager.h
@@ -19,6 +19,7 @@ public:
struct CCRes {
QString inFile;
QString outFile;
+ QString errorMessage;
bool success = false;
bool aborted = false;
@@ -53,9 +54,9 @@ public:
signals:
/**
* @brief ccChanged
- * Emitted whenever the current CC path changed. @param valid indicates whether the CC was successfully validated.
+ * Emitted whenever the current CC path changed. @param res contains information regarding the compiler validation.
*/
- void ccChanged(bool valid);
+ void ccChanged(CCRes res);
public slots:
/**
@@ -77,7 +78,7 @@ private:
* Attempts to compile a simple test program using the provided compiler path @param CC.
* @returns true if successful.
*/
- bool verifyCC(const QString& CC);
+ CCRes verifyCC(const QString& CC);
CCManager();
QString m_currentCC;

MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -59,8 +59,8 @@ EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent)
connect(m_ui->setCInput, &QRadioButton::toggled, m_buildAction, &QAction::setEnabled);
// Ensure that changes to the current compiler path will disable C input, if the compiler is invalid
- connect(&CCManager::get(), &CCManager::ccChanged, [=](bool valid) {
- if (!valid) {
+ connect(&CCManager::get(), &CCManager::ccChanged, [=](auto res) {
+ if (!res.success) {
m_ui->setAssemblyInput->setChecked(true);
}
});

MODIFY
src/settingsdialog.cpp
src/settingsdialog.cpp
@@ -191,39 +191,41 @@ QWidget* SettingsDialog::createEditorPage() {
// Add effective compile command line view
auto* CCCLineHLayout = new QHBoxLayout();
- CCCLineHLayout->addWidget(new QLabel("Compile command:"));
- m_compileCommand = new QLabel();
- m_compileCommand->setWordWrap(true);
- m_compileCommand->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
- m_compileCommand->setTextInteractionFlags(Qt::TextSelectableByMouse);
- CCCLineHLayout->addWidget(m_compileCommand);
+ m_compileInfoHeader = new QLabel();
+ CCCLineHLayout->addWidget(m_compileInfoHeader);
+ m_compileInfo = new QLabel();
+ m_compileInfo->setWordWrap(true);
+ m_compileInfo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+ m_compileInfo->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ CCCLineHLayout->addWidget(m_compileInfo);
CCLayout->addLayout(CCCLineHLayout);
pageLayout->addWidget(CCGroupBox);
// Trigger initial rehighlighting
- CCManager::get().trySetCC(CCManager::get().currentCC());
+ CCManager::get().trySetCC(m_ccpath->text());
return pageWidget;
}
-void SettingsDialog::CCPathChanged(bool valid) {
+void SettingsDialog::CCPathChanged(CCManager::CCRes res) {
QPalette palette = this->palette();
- if (!valid) {
- palette.setColor(QPalette::Base, QColor(Qt::red).lighter());
- } else {
+ if (res.success) {
palette.setColor(QPalette::Base, QColor(Qt::green).lighter());
+ m_compileInfoHeader->setText("Compile command:");
+ } else {
+ palette.setColor(QPalette::Base, QColor(Qt::red).lighter());
+ m_compileInfoHeader->setText("Error:");
}
m_ccpath->setPalette(palette);
// Update compile command preview
auto [cstring, cargs] = CCManager::get().createCompileCommand("${input}", "${output}");
- if (m_compileCommand) {
- m_compileCommand->setEnabled(valid);
- if (valid) {
- m_compileCommand->setText(cstring + " " + cargs.join(" "));
+ if (m_compileInfo) {
+ if (res.success) {
+ m_compileInfo->setText(cstring + " " + cargs.join(" "));
} else {
- m_compileCommand->clear();
+ m_compileInfo->setText(res.errorMessage);
}
}
}

MODIFY
src/settingsdialog.h
src/settingsdialog.h
#pragma once
#include <QDialog>
+#include "ccmanager.h"
QT_FORWARD_DECLARE_CLASS(QLineEdit);
QT_FORWARD_DECLARE_CLASS(QLabel);
@@ -25,9 +26,10 @@ private:
* @brief CCPathChanged
* Rehighlightss the current CCPath if the CC is @param valid
*/
- void CCPathChanged(bool valid);
+ void CCPathChanged(CCManager::CCRes res);
QLineEdit* m_ccpath = nullptr;
- QLabel* m_compileCommand = nullptr;
+ QLabel* m_compileInfo = nullptr;
+ QLabel* m_compileInfoHeader = nullptr;
QWidget* createEditorPage();
QWidget* createSimulatorPage();

Handle space characters in compiler paths #59

Also forwards compiler verification error messages to the UI.