XNSim/XNModelGenServer/XNModelGen.cpp

439 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "XNModelGen.h"
#include <sqlite3.h>
#include <stdexcept>
#include <filesystem>
#include <cstdlib>
#include <fstream>
#include <algorithm>
#include <nlohmann/json.hpp>
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 <XNCore/XNModelObject.h>" << 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 <XNCore/XNModelObject_p.h>";
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 <XNCore/XNModelManager.h>" << 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 = "";
}
}