From 73bcf2207b6148e467c678843894f011a9c41ed6 Mon Sep 17 00:00:00 2001 From: hym Date: Fri, 12 Dec 2025 18:54:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=B8=8E=E5=8F=AF=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E6=96=87=E4=BB=B6=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/compileprocessmanager.cpp | 129 ++++++++++++++++++++++++------ backend/compileprocessmanager.h | 44 ++++++++-- 2 files changed, 141 insertions(+), 32 deletions(-) diff --git a/backend/compileprocessmanager.cpp b/backend/compileprocessmanager.cpp index 45f3279..dbeeaf1 100644 --- a/backend/compileprocessmanager.cpp +++ b/backend/compileprocessmanager.cpp @@ -1,51 +1,132 @@ #include "compileprocessmanager.h" -#include +#include +#include +#include +#include +#include +#include CompileProcessManager::CompileProcessManager(QObject *parent) : QObject(parent) { 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) { - // 简单处理:如果已经在运行,就先杀掉,或直接返回 m_process->kill(); m_process->waitForFinished(); } - // TODO: 这里根据你的编译器协议生成指令和参数 - // 假设你已存在一个后端可执行文件 "my_compiler_backend" - QString program = "my_compiler_backend"; + m_isAsmOperation = true; + m_pendingInputFile = inputPath; + 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); - m_process->setArguments(args); - m_process->start(); -} - -QStringList CompileProcessManager::buildArguments(const QString &sourceCode) -{ + // mini_c 调用形式:mini_c asm + m_process->setProgram(m_backendProgram); QStringList args; + args << QStringLiteral("asm") << inputPath; + m_process->setArguments(args); - // TODO: 把 sourceCode 写入临时文件 / 管道 / 特定协议 - // 这里只是示例:假设后端接受一个 -code "xxx" 的参数 - args << "-code" << sourceCode; + m_process->setProcessChannelMode(QProcess::SeparateChannels); - return args; + m_process->start(); + // 不用 waitForFinished,异步等 finished 信号 } 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()); - QString stderrText = QString::fromLocal8Bit(m_process->readAllStandardError()); + if (status != QProcess::NormalExit && exitCode == 0) { + 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(); } diff --git a/backend/compileprocessmanager.h b/backend/compileprocessmanager.h index 933da5c..266a925 100644 --- a/backend/compileprocessmanager.h +++ b/backend/compileprocessmanager.h @@ -1,7 +1,8 @@ #pragma once #include -#include // ✅ 关键:要完整引入 QProcess +#include +#include class CompileProcessManager : public QObject { @@ -9,13 +10,34 @@ class CompileProcessManager : public QObject public: explicit CompileProcessManager(QObject *parent = nullptr); - // 目前简单接受代码字符串,后面可以加更多参数 - void runCompile(const QString &sourceCode); + // 设置 mini_c 可执行文件路径,如:"/Users/xxx/mini_c_build/mini_c" + void setBackendProgram(const QString &programPath); - signals: - void compileFinished(const QString &stdoutText, - const QString &stderrText, - int exitCode); + // 设置项目根目录,用来拼接 "test.c"、"test.s" 这样的相对路径 + // 比如:"/Users/haolixin/Desktop/Compiler_Project" + void setProjectRoot(const QString &rootPath); + + // 异步生成汇编: + // 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: void onProcessFinished(int exitCode, QProcess::ExitStatus status); @@ -23,5 +45,11 @@ private slots: private: 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; };