#include "XNServiceGen.h" #include #include #include #include #include #include #include #include using json = nlohmann::json; namespace fs = std::filesystem; XNServiceGen::XNServiceGen() { } XNServiceGen::~XNServiceGen() { } const std::string &XNServiceGen::GetCodePath() const { return m_codePath; } int XNServiceGen::Initialize(const std::string &className, const std::string &version, std::string &errorMsg) { std::string dbPath = GetXNCorePath() + "/database/XNSim.db"; sqlite3 *db; int rc = sqlite3_open(dbPath.c_str(), &db); if (rc != SQLITE_OK) { errorMsg = "无法打开数据库: " + std::string(sqlite3_errmsg(db)); return -1; } std::string sql = "SELECT * FROM XNServiceVersion WHERE ClassName = ? AND Version = ?"; sqlite3_stmt *stmt; rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr); if (rc != SQLITE_OK) { errorMsg = "准备XNServiceVersion表SQL语句失败: " + std::string(sqlite3_errmsg(db)); sqlite3_close(db); return -1; } // 绑定参数 sqlite3_bind_text(stmt, 1, className.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, version.c_str(), -1, SQLITE_STATIC); // 执行查询 rc = sqlite3_step(stmt); if (rc == SQLITE_ROW) { // 读取数据到成员变量 - 按照CREATE TABLE语句的字段顺序 m_className = (const char *)sqlite3_column_text(stmt, 0); // ClassName m_version = (const char *)sqlite3_column_text(stmt, 2); // Version m_name = (const char *)sqlite3_column_text(stmt, 1); // Name m_author = (const char *)sqlite3_column_text(stmt, 3); // Author m_description = (const char *)sqlite3_column_text(stmt, 4); // Description m_createTime = (const char *)sqlite3_column_text(stmt, 5); // CreatTime m_changeTime = (const char *)sqlite3_column_text(stmt, 6); // ChangeTime // TODO cmdList暂不读取 } else if (rc == SQLITE_DONE) { // 没有找到数据 errorMsg = "未找到匹配的XNServiceVersion记录"; sqlite3_finalize(stmt); sqlite3_close(db); return -2; } else { // 查询出错 errorMsg = "查询XNServiceVersion表执行失败: " + std::string(sqlite3_errmsg(db)); sqlite3_finalize(stmt); sqlite3_close(db); return -3; } sqlite3_finalize(stmt); sqlite3_close(db); //目录组装 m_workPath = GetXNCorePath() + "/Service"; m_codePath = GetXNCorePath() + "/ServiceProjects/" + className + "_" + version; return 0; } int XNServiceGen::GenerateCode(std::string &errorMsg) { // 检查代码目录是否存在,不存在则创建 if (!fs::exists(m_codePath)) { try { fs::create_directories(m_codePath); } catch (const fs::filesystem_error &e) { errorMsg = "创建代码目录失败: " + std::string(e.what()); return -1; } } bool ret = GenerateHeaderFile(); if (!ret) { errorMsg = "生成头文件失败"; return -2; } ret = GenerateSourceFile(); if (!ret) { errorMsg = "生成源文件失败"; return -3; } ret = GenerateConfigFile(); if (!ret) { errorMsg = "生成配置文件失败"; return -4; } ret = GenerateCMakeLists(); if (!ret) { errorMsg = "生成CMakeLists.txt失败"; return -5; } return 0; } bool XNServiceGen::GenerateHeaderFile() { std::string globalHeaderPath = m_codePath + "/" + m_className + "_global.h"; std::ofstream globalHeaderFile(globalHeaderPath); if (!globalHeaderFile.is_open()) { return false; } std::string upperClassName = UpperCase(m_className); // 导入导出定义文件 globalHeaderFile << "#ifndef " << upperClassName << "_GLOBAL_H" << std::endl; globalHeaderFile << "#define " << upperClassName << "_GLOBAL_H" << std::endl; globalHeaderFile << std::endl; globalHeaderFile << "#if defined(" << upperClassName << "_LIBRARY)" << std::endl; globalHeaderFile << "#define " << upperClassName << "_EXPORT __attribute__((visibility(\"default\")))" << std::endl; globalHeaderFile << "#else" << std::endl; globalHeaderFile << "#define " << upperClassName << "_EXPORT __attribute__((visibility(\"default\")))" << std::endl; globalHeaderFile << "#endif" << std::endl; globalHeaderFile << std::endl; globalHeaderFile << "#endif // " << upperClassName << "_GLOBAL_H" << std::endl; globalHeaderFile << std::endl; globalHeaderFile.close(); // 模型头文件 std::string headerPath = m_codePath + "/" + m_className + ".h"; std::ofstream headerFile(headerPath); if (!headerFile.is_open()) { return false; } headerFile << "#pragma once" << std::endl; headerFile << std::endl; headerFile << "#include \"" << m_className << "_global.h\"" << std::endl; headerFile << "#include " << std::endl; headerFile << std::endl; headerFile << "struct " << m_className << "Private;" << std::endl; headerFile << std::endl; headerFile << "class " << upperClassName << "_EXPORT " << m_className << " : public XNServiceObject" << std::endl; headerFile << "{" << std::endl; headerFile << "XN_METATYPE(" << m_className << ", XNServiceObject)" << std::endl; headerFile << "XN_DECLARE_PRIVATE(" << m_className << ")" << std::endl; headerFile << "public:" << std::endl; headerFile << " " << m_className << "();" << std::endl; headerFile << " virtual ~" << m_className << "();" << std::endl; headerFile << std::endl; headerFile << "protected:" << std::endl; headerFile << " " << m_className << "(PrivateType *p);" << std::endl; headerFile << std::endl; headerFile << "public:" << std::endl; headerFile << " virtual void Initialize() override;" << std::endl; headerFile << " virtual void PrepareForExecute() override;" << std::endl; headerFile << std::endl; headerFile << "};" << std::endl; headerFile << std::endl; headerFile << "XNCLASS_PTR_DECLARE(" << m_className << ")" << std::endl; headerFile << std::endl; headerFile.close(); // 私有结构体头文件 std::string pHeaderPath = m_codePath + "/" + m_className + "_p.h"; std::ofstream pHeaderFile(pHeaderPath); if (!pHeaderFile.is_open()) { return false; } pHeaderFile << "#pragma once" << std::endl; pHeaderFile << std::endl; pHeaderFile << "#include " << std::endl; pHeaderFile << std::endl; pHeaderFile << "struct " << m_className << "Private : public XNServiceObjectPrivate{" << std::endl; pHeaderFile << "};" << std::endl; pHeaderFile << std::endl; pHeaderFile.close(); return true; } bool XNServiceGen::GenerateSourceFile() { // 源文件 std::string sourcePath = m_codePath + "/" + m_className + ".cpp"; std::ofstream sourceFile(sourcePath); if (!sourceFile.is_open()) { return false; } sourceFile << "#include \"" << m_className << ".h\"" << std::endl; sourceFile << "#include \"" << m_className << "_p.h\"" << std::endl; sourceFile << "#include " << std::endl; sourceFile << std::endl; sourceFile << "XN_SERVICE_INITIALIZE(" << m_className << ")" << std::endl; sourceFile << std::endl; sourceFile << m_className << "::" << m_className << "() : XNServiceObject(" << "new " << m_className << "Private())" << std::endl; sourceFile << "{" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; sourceFile << m_className << "::~" << m_className << "() {" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; sourceFile << m_className << "::" << m_className << "(PrivateType *p) : XNServiceObject(p)" << std::endl; sourceFile << "{" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; sourceFile << "void " << m_className << "::Initialize() {" << std::endl; sourceFile << " T_D();" << std::endl; sourceFile << " SuperType::Initialize();" << std::endl; sourceFile << " /* 在这里进行其它初始化 */" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; sourceFile << "void " << m_className << "::PrepareForExecute() {" << std::endl; sourceFile << " T_D();" << std::endl; sourceFile << " SuperType::PrepareForExecute();" << std::endl; sourceFile << " /* 在这里进行其它运行前准备工作 */" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; sourceFile.close(); return true; } bool XNServiceGen::GenerateConfigFile() { std::string configPath = m_codePath + "/" + m_className + ".mcfg"; std::ofstream configFile(configPath); if (!configFile.is_open()) { return false; } configFile << "" << std::endl; configFile << "" << std::endl; configFile << " " << m_className << "" << std::endl; configFile << " " << m_description << "" << std::endl; configFile << " " << m_author << "" << std::endl; configFile << " " << m_version << "" << std::endl; configFile << " " << m_createTime << "" << std::endl; configFile << " " << m_changeTime << "" << std::endl; // TODO: 添加命令列表 configFile << " " << std::endl; configFile << "" << std::endl; configFile.close(); return true; } bool XNServiceGen::GenerateCMakeLists() { std::string cmakeListsPath = m_codePath + "/CMakeLists.txt"; std::ofstream cmakeListsFile(cmakeListsPath); if (!cmakeListsFile.is_open()) { return false; } cmakeListsFile << "cmake_minimum_required(VERSION 3.16)" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "project(" << m_className << " LANGUAGES CXX)" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "set(SERVICE_VERSION \"" << m_version << "\")" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "set(CMAKE_CXX_STANDARD 17)" << std::endl; cmakeListsFile << "set(CMAKE_CXX_STANDARD_REQUIRED ON)" << std::endl; cmakeListsFile << "set(CMAKE_POSITION_INDEPENDENT_CODE ON)" << std::endl; cmakeListsFile << std::endl; // 获取环境变量 cmakeListsFile << "if(DEFINED ENV{XNCore})" << std::endl; cmakeListsFile << " set(XNCore_PATH $ENV{XNCore})" << std::endl; cmakeListsFile << "else()" << std::endl; cmakeListsFile << " message(FATAL_ERROR \"Environment variable XNCore is not set.\")" << std::endl; cmakeListsFile << "endif()" << std::endl; cmakeListsFile << std::endl; // 添加 XNCore_PATH 下的 include 目录为包含目录 cmakeListsFile << "include_directories(${XNCore_PATH}/include)" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "add_library(" << m_className << " SHARED" << std::endl; cmakeListsFile << " " << m_className << "_global.h" << std::endl; cmakeListsFile << " " << m_className << ".cpp" << std::endl; cmakeListsFile << " " << m_className << ".h" << std::endl; cmakeListsFile << " " << m_className << "_p.h" << std::endl; cmakeListsFile << ")" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "set_target_properties(" << m_className << " PROPERTIES" << std::endl; cmakeListsFile << " LIBRARY_OUTPUT_NAME \"lib" << m_className << ".so." << m_version << "\"" << std::endl; cmakeListsFile << " PREFIX \"\"" << std::endl; cmakeListsFile << " SUFFIX \"\"" << std::endl; cmakeListsFile << " SKIP_BUILD_RPATH TRUE" << std::endl; cmakeListsFile << " BUILD_WITH_INSTALL_RPATH TRUE" << std::endl; cmakeListsFile << ")" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "target_link_libraries(" << m_className << " PRIVATE" << std::endl; cmakeListsFile << " ${XNCore_PATH}/lib/libXNCore.so" << std::endl; cmakeListsFile << ")" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "target_compile_definitions(" << m_className << " PRIVATE " << UpperCase(m_className) << "_LIBRARY)" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)" << std::endl; cmakeListsFile << " set(CMAKE_INSTALL_PREFIX \"${XNCore_PATH}/Services\" CACHE PATH " "\"Install path prefix\" FORCE)" << std::endl; cmakeListsFile << "endif()" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "install(TARGETS " << m_className << " BUNDLE DESTINATION . LIBRARY DESTINATION . RUNTIME DESTINATION .)" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "file(GLOB CONFIG_FILE \"*.scfg\")" << std::endl; cmakeListsFile << std::endl; cmakeListsFile << "install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX} RENAME " "\"${CMAKE_PROJECT_NAME}_V${SERVICE_VERSION}.scfg\")" << std::endl; cmakeListsFile << std::endl; cmakeListsFile.close(); return true; } std::string XNServiceGen::GetXNCorePath() { const char *env_value = std::getenv("XNCore"); return env_value ? env_value : ""; } std::string XNServiceGen::UpperCase(const std::string &str) { std::string result = str; std::transform(result.begin(), result.end(), result.begin(), ::toupper); return result; } std::vector XNServiceGen::SplitString(const std::string &str) { std::vector result; std::stringstream ss(str); std::string token; while (ss >> token) { result.push_back(token); } return result; }