XNSim/XNModelGenServer/XNModelGen.cpp

704 lines
26 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>
#include <sstream>
using json = nlohmann::json;
namespace fs = std::filesystem;
XNModelGen::XNModelGen()
{
}
XNModelGen::~XNModelGen()
{
}
const std::string &XNModelGen::GetCodePath() const
{
return m_codePath;
}
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) {
// 读取数据到成员变量 - 按照CREATE TABLE语句的字段顺序
m_planeName = (const char *)sqlite3_column_text(stmt, 0); // PlaneName
m_className = (const char *)sqlite3_column_text(stmt, 1); // ClassName
m_version = (const char *)sqlite3_column_text(stmt, 2); // Version
m_confID = sqlite3_column_int(stmt, 3); // ConfID (INTEGER)
m_name = (const char *)sqlite3_column_text(stmt, 4); // Name
m_author = (const char *)sqlite3_column_text(stmt, 5); // Author
m_description = (const char *)sqlite3_column_text(stmt, 6); // Description
m_createTime = (const char *)sqlite3_column_text(stmt, 7); // CreatTime
m_changeTime = (const char *)sqlite3_column_text(stmt, 8); // ChangeTime
m_runFreq = std::to_string(sqlite3_column_int(stmt, 9)); // RunFreqGroup (INTEGER)
m_runNode = std::to_string(sqlite3_column_int(stmt, 10)); // RunNode (INTEGER)
m_priority = std::to_string(sqlite3_column_int(stmt, 11)); // Priority (INTEGER)
m_dataPackagePath = (const char *)sqlite3_column_text(stmt, 12); // DataPackagePath
m_dataPackageName = (const char *)sqlite3_column_text(stmt, 13); // DataPackageName
m_dataPackageHeaderName =
(const char *)sqlite3_column_text(stmt, 14); // DataPackageHeaderName
m_dataPackageEntryPoint =
(const char *)sqlite3_column_text(stmt, 15); // DataPackageEntryPoint
m_dataPackageInterfaceName =
(const char *)sqlite3_column_text(stmt, 16); // DataPackageInterfaceName
std::string inputStruct = (const char *)sqlite3_column_text(stmt, 17); // InputStruct
ParseStructName(inputStruct, m_inputStructName_Interface, m_inputStructName.originalName);
ParseStructOriginalName(m_inputStructName);
std::string outputStruct = (const char *)sqlite3_column_text(stmt, 18); // OutputStruct
ParseStructName(outputStruct, m_outputStructName_Interface,
m_outputStructName.originalName);
ParseStructOriginalName(m_outputStructName);
std::string heartStruct = (const char *)sqlite3_column_text(stmt, 19); // HeartStruct
ParseStructName(heartStruct, m_heartStructName_Interface, m_heartStructName.originalName);
ParseStructOriginalName(m_heartStructName);
// 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 > 0) {
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;
}
// 绑定参数 - ConfID是INTEGER类型
sqlite3_bind_int(confStmt, 1, m_confID);
// 执行查询
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: " + std::to_string(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>" << std::endl;
if (m_hasDataPackage) {
pHeaderFile << "#include \"../../Packages/" << m_dataPackagePath << "/"
<< m_dataPackageHeaderName << "\"" << std::endl;
}
pHeaderFile << "#include \"../../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("
<< "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.structName.empty()) {
if (m_inputStructName.isPointer) {
sourceFile << " d->_inputInterface.getData(d->_data."
<< m_inputStructName.structName << ");" << std::endl;
} else {
sourceFile << " d->_inputInterface.getData(&d->_data."
<< m_inputStructName.structName << ");" << std::endl;
}
}
sourceFile << " d->_fun(&d->_data);" << std::endl;
if (!m_outputStructName_Interface.empty() && !m_outputStructName.structName.empty()) {
if (m_outputStructName.isPointer) {
sourceFile << " d->_outputInterface.setData(d->_data."
<< m_outputStructName.structName << ");" << std::endl;
} else {
sourceFile << " d->_outputInterface.setData(&d->_data."
<< m_outputStructName.structName << ");" << std::endl;
}
}
// 这里只适用于本体模型
if (!m_heartStructName_Interface.empty() && !m_heartStructName.structName.empty()) {
if (m_heartStructName.isNumeric) {
sourceFile << " d->_heartbeatInterface.setData(&d->_data);" << std::endl;
}
}
sourceFile << " }" << std::endl;
}
sourceFile << " /* 在这里进行其它运行时计算 */" << std::endl;
sourceFile << "}" << std::endl;
sourceFile << std::endl;
sourceFile << "void " << m_className << "::InitializeData() {" << std::endl;
sourceFile << " T_D();" << std::endl;
if (!m_inputStructName.structName.empty()) {
if (m_inputStructName.isPointer) {
sourceFile << " d->_data." << m_inputStructName.structName << " = new "
<< m_inputStructName.structType << ";" << std::endl;
}
sourceFile << " // TODO: 在这里初始化输入数据" << std::endl;
sourceFile << std::endl;
}
if (!m_outputStructName.structName.empty()) {
if (m_outputStructName.isPointer) {
sourceFile << " d->_data." << m_outputStructName.structName << " = new "
<< m_outputStructName.structType << ";" << std::endl;
}
sourceFile << " // TODO: 在这里初始化输出数据" << std::endl;
sourceFile << std::endl;
}
// 心跳数据,仅适用于本体模型
if (!m_heartStructName.structName.empty()) {
if (m_heartStructName.isNumeric) {
sourceFile << " d->_data." << m_heartStructName.structName << " = 0;" << std::endl;
}
}
sourceFile << "}" << std::endl;
sourceFile << std::endl;
sourceFile << "void " << m_className << "::ReleaseData() {" << std::endl;
sourceFile << " T_D();" << std::endl;
if (!m_inputStructName.structName.empty()) {
if (m_inputStructName.isPointer) {
sourceFile << " if (d->_data." << m_inputStructName.structName << ") {" << std::endl;
sourceFile << " // TODO: 在这里释放输入数据" << std::endl;
sourceFile << std::endl;
sourceFile << " delete d->_data." << m_inputStructName.structName << ";"
<< std::endl;
sourceFile << " d->_data." << m_inputStructName.structName << " = nullptr;"
<< std::endl;
sourceFile << " }" << std::endl;
}
}
if (!m_outputStructName.structName.empty()) {
if (m_outputStructName.isPointer) {
sourceFile << " if (d->_data." << m_outputStructName.structName << ") {"
<< std::endl;
sourceFile << " // TODO: 在这里释放输出数据" << std::endl;
sourceFile << std::endl;
sourceFile << " delete d->_data." << m_outputStructName.structName << ";"
<< std::endl;
sourceFile << " d->_data." << m_outputStructName.structName << " = nullptr;"
<< std::endl;
sourceFile << " }" << std::endl;
}
}
sourceFile << "}" << std::endl;
sourceFile << std::endl;
sourceFile.close();
return true;
}
bool XNModelGen::GenerateConfigFile()
{
std::string configPath = m_codePath + "/" + m_className + ".mcfg";
std::ofstream configFile(configPath);
if (!configFile.is_open()) {
return false;
}
configFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
configFile << "<Model>" << std::endl;
configFile << " <Name>" << m_className << "</Name>" << std::endl;
configFile << " <Description>" << m_description << "</Description>" << std::endl;
configFile << " <Author>" << m_author << "</Author>" << std::endl;
configFile << " <Version>" << m_version << "</Version>" << std::endl;
configFile << " <CreateTime>" << m_createTime << "</CreateTime>" << std::endl;
configFile << " <ChangeTime>" << m_changeTime << "</ChangeTime>" << std::endl;
configFile << " <Node>" << m_runNode << "</Node>" << std::endl;
configFile << " <Priority>" << m_priority << "</Priority>" << std::endl;
configFile << " <MathLib>" << m_dataPackagePath << "/" << m_dataPackageName << "</MathLib>"
<< std::endl;
// TODO: 添加命令列表
configFile << " <CommandList/>" << std::endl;
configFile << "</Model>" << std::endl;
configFile.close();
return true;
}
bool XNModelGen::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(MODEL_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;
// 设置默认构建类型为Release
cmakeListsFile << "if(NOT CMAKE_BUILD_TYPE)" << std::endl;
cmakeListsFile << "\tset(CMAKE_BUILD_TYPE Release CACHE STRING "
<< "\"Choose the type of build (Debug, Release, RelWithDebInfo, MinSizeRel)\""
<< " FORCE)" << std::endl;
cmakeListsFile << "endif()" << 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 << "include_directories(${XNCore_PATH}/IDL)" << 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 << " ${XNCore_PATH}/lib/lib" << m_confName << "_Interface.so" << std::endl;
cmakeListsFile << " dl" << 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}/Configuration/" << m_confName
<< "/Models\" 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 \"*.mcfg\")" << std::endl;
cmakeListsFile << std::endl;
cmakeListsFile << "install(FILES ${CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX} RENAME "
"\"${CMAKE_PROJECT_NAME}_V${MODEL_VERSION}.mcfg\")"
<< std::endl;
cmakeListsFile << std::endl;
cmakeListsFile.close();
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;
}
bool XNModelGen::IsPointer(const std::string &str)
{
return str.find("*") != std::string::npos;
}
bool XNModelGen::IsNumeric(const std::string &str)
{
return str.find("int") != std::string::npos || str.find("float") != std::string::npos
|| str.find("double") != std::string::npos || str.find("long") != std::string::npos
|| str.find("short") != std::string::npos || str.find("char") != std::string::npos
|| str.find("bool") != std::string::npos;
}
void XNModelGen::ParseStructName(const std::string &str, std::string &interfaceName,
std::string &structName)
{
try {
json j = json::parse(str);
// 遍历JSON对象第一个键作为interfaceName(数据库中的字段名)第一个值作为structName(头文件中的结构体名)
if (!j.empty() && j.is_object()) {
auto it = j.begin();
if (it != j.end()) {
interfaceName = it.key();
if (it.value().is_string()) {
structName = it.value();
}
}
}
} catch (const json::exception &e) {
// JSON解析失败将整个字符串作为structName
structName = "";
interfaceName = "";
}
}
std::vector<std::string> XNModelGen::SplitString(const std::string &str)
{
std::vector<std::string> result;
std::stringstream ss(str);
std::string token;
while (ss >> token) {
result.push_back(token);
}
return result;
}
void XNModelGen::ParseStructOriginalName(InterfaceStructInfo &structInfo)
{
std::vector<std::string> tokens = SplitString(structInfo.originalName);
if (tokens.empty()) {
return;
}
// 处理 "struct" 关键字
int startIndex = 0;
if (tokens[0] == "struct") {
startIndex = 1;
}
if (startIndex >= tokens.size()) {
return;
}
// 获取结构体类型名,检查是否包含指针符号
std::string typeToken = tokens[startIndex];
bool hasPointer = false;
std::string structType = typeToken;
// 检查类型名本身是否包含指针符号
if (typeToken.find("*") != std::string::npos) {
hasPointer = true;
// 移除指针符号,获取纯类型名
structType = typeToken;
structType.erase(std::remove(structType.begin(), structType.end(), '*'), structType.end());
}
structInfo.structType = structType;
// 获取结构体名称
std::string structName;
int nameIndex = startIndex + 1;
while (nameIndex < tokens.size()) {
std::string token = tokens[nameIndex];
// 如果当前token是单独的指针符号
if (token == "*") {
hasPointer = true;
nameIndex++;
continue;
}
// 如果当前token包含指针符号
if (token.find("*") != std::string::npos) {
hasPointer = true;
// 移除指针符号,获取结构体名称
structName = token;
structName.erase(std::remove(structName.begin(), structName.end(), '*'),
structName.end());
} else {
// 普通的结构体名称
structName = token;
}
break; // 找到结构体名称后退出
}
structInfo.isPointer = hasPointer;
structInfo.structName = structName;
structInfo.isNumeric = IsNumeric(structInfo.structType);
}