Java后台调用gcc编译C语言代码

想做一个能够在线编译代码运行的平台,Java和SQL已经支持了,因为是用Java写的后台,所以Java和SQL挺容易就实现了,做到支持C的时候就卡住了,网上搜了一下这种帖子好像很少。

 

我采取的办法是就是刚开始学C语言的教的调用GCC来编译.C文件的文件,首先将前端传过来的C代码写入到特定的路径下,然后利用Java的API调用CMD来执行gcc命令编译这个文件,这好像有点MakeFile文件的意思。。编译之后继续调用CMD执行生成的exe,同时获取CMD的输出,至此整个过程完成,但是最后需要做好一项善后工作,那就是继续调用CMD将这个exe的进程杀掉,否则会出现问题,因为exe还没停止,继续编译写入会报权限问题。

 

封装了整个编译运行的Servivce:

package com.mine.ide.service.implement;

import com.mine.ide.util.CLangUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.concurrent.*;

/**
 * @author yintianhao
 * @createTime 20190625 11:14
 * @description ExecuteCLang
 */
@Service
public class ExecuteCLangService {
    private static final Logger log = Logger.getLogger(ExecuteCLangService.class);

    //代码存放路径
    public static final String CODE_PATH = "D:\\springboot2\\code\\";


    /**
     * @param content C代码
     * */
    private boolean generateCFile(String content){
        BufferedWriter out = null;
        try{
            //写入
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(CODE_PATH+"test.c", false)));
            out.write(content);
        }catch (Exception e){
            log.error(e.getCause().getMessage());
            return false;
        }finally {
            try {
                out.close();
            }catch (IOException e){
                log.error(e.getCause().getMessage());
                return false;
            }
        }
        return true;
    }
    /**
     * @param sourceCode 源代码
     * */
    public String runCLangCode(String sourceCode){
        //先生成文件
        generateCFile(sourceCode);
        Executor executor = Executors.newSingleThreadExecutor();
        FutureTask futureTask = new FutureTask(new Callable() {
            @Override
            public String call() throws Exception {
                //编译C文件
                String compileResult = execCmd("gcc -o "+CODE_PATH+"test "+CODE_PATH+"test.c",null);
                if (compileResult.equals(""))
                    //编译不出错的情况,replaceAll将\n换成HTML的换行,空格换成HTML的空格
                    return execCmd(CODE_PATH+"test.exe",null).replaceAll("\n","
").replaceAll(" "," "); else { //编译出错,找到error的位置,返回error及其后的信息 int errorIndex = compileResult.indexOf("error"); return compileResult.substring(errorIndex).replaceAll("\n","
").replaceAll(" "," "); } } }); executor.execute(futureTask); try { //编译运行完毕将text.exe的进程kill execCmd("taskkill /f /im test.exe",null); log.info("killed test.exe"); }catch (Exception e){ e.printStackTrace(); } String result = ""; try{ //设置超时时间 result=futureTask.get(10, TimeUnit.SECONDS); }catch (InterruptedException e) { log.info("Interrupt"); result = "程序中断,请检查是否有内存冲突等错误"; // future.cancel(true); }catch (ExecutionException e) { result = "程序执行错误"; futureTask.cancel(true); }catch (TimeoutException e) { result = "时间超限,请检查是否存在无限循环等程序无法自动结束的情况"; } log.info("result - "+result); return result.equals("")?"没有输出":result; } /** * 执行系统命令, 返回执行结果 * @param cmd 需要执行的命令 * @param dir 执行命令的子进程的工作目录, null 表示和当前主进程工作目录相同 */ private String execCmd(String cmd, File dir) throws Exception { StringBuilder result = new StringBuilder(); Process process = null; BufferedReader bufrIn = null; BufferedReader bufrError = null; try { // 执行命令, 返回一个子进程对象(命令在子进程中执行) process = Runtime.getRuntime().exec(cmd, null, dir); // 方法阻塞, 等待命令执行完成(成功会返回0) process.waitFor(); // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出(PS: 子进程的输出就是主进程的输入) bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8")); // 读取输出 String line = null; while ((line = bufrIn.readLine()) != null) { result.append(line).append('\n'); } while ((line = bufrError.readLine()) != null) { result.append(line).append('\n'); } } finally { closeStream(bufrIn); closeStream(bufrError); // 销毁子进程 if (process != null) { process.destroy(); } } // 返回执行结果 return result.toString(); } private void closeStream(Closeable stream) { if (stream != null) { try { stream.close(); } catch (Exception e) { // nothing } } } }

 

至此写完,之后只要调用runCLangCode方法就可以了

 

你可能感兴趣的:(Java后台调用gcc编译C语言代码)