1.compiler服务设计|makefile|util|compiler|日志功能|日志功能调用|测试编译模块(C++)

compiler服务设计

![[Pasted image 20250219155549.png]]

提供的服务:编译并运行代码,得到格式化的相关的结果
compiler.hpp:提供编译服务
runner.hpp:提供运行服务
compile_run.hpp:整合功能,既调用compiler又调用runner
compile_server.cc:基于网络请求的编译并运行服务
makefile
![[Pasted image 20250219105019.png]]

编写makefile
compile_server:compile_server.cc
    g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
    rm -f compile_server
编写util.hpp

创建一个temp路径来保存临时文件
![[Pasted image 20250219111604.png]]

在comm文件夹创建一个util.hpp,提供一个工具类
![[Pasted image 20250219111916.png]]

util.hpp

#pragma once
  
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
  
namespace ns_util
{
    const std::string temp_path = "./temp/";
    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &file_name, const std::string &suffix)
        {
            std::string path_name = temp_path;
            path_name += file_name;
            path_name += suffix;
            return path_name;
        }
        //构建源文件路径+后缀的完整文件名
        //1234 -> ./temp/1234.cpp
        static std::string Src(const std::string &file_name)
        {
            return AddSuffix(file_name, ".cpp");
        }
        //构建可执行程序的完整路径+后缀名
        static std::string Exe(const std::string &file_name)
        {
            return AddSuffix(file_name, ".exe");
        }
        //构建该程序对应的标准错误完整路径+后缀名
        static std::string Stderr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stderr");
        }
    };
  
    class FileUtil {
        public:
        static bool IsFileExists(const std::string &path_name)
        {
            struct stat st;
            if(stat(path_name.c_str(), &st) == 0){
                //获取属性成功,文件已经存在
                return true;
            }
            return false;
        }
    };
}
编写compiler.hpp

compiler.hpp

#pragma once
  
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "../comm/util.hpp"
  
// 只负责进行代码的编译
  
namespace ns_compiler
{
    //引入路径拼接功能
    using namespace ns_util;
  
    class Compiler{
        public:
        Compiler()
        {}
        ~Compiler()
        {}
        //返回值:编译成功:true,否则:false
        //输入参数:编译的文件名
        //1234 -> ./temp/1234.cpp源文件
        //1234 -> ./temp/1234.exe可执行程序文件名
        //1234 -> ./temp/1234.stderr标准错误文件名
        static bool Compile(const std::string &file_name)
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                return false;
            }
            else if (pid == 0)
            {
                int _stderr = open(PathUtil::Stderr(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if(_stderr < 0){
                    exit(1);
                }
  
                //重定向标准错误到_stderr
                dup2(_stderr, 2);
                //程序替换,并不影响进程的文件描述符表
                // 子进程:调用编译器,完成对代码的编译工作
                //g++ -o target src -std=c++11
                execlp("g++", "-o", PathUtil::Exe(file_name).c_str(), \
                PathUtil::Src(file_name).c_str(), "-std=c++11", nullptr/*不要忘记*/);
                exit(2);
            }
            else{
                waitpid(pid, nullptr, 0);
                //编译是否成功,就看有没有形成对应的可执行程序
                if(FileUtil::IsFileExists(PathUtil::Exe(file_name))){
                    return true;
                }
            }
  
            return false;
        }
    };
}

日志功能

在comm新建一个log.hpp
![[Pasted image 20250219160001.png]]

log.hpp

#pragma once
  
#include <iostream>
#include <string>
#include "util.hpp"
  
namespace ns_log
{
    using namespace ns_util;
  
    //日志等级
    enum {
        INFO,
        DEBUG,
        WARNING,
        ERROR,
        FATAL
    };
  
    inline std::ostream &Log(const std::string &level, const std::string &file_name, int line)
    {
        // 添加日志等级
        std::string message = "[";
        message += level;
        message += "]";
  
        // 添加报错文件名称
        message += "[";
        message += file_name;
        message += "]";
  
        // 添加报错行
        message += "[";
        message += std::to_string(line);
        message += "]";
  
        // 日志时间戳
        message += "[";
        message += TimeUtil::GetTimeStamp();
        message += "]";
  
        // cout 本质 内部是包含缓冲区的
        std::cout << message; //不要endl进行刷新
  
        return std::cout;
    }
    // LOG(INFo) << "message" << "\n";
    // 开放式日志
    #define LOG(level) Log(#level, __FILE__, __LINE__)
}

util.hpp,添加TimeUtil类

    class TimeUtil
    {
    public:
        static std::string GetTimeStamp()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            return std::to_string(_time.tv_sec);
        }
    };

日志功能调用

#pragma once
  
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
  
#include "../comm/util.hpp"
#include "../comm/log.hpp"
  
// 只负责进行代码的编译
  
namespace ns_compiler
{
    //引入路径拼接功能
    using namespace ns_util;
    using namespace ns_log;
  
    class Compiler{
        public:
        Compiler()
        {}
        ~Compiler()
        {}
        //返回值:编译成功:true,否则:false
        //输入参数:编译的文件名
        //1234 -> ./temp/1234.cpp源文件
        //1234 -> ./temp/1234.exe可执行程序文件名
        //1234 -> ./temp/1234.stderr标准错误文件名
        static bool Compile(const std::string &file_name)
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                LOG(ERROR) << "内部错误,创建子进程失败" << "\n";
                return false;
            }
            else if (pid == 0)
            {
                int _stderr = open(PathUtil::Stderr(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if(_stderr < 0){
                    LOG(WARNING) << "没有成功形成stderr文件" << "\n";
                    exit(1);
                }
  
                //重定向标准错误到_stderr
                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(), "-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(ERROR) << "编译失败,没有形成可执行程序" << "\n";
            return false;
        }
    };
}

测试编译模块

在temp文件夹里添加一个code.cpp作为测试代码

#include <iostream>

int main()
{
    std::cout << "hello world!" << std::endl;
    return 0;
}

编写compile_server.cc

#include "compiler.hpp"
  
using namespace ns_compiler;
  
int main()
{
    std::string code = "code";
    Compiler::Compile(code);
  
    return 0;
}

编译运行compile_server
![[Pasted image 20250219171050.png]]

编译成功
在temp有code执行文件
![[Pasted image 20250219171334.png]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值