/** * C 代码编译运行后端服务 * 接收 C 代码 → 编译 → 运行 → 返回输出 */ const express = require('express') const cors = require('cors') const { execSync } = require('child_process') const path = require('path') const fs = require('fs') const app = express() const PORT = 3001 app.use(cors()) app.use(express.json({ limit: '1mb' })) // 查找可用的 C 编译器 // w64devkit GCC 路径 const W64DEVKIT_DIR = path.join(__dirname, 'bin', 'w64devkit', 'w64devkit') const W64DEVKIT_GCC = path.join(W64DEVKIT_DIR, 'bin', 'gcc.exe') const W64DEVKIT_PREFIX = path.join(W64DEVKIT_DIR, 'lib', 'gcc') function findCompiler() { const candidates = [ // MinGW / MSYS2 (PATH) 'gcc.exe', 'x86_64-w64-mingw32-gcc.exe', 'i686-w64-mingw32-gcc.exe', // TCC (Tiny C Compiler) 'tcc.exe', // Clang 'clang.exe', // MSVC 'cl.exe', // 本项目的便携编译器 path.join(__dirname, 'bin', 'tcc.exe'), path.join(__dirname, 'bin', 'gcc.exe'), path.join(__dirname, '..', 'tools', 'tcc', 'tcc.exe'), ] // 先在 PATH 中查找 for (const name of ['gcc.exe', 'tcc.exe', 'clang.exe', 'cl.exe']) { try { execSync(`where ${name}`, { stdio: 'pipe', timeout: 3000 }) return { path: name, name } } catch {} } // 检查 w64devkit GCC(需设置 GCC_EXEC_PREFIX) if (fs.existsSync(W64DEVKIT_GCC)) { return { path: W64DEVKIT_GCC, name: 'gcc.exe', execPrefix: W64DEVKIT_PREFIX } } // 再检查其他具体路径 for (const candidate of candidates) { try { const absPath = path.resolve(candidate) if (fs.existsSync(absPath)) { return { path: absPath, name: path.basename(absPath) } } } catch {} } // 搜索 Visual Studio MSVC 安装目录 try { const vsPaths = [ 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC', 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Tools\\MSVC', 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC', 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC', 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC', ] for (const vsPath of vsPaths) { if (fs.existsSync(vsPath)) { const versions = fs.readdirSync(vsPath).sort().reverse() for (const ver of versions) { const clPath = path.join(vsPath, ver, 'bin', 'Hostx64', 'x64', 'cl.exe') if (fs.existsSync(clPath)) { return { path: clPath, name: 'cl.exe' } } } } } } catch {} return null } // 编译并运行 C 代码 app.post('/api/run-c', (req, res) => { const { code } = req.body if (!code) { return res.status(400).json({ error: '请提供 C 代码' }) } const compiler = findCompiler() if (!compiler) { return res.status(400).json({ error: '未找到 C 编译器', hint: '请安装 MinGW-w64 GCC 编译器', installGuide: [ '--- 安装 MinGW-w64 ---', '方法一(推荐):下载 MinGW-w64 GCC', ' 1. 访问 https://winlibs.com/ 下载 GCC (MinGW-w64)', ' 2. 解压并将 bin/ 目录添加到系统 PATH 环境变量', ' 3. 重启终端后即可使用', '', '方法二(轻量):下载 TCC (Tiny C Compiler)', ' 将 tcc.exe 放入 server/bin/ 目录', '', '安装后重新启动: npm run server', ].join('\n') }) } const tmpDir = path.join(__dirname, '..', 'tmp') if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir, { recursive: true }) } const srcFile = path.join(tmpDir, `code_${Date.now()}.c`) const outFile = path.join(tmpDir, `code_${Date.now()}.exe`) try { // 写入源码 fs.writeFileSync(srcFile, code, 'utf-8') let compileCmd const execOptions = { timeout: 15000, cwd: tmpDir, encoding: 'utf-8', env: { ...process.env } } if (compiler.name.includes('tcc')) { // TCC: 编译并运行一步到位(支持 -run) compileCmd = `"${compiler.path}" -run "${srcFile}"` } else if (compiler.execPrefix) { // w64devkit GCC: 需要设置 GCC_EXEC_PREFIX 并加入 PATH const w64binDir = path.dirname(compiler.path) execOptions.env.GCC_EXEC_PREFIX = compiler.execPrefix + path.sep execOptions.env.PATH = w64binDir + path.delimiter + (execOptions.env.PATH || '') compileCmd = `"${compiler.path}" "${srcFile}" -o "${outFile}" -Wall -std=c99` } else { // GCC/Clang: 先编译再运行 compileCmd = `"${compiler.path}" "${srcFile}" -o "${outFile}" -Wall -std=c99 2>&1` } // 编译 const compileOutput = execSync(compileCmd, execOptions) let runOutput = compileOutput // GCC/Clang: 编译后还需运行 exe if (!compiler.name.includes('tcc') && fs.existsSync(outFile)) { try { runOutput = execSync(`"${outFile}"`, { timeout: 10000, cwd: tmpDir, encoding: 'utf-8', env: execOptions.env }) } catch (runErr) { runOutput = runErr.stdout || runErr.message } } // 清理临时文件 try { if (fs.existsSync(srcFile)) fs.unlinkSync(srcFile) if (fs.existsSync(outFile)) fs.unlinkSync(outFile) } catch {} res.json({ output: runOutput }) } catch (compileErr) { // 编译错误 res.json({ output: compileErr.stdout || compileErr.message, isError: true }) } finally { // 确保清理 try { if (fs.existsSync(srcFile)) fs.unlinkSync(srcFile) if (fs.existsSync(outFile)) fs.unlinkSync(outFile) } catch {} } }) // 健康检查 app.get('/api/status', (req, res) => { const compiler = findCompiler() res.json({ status: 'ok', compiler: compiler ? `${compiler.name} (${compiler.path})` : '未安装' }) }) // 下载 TCC 脚本 app.get('/api/setup-compiler', (req, res) => { res.json({ message: '请手动下载 TCC:', url: 'https://raw.githubusercontent.com/FooBarWidget/tinycc/master/tcc.exe', instructions: `将 tcc.exe 放入 ${path.join(__dirname, 'bin')} 目录` }) }) app.listen(PORT, () => { console.log(`✅ C 代码运行服务已启动: http://localhost:${PORT}`) const compiler = findCompiler() if (compiler) { console.log(` 检测到编译器: ${compiler.name}`) } else { console.log(` ⚠️ 未检测到 C 编译器,请安装后使用`) console.log(` 下载 TCC: https://raw.githubusercontent.com/FooBarWidget/tinycc/master/tcc.exe`) console.log(` 放置路径: ${path.join(__dirname, 'bin', 'tcc.exe')}`) } })