#include "XNModelGen.h" #include #include #include #include #include #include #include using json = nlohmann::json; namespace fs = std::filesystem; XNModelGen::XNModelGen() { } XNModelGen::~XNModelGen() { } int XNModelGen::Initialize(const std::string &className, const std::string &version, const std::string &planeName, 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 XNModelsVersion WHERE ClassName = ? AND Version = ? AND PlaneName = ?"; sqlite3_stmt *stmt; rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr); if (rc != SQLITE_OK) { errorMsg = "准备XNModelsVersion表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); sqlite3_bind_text(stmt, 3, planeName.c_str(), -1, SQLITE_STATIC); // 执行查询 rc = sqlite3_step(stmt); if (rc == SQLITE_ROW) { // 读取数据到成员变量 m_planeName = (const char *)sqlite3_column_text(stmt, 1); // PlaneName m_className = (const char *)sqlite3_column_text(stmt, 2); // ClassName m_version = (const char *)sqlite3_column_text(stmt, 3); // Version m_confID = (const char *)sqlite3_column_text(stmt, 4); // ConfID m_name = (const char *)sqlite3_column_text(stmt, 5); // Name m_author = (const char *)sqlite3_column_text(stmt, 6); // Author m_description = (const char *)sqlite3_column_text(stmt, 7); // Description m_createTime = (const char *)sqlite3_column_text(stmt, 8); // CreateTime m_changeTime = (const char *)sqlite3_column_text(stmt, 9); // ChangeTime m_runFreq = (const char *)sqlite3_column_text(stmt, 10); // RunFreq m_runNode = (const char *)sqlite3_column_text(stmt, 11); // RunNode m_priority = (const char *)sqlite3_column_text(stmt, 12); // Priority m_dataPackagePath = (const char *)sqlite3_column_text(stmt, 13); // DataPackagePath m_dataPackageName = (const char *)sqlite3_column_text(stmt, 14); // DataPackageName m_dataPackageHeaderName = (const char *)sqlite3_column_text(stmt, 15); // DataPackageHeaderName m_dataPackageEntryPoint = (const char *)sqlite3_column_text(stmt, 16); // DataPackageEntryPoint m_dataPackageInterfaceName = (const char *)sqlite3_column_text(stmt, 17); // DataPackageInterfaceName std::string inputStruct = (const char *)sqlite3_column_text(stmt, 18); // InputStructName ParseStructName(inputStruct, m_inputStructName, m_inputStructName_Interface); std::string outputStruct = (const char *)sqlite3_column_text(stmt, 19); // OutputStructName ParseStructName(outputStruct, m_outputStructName, m_outputStructName_Interface); std::string heartStruct = (const char *)sqlite3_column_text(stmt, 20); // HeartStructName ParseStructName(outputStruct, m_heartStructName, m_heartStructName_Interface); // TODO cmdList暂不读取 } else if (rc == SQLITE_DONE) { // 没有找到数据 errorMsg = "未找到匹配的XNModelsVersion记录"; sqlite3_finalize(stmt); sqlite3_close(db); return -2; } else { // 查询出错 errorMsg = "查询XNModelsVersion表执行失败: " + std::string(sqlite3_errmsg(db)); sqlite3_finalize(stmt); sqlite3_close(db); return -3; } sqlite3_finalize(stmt); // 根据m_confID查询Configuration表 if (!m_confID.empty()) { std::string confSql = "SELECT ConfName FROM Configuration WHERE ConfID = ?"; sqlite3_stmt *confStmt; rc = sqlite3_prepare_v2(db, confSql.c_str(), -1, &confStmt, nullptr); if (rc != SQLITE_OK) { errorMsg = "准备Configuration表SQL语句失败: " + std::string(sqlite3_errmsg(db)); sqlite3_close(db); return -4; } // 绑定参数 sqlite3_bind_text(confStmt, 1, m_confID.c_str(), -1, SQLITE_STATIC); // 执行查询 rc = sqlite3_step(confStmt); if (rc == SQLITE_ROW) { // 读取Configuration表数据 m_confName = (const char *)sqlite3_column_text(confStmt, 0); // ConfName } else if (rc == SQLITE_DONE) { // 没有找到Configuration记录 errorMsg = "未找到匹配的Configuration记录,ConfID: " + m_confID; sqlite3_finalize(confStmt); sqlite3_close(db); return -5; } else { // Configuration查询出错 errorMsg = "查询Configuration表执行失败: " + std::string(sqlite3_errmsg(db)); sqlite3_finalize(confStmt); sqlite3_close(db); return -6; } sqlite3_finalize(confStmt); } sqlite3_close(db); //目录组装 if (m_confName.empty()) { errorMsg = "Configuration表ConfName为空"; return -7; } m_workPath = GetXNCorePath() + "/Configuration/" + m_confName; m_modelsPath = m_workPath + "/Models"; m_codePath = m_workPath + "/ModelProjects/" + className + "_" + version; m_hasDataPackage = false; if (!m_dataPackagePath.empty() && !m_dataPackageHeaderName.empty() && !m_dataPackageInterfaceName.empty() && !m_dataPackageEntryPoint.empty()) { m_hasDataPackage = true; } return 0; } int XNModelGen::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 XNModelGen::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 XNModelObject" << std::endl; headerFile << "{" << std::endl; headerFile << "XN_METATYPE(" << m_className << ", XNModelObject)" << 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 << " virtual void StepUpdate() override;" << std::endl; headerFile << std::endl; headerFile << "protected:" << std::endl; headerFile << " void InitializeData();" << std::endl; headerFile << " void ReleaseData();" << 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 "; if (m_hasDataPackage) { pHeaderFile << "#include \"" << m_workPath << "/Packages/" << m_dataPackagePath << "/" << m_dataPackageHeaderName << "\"" << std::endl; } pHeaderFile << "#include \"" << m_workPath << "/IDL/" << m_confName << "_Interface.h\"" << std::endl; pHeaderFile << std::endl; if (m_hasDataPackage) { pHeaderFile << "using InterfaceType = " << m_dataPackageInterfaceName << ";" << std::endl; pHeaderFile << "typedef void (*FunctionType)(InterfaceType *);" << std::endl; pHeaderFile << std::endl; } pHeaderFile << "struct " << m_className << "Private : public XNModelObjectPrivate{" << std::endl; if (m_hasDataPackage) { pHeaderFile << " FunctionType _fun = nullptr;" << std::endl; pHeaderFile << " InterfaceType _data;" << std::endl; pHeaderFile << " std::string _entryPointName = \"" << m_dataPackageEntryPoint << "\";" << std::endl; } pHeaderFile << "std::mutex _mutex" << std::endl; if (!m_inputStructName_Interface.empty()) { pHeaderFile << " " << m_inputStructName_Interface << "_Interface _inputInterface;" << std::endl; } if (!m_outputStructName_Interface.empty()) { pHeaderFile << " " << m_outputStructName_Interface << "_Interface _outputInterface;" << std::endl; } if (!m_heartStructName_Interface.empty()) { pHeaderFile << " " << m_heartStructName_Interface << "_Interface _heartbeatInterface;" << std::endl; } pHeaderFile << "};" << std::endl; pHeaderFile << std::endl; pHeaderFile.close(); return true; } bool XNModelGen::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_MODEL_INITIALIZE(" << m_className << ")" << std::endl; sourceFile << std::endl; sourceFile << m_className << "::" << m_className << "() : XNModelObject(" << m_className << "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) : XNModelObject(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; if (m_hasDataPackage) { sourceFile << " if (d->_dynamicLib) {" << std::endl; sourceFile << " d->_fun = (FunctionType)dlsym(d->_dynamicLib, d->_entryPointName.c_str());" << std::endl; sourceFile << " if (!d->_fun) {" << std::endl; sourceFile << " LOG_WARNING(\"Failed to resolve " << m_dataPackageEntryPoint << "\");" << std::endl; sourceFile << " }" << std::endl; sourceFile << " }" << 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 << " InitializeData();" << std::endl; if (!m_inputStructName_Interface.empty()) { sourceFile << " d->_inputInterface.Initialize(GetFramework(), GetUniqueId(), 1);" << std::endl; } if (!m_outputStructName_Interface.empty()) { sourceFile << " d->_outputInterface.Initialize(GetFramework(), GetUniqueId(), 2);" << std::endl; } if (!m_heartStructName_Interface.empty()) { sourceFile << " d->_heartbeatInterface.Initialize(GetFramework(), GetUniqueId(), 2);" << std::endl; } sourceFile << " /* 在这里进行其它运行前准备工作 */" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; sourceFile << "void " << m_className << "::StepUpdate() {" << std::endl; sourceFile << " T_D();" << std::endl; sourceFile << " SuperType::StepUpdate();" << std::endl; if (m_hasDataPackage) { sourceFile << " if(d->_fun){" << std::endl; if (!m_inputStructName_Interface.empty() && !m_inputStructName.empty()) { sourceFile << " d->_inputInterface.getData(&d->_data." << m_inputStructName << ");" << std::endl; } sourceFile << " d->_fun(&d->_data);" << std::endl; if (!m_outputStructName_Interface.empty() && !m_outputStructName.empty()) { sourceFile << " d->_outputInterface.setData(&d->_data." << m_outputStructName << ");" << std::endl; } // 这里只适用于本体模型 if (!m_heartStructName_Interface.empty() && !m_heartStructName.empty() && m_heartStructName == m_dataPackageInterfaceName) { sourceFile << " d->_heartbeatInterface.setData(&d->_data);" << std::endl; } sourceFile << " }" << std::endl; } sourceFile << " /* 在这里进行其它运行时计算 */" << std::endl; sourceFile << "}" << std::endl; sourceFile << std::endl; return true; } bool XNModelGen::GenerateConfigFile() { return true; } bool XNModelGen::GenerateCMakeLists() { return true; } std::string XNModelGen::GetXNCorePath() { const char *env_value = std::getenv("XNCore"); return env_value ? env_value : ""; } std::string XNModelGen::UpperCase(const std::string &str) { std::string result = str; std::transform(result.begin(), result.end(), result.begin(), ::toupper); return result; } void XNModelGen::ParseStructName(const std::string &str, std::string &structName, std::string &interfaceName) { try { json j = json::parse(str); // 遍历JSON对象,第一个键作为structName,第一个值作为interfaceName if (!j.empty() && j.is_object()) { auto it = j.begin(); if (it != j.end()) { structName = it.key(); if (it.value().is_string()) { interfaceName = it.value(); } } } } catch (const json::exception &e) { // JSON解析失败,将整个字符串作为structName structName = ""; interfaceName = ""; } }