编译运行模块是一个网络服务,这样编译模块就可以可以快速部署到,其他主机上。
编译模块思路
util.hpp
#pragma once
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <atomic>
#include <fstream>
#include <boost/algorithm/string.hpp>
namespace ns_util
{
class utiltime
{
public:
static std::string getTime() // 获取秒级别的时间戳
{
timeval t;
gettimeofday(&t, nullptr);
return std::to_string(t.tv_sec);
}
static std::string getMTime() // 获取微秒级别的时间戳
{
timeval t;
gettimeofday(&t, nullptr);
return std::to_string(t.tv_sec * 1000 + t.tv_usec / 1000);
}
};
std::string path = "../temp/";
class util
{
private:
static std::string addSuffix(std::string &filename, std::string suffix)
{
std::string ret = path;
ret += filename;
ret += suffix;
return ret;
}
public:
// 构建完整的编译文件的路径 + 后缀
// 1234 -> 1234.cpp
static std::string src(std::string filename)
{
return addSuffix(filename, ".cpp");
}
// 构建编译生成 可执行程序名字 + 后缀
// 1234 -> 1234.exe
static std::string exu(std::string filename)
{
return addSuffix(filename, ".exe");
}
// 构建编译错误生成的 文件名 + 后缀
static std::string err(std::string filename)
{
return addSuffix(filename, ".cerr");
}
// 构建运行时 输入的 文件名 + 后缀
static std::string Stdin(std::string filename)
{
return addSuffix(filename, ".stdin");
}
// 构建运行时 输出的 文件名 + 后缀
static std::string Stdout(std::string filename)
{
return addSuffix(filename, ".stdout");
}
// 构建输出错误的文件名 + 后缀
static std::string Stderr(std::string filename)
{
return addSuffix(filename, ".stderr");
}
};
// 检索文件是否存在
class utilfile
{
public:
// 清理临时文件
static void clearTempfile(const std::string &filename)
{
// 因为生成文件数是不确定的,所以删除之前需要判断其存不存在
if (fileIsExsit(util::src(filename)))
unlink(util::src(filename).c_str());
if (fileIsExsit(util::exu(filename)))
unlink(util::exu(filename).c_str());
if (fileIsExsit(util::err(filename)))
unlink(util::err(filename).c_str());
if (fileIsExsit(util::Stdin(filename)))
unlink(util::Stdin(filename).c_str());
if (fileIsExsit(util::Stdout(filename)))
unlink(util::Stdout(filename).c_str());
if (fileIsExsit(util::Stderr(filename)))
unlink(util::Stderr(filename).c_str());
}
// 判断文件是否存在
static bool fileIsExsit(std::string filename)
{
struct stat statbuf;
int n = stat(filename.c_str(), &statbuf);
return n == 0 ? true : false;
}
// 毫秒级时间戳 + 唯一原子递增值
static std::string uniquefilename() // 生成一个唯一的文件名
{
static std::atomic_int a(0);
a++;
std::string t = utiltime::getMTime();
return t + "_" + std::to_string(a);
}
static bool writefile(const std::string &filename, std::string &buffer) // 向代码文件中写入
{
std::ofstream out(filename);
if (!out.is_open())
{
return false;
}
out << buffer;
out.close();
return true;
}
//读取文件
static bool readfile(const std::string &filename, std::string &buffer, bool keep = false /*是否保存\n */)
{
buffer.clear();
std::ifstream in(filename);
if (!in.is_open())
{
return false;
}
std::string tmp;
while (getline(in, tmp))
{
buffer += tmp;
buffer += (keep ? "\n" : "");
}
in.close();
return true;
}
};
class utilstring
{
public:
// s s输入型参数,打算切割的字符串s
// ret 输出型参数, 存储切割完之后的部分
// sep 以哪种分割符进行切割
static void substring(std::string s, std::vector<std::string> &ret,const std::string &sep)
{
boost::split(ret , s, boost::is_any_of(sep), boost::algorithm::token_compress_on);
}
};
}
complier.hpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <wait.h>
#include <fcntl.h>
#include "../comm/util.hpp" // 工具类
#include "../comm/log.hpp"
namespace ns_complier
{
using namespace ns_log;
using namespace ns_util;
class complier
{
public:
complier() {}
~complier() {}
static bool complie(std::string filename)
{
pid_t pid = fork();
if (pid < 0) //创建进程失败
{
Log(ERROR) << "crate child process fail" << std::endl;
return false;
}
else if (pid == 0)// 子进程 进行编译工作
{
// 进行程序替换
umask(0); //权限掩码设置为0
Log(INFO) << "crate child process sucess" << std::endl;
int _stdrr = open(ns_util::util::err(filename).c_str(),\
O_CREAT| O_WRONLY , 0644);
if(_stdrr < 0)
{
Log(ERROR) << "open file fail" << std::endl;
exit(1);
}
// 将标准错误重定向到编译错误文件当中
int n = dup2(_stdrr, STDERR_FILENO);
if(n < 0)
Log(ERROR) << "dup2 fail" << std::endl;
// util::exu() util::src() 详情见工具类
Log(DEBUG) << util::exu(filename) << " " << util::src(filename).c_str();
//程序替换为g++进行编译
execlp("g++", "g++", "-o", util::exu(filename).c_str(),\
util::src(filename).c_str(),"-D", "ONLINE", nullptr /*必须以nullptr结尾 */);// -D选项是条件编译的选项,是为了避免拼 用户代码和测试用例的时候报错。
exit(2);
}
else
{
waitpid(pid, nullptr, 0);
//std::cout << filename << std::endl;
if (ns_util::utilfile::fileIsExsit(util::exu(filename))) // 文件存在编译成功
{
Log(INFO) << "complie success" << std::endl;
return true;
}
}
Log(INFO) << "complie fail" << std::endl;
return false;
}
private:
};
}