后端与可执行文件交互
This commit is contained in:
@@ -1,51 +1,132 @@
|
|||||||
#include "compileprocessmanager.h"
|
#include "compileprocessmanager.h"
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QStringConverter>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
CompileProcessManager::CompileProcessManager(QObject *parent)
|
CompileProcessManager::CompileProcessManager(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
m_process = new QProcess(this);
|
m_process = new QProcess(this);
|
||||||
connect(m_process, &QProcess::finished,
|
|
||||||
this, &CompileProcessManager::onProcessFinished);
|
connect(m_process,
|
||||||
|
&QProcess::finished,
|
||||||
|
this,
|
||||||
|
&CompileProcessManager::onProcessFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompileProcessManager::runCompile(const QString &sourceCode)
|
void CompileProcessManager::setBackendProgram(const QString &programPath)
|
||||||
{
|
{
|
||||||
|
m_backendProgram = programPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompileProcessManager::setProjectRoot(const QString &rootPath)
|
||||||
|
{
|
||||||
|
m_projectRoot = rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompileProcessManager::generateAsm(const QString &inputFileName,
|
||||||
|
const QString &outputFileName)
|
||||||
|
{
|
||||||
|
if (m_backendProgram.isEmpty()) {
|
||||||
|
emit processError(tr("mini_c 可执行文件路径未设置"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 项目根目录(如果没设就用当前工作目录)
|
||||||
|
QDir root(m_projectRoot.isEmpty() ? QDir::currentPath() : m_projectRoot);
|
||||||
|
|
||||||
|
// 拼出源文件完整路径:root + "test.c"
|
||||||
|
QString inputPath = root.filePath(inputFileName);
|
||||||
|
if (!QFileInfo::exists(inputPath)) {
|
||||||
|
emit processError(tr("源文件不存在: %1").arg(inputPath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若之前还有进程在跑,先结束(简单粗暴版)
|
||||||
if (m_process->state() != QProcess::NotRunning) {
|
if (m_process->state() != QProcess::NotRunning) {
|
||||||
// 简单处理:如果已经在运行,就先杀掉,或直接返回
|
|
||||||
m_process->kill();
|
m_process->kill();
|
||||||
m_process->waitForFinished();
|
m_process->waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 这里根据你的编译器协议生成指令和参数
|
m_isAsmOperation = true;
|
||||||
// 假设你已存在一个后端可执行文件 "my_compiler_backend"
|
m_pendingInputFile = inputPath;
|
||||||
QString program = "my_compiler_backend";
|
m_pendingOutputFile = outputFileName.isEmpty()
|
||||||
|
? QStringLiteral("1.s")
|
||||||
|
: outputFileName;
|
||||||
|
|
||||||
QStringList args = buildArguments(sourceCode);
|
// 把工作目录设为项目根目录:这样 mini_c 写 "1.s" 就会写到项目根目录
|
||||||
|
QString workingDir = root.absolutePath();
|
||||||
|
m_process->setWorkingDirectory(workingDir);
|
||||||
|
|
||||||
m_process->setProgram(program);
|
// mini_c 调用形式:mini_c asm <inputFilename>
|
||||||
m_process->setArguments(args);
|
m_process->setProgram(m_backendProgram);
|
||||||
m_process->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList CompileProcessManager::buildArguments(const QString &sourceCode)
|
|
||||||
{
|
|
||||||
QStringList args;
|
QStringList args;
|
||||||
|
args << QStringLiteral("asm") << inputPath;
|
||||||
|
m_process->setArguments(args);
|
||||||
|
|
||||||
// TODO: 把 sourceCode 写入临时文件 / 管道 / 特定协议
|
m_process->setProcessChannelMode(QProcess::SeparateChannels);
|
||||||
// 这里只是示例:假设后端接受一个 -code "xxx" 的参数
|
|
||||||
args << "-code" << sourceCode;
|
|
||||||
|
|
||||||
return args;
|
m_process->start();
|
||||||
|
// 不用 waitForFinished,异步等 finished 信号
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompileProcessManager::onProcessFinished(int exitCode, QProcess::ExitStatus status)
|
void CompileProcessManager::onProcessFinished(int exitCode, QProcess::ExitStatus status)
|
||||||
{
|
{
|
||||||
Q_UNUSED(status);
|
QString stdoutText = QString::fromUtf8(m_process->readAllStandardOutput());
|
||||||
|
QString stderrText = QString::fromUtf8(m_process->readAllStandardError());
|
||||||
|
|
||||||
QString stdoutText = QString::fromLocal8Bit(m_process->readAllStandardOutput());
|
if (status != QProcess::NormalExit && exitCode == 0) {
|
||||||
QString stderrText = QString::fromLocal8Bit(m_process->readAllStandardError());
|
exitCode = -1;
|
||||||
|
}
|
||||||
|
|
||||||
emit compileFinished(stdoutText, stderrText, exitCode);
|
QString asmText;
|
||||||
|
QString finalOutputPath;
|
||||||
|
|
||||||
|
if (m_isAsmOperation) {
|
||||||
|
// mini_c 当前实现中,汇编输出写到固定文件 "1.s"
|
||||||
|
QDir workDir(m_process->workingDirectory());
|
||||||
|
QString tmpAsmPath = workDir.filePath(QStringLiteral("1.s"));
|
||||||
|
|
||||||
|
if (exitCode == 0 && QFileInfo::exists(tmpAsmPath)) {
|
||||||
|
// 读出 1.s 内容
|
||||||
|
QFile f(tmpAsmPath);
|
||||||
|
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QTextStream in(&f);
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
in.setEncoding(QStringConverter::Utf8);
|
||||||
|
#endif
|
||||||
|
asmText = in.readAll();
|
||||||
|
f.close();
|
||||||
|
} else {
|
||||||
|
stderrText += QStringLiteral(
|
||||||
|
"\n[CompileProcessManager] 无法打开汇编输出文件: %1\n"
|
||||||
|
).arg(tmpAsmPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果用户希望输出文件名不是 "1.s",比如 "test.s",就复制一份
|
||||||
|
finalOutputPath = workDir.filePath(m_pendingOutputFile);
|
||||||
|
if (finalOutputPath != tmpAsmPath) {
|
||||||
|
QFile::remove(finalOutputPath); // 不成功也无所谓
|
||||||
|
QFile::copy(tmpAsmPath, finalOutputPath); // 覆盖为目标文件名
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (exitCode == 0) {
|
||||||
|
stderrText += QStringLiteral(
|
||||||
|
"\n[CompileProcessManager] 未找到 mini_c 生成的 1.s 文件。\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把汇编文本 + 文件路径 + stdout/stderr + exitCode 一次性丢给前端
|
||||||
|
emit asmGenerated(asmText, finalOutputPath, stdoutText, stderrText, exitCode);
|
||||||
|
|
||||||
|
// 重置状态
|
||||||
|
m_isAsmOperation = false;
|
||||||
|
m_pendingInputFile.clear();
|
||||||
|
m_pendingOutputFile.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QProcess> // ✅ 关键:要完整引入 QProcess
|
#include <QProcess>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class CompileProcessManager : public QObject
|
class CompileProcessManager : public QObject
|
||||||
{
|
{
|
||||||
@@ -9,13 +10,34 @@ class CompileProcessManager : public QObject
|
|||||||
public:
|
public:
|
||||||
explicit CompileProcessManager(QObject *parent = nullptr);
|
explicit CompileProcessManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
// 目前简单接受代码字符串,后面可以加更多参数
|
// 设置 mini_c 可执行文件路径,如:"/Users/xxx/mini_c_build/mini_c"
|
||||||
void runCompile(const QString &sourceCode);
|
void setBackendProgram(const QString &programPath);
|
||||||
|
|
||||||
signals:
|
// 设置项目根目录,用来拼接 "test.c"、"test.s" 这样的相对路径
|
||||||
void compileFinished(const QString &stdoutText,
|
// 比如:"/Users/haolixin/Desktop/Compiler_Project"
|
||||||
const QString &stderrText,
|
void setProjectRoot(const QString &rootPath);
|
||||||
int exitCode);
|
|
||||||
|
// 异步生成汇编:
|
||||||
|
// inputFileName 比如 "test.c"(在项目根目录下)
|
||||||
|
// outputFileName 比如 "test.s"(希望输出的文件名,同样在项目根目录下)
|
||||||
|
//
|
||||||
|
// 调用后立刻返回,编译结束后,通过 asmGenerated 信号把结果发给前端。
|
||||||
|
void generateAsm(const QString &inputFileName,
|
||||||
|
const QString &outputFileName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// asmText: 读出来的汇编文本(通常就是 outputFileName 的内容)
|
||||||
|
// outputFilePath: 实际写出的汇编文件完整路径(项目根目录下)
|
||||||
|
// stdoutText / stderrText: mini_c 的标准输出 / 错误输出(原样传递,不做处理)
|
||||||
|
// exitCode: mini_c 的返回码(0 正常,非 0 表示错误)
|
||||||
|
void asmGenerated(const QString &asmText,
|
||||||
|
const QString &outputFilePath,
|
||||||
|
const QString &stdoutText,
|
||||||
|
const QString &stderrText,
|
||||||
|
int exitCode);
|
||||||
|
|
||||||
|
// 出现明显错误(比如 mini_c 路径没设、源文件不存在等)
|
||||||
|
void processError(const QString &message);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onProcessFinished(int exitCode, QProcess::ExitStatus status);
|
void onProcessFinished(int exitCode, QProcess::ExitStatus status);
|
||||||
@@ -23,5 +45,11 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
QProcess *m_process = nullptr;
|
QProcess *m_process = nullptr;
|
||||||
|
|
||||||
QStringList buildArguments(const QString &sourceCode);
|
QString m_backendProgram; // mini_c 路径
|
||||||
|
QString m_projectRoot; // 项目根目录
|
||||||
|
|
||||||
|
// 当前这次 generateAsm 的输入/输出信息,用来在 finished 时读文件
|
||||||
|
QString m_pendingInputFile; // 完整路径:root + inputFileName
|
||||||
|
QString m_pendingOutputFile; // 仅文件名,如 "test.s"
|
||||||
|
bool m_isAsmOperation = false;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user