【负载均衡oj】(二)编译模块

发布时间:2023年12月28日

一.编译模块整体结构

编译模块只提供编译功能,所以我们不考虑把用户的代码转换成临时文件的整个过程,假设我们已经拿到了一份代码文件,里面是用户的代码。编译只有两种结果,编译成功和编译失败,出错的时候会将错误信息打印到stder上,我们需要将这段信息还给用户,所以需要输出重定向,生成个一个临时文件用来保存错误信息。同时编译本身这一过程必须是另一个进程或者线程,因为服务器不能卡死。

二.Compiler

只负责提供编译功能,通过创建子进程,并进行进程替换,替换成gcc编译程序,运行用户代码。通过execl或者类似函数实现这一功能。 因为这一过程会产生大量临时文件,我们需要对文件和名字路径进行管理,我们需要一个temp文件夹用来存放临时文件。同时因为拿到的只有要处理的文件名,没有后缀我们需要构建出源文件程序名和可执行程序的文件名,还有标准错误的文件名。这个模块因为会经常使用,所以放在公共模块里。在进程替换完成之后,需要对子进程的编译是否成功进行判断,主进程等待到子进程后,可以通过判断是否生成同名的exe来判断子进程的任务是否成功。所以就需要查找文件是否存在的函数。

处理编译错误产生的错误信息,可以创建一个错误文件,并将标准错误重定向到这个文件上。

class Compiler
    {
    public:
        Compiler() {}

        ~Compiler() {}

        //负责编译客户的代码并生成cc文件
        static bool Compile(const std::string &file_name)
        {
            // 创建子进程进行程序替换执行用户的代码主进程继续执行替他逻辑
            pid_t pid = fork();
            if(pid<0)
            {
                LOG(ERROR)<<"编译创建子进程失败"<<"\n";
            }
            else if (pid==0)    //子进程执行的逻辑
            {
                //先打开日志文件并进行输出重定向,以创建文件和只写的方式
                umask(0);
                //root拥有读写权限,其他只有读权限
                //子进程打开的文件描述符不用主动关闭
                int _stderr = open(PathUtil::CompilerError(file_name).c_str(),O_CREAT|O_WRONLY,0644);
                if(_stderr<0)
                {
                    LOG(ERROR)<<"创建stderr文件失败"<<"\n";
                }
                //重定向标准错误到_stderr
                //拷贝后旧的fd   新的没使用的fd
                dup2(_stderr,2);

                //日志打开完成进行程序替换
                //子进程: 调用编译器,完成对代码的编译工作
                //g++ -o target src -std=c++11
                execlp("g++", "g++", "-o", PathUtil::Exe(file_name).c_str(),PathUtil::Src(file_name).c_str(), "-D", "COMPILER_ONLINE","-std=c++11",  nullptr/*不要忘记*/);

                LOG(ERROR) << "启动编译器g++失败" << "\n";
                exit(2);
            }
            //主进程等待回收子进程
            else
            {
                waitpid(pid,nullptr,0);
                //通过查看可执行文件是否存在判断编译是否成功
                if(FileUtil::IsFileExists(PathUtil::Exe(file_name)))
                {
                    LOG(INFO)<<"编译成功:"<<PathUtil::Src(file_name)<<'\n';
                    return true;
                }
            }
            LOG(INFO)<<"编译失败,无可用执行程序:"<<PathUtil::Src(file_name)<<'\n';
        return false;
        }
    };

文章来源:https://blog.csdn.net/m0_62572672/article/details/135185357
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。