diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 1afc36a..22cda0b 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/XNModelGenServer/XNModelGen.cpp b/XNModelGenServer/XNModelGen.cpp index 14d7171..db5340b 100644 --- a/XNModelGenServer/XNModelGen.cpp +++ b/XNModelGenServer/XNModelGen.cpp @@ -466,6 +466,7 @@ bool XNModelGen::GenerateSourceFile() } sourceFile << "}" << std::endl; sourceFile << std::endl; + sourceFile.close(); return true; } diff --git a/XNServiceGenServer/.vscode/settings.json b/XNServiceGenServer/.vscode/settings.json new file mode 100644 index 0000000..d956cd1 --- /dev/null +++ b/XNServiceGenServer/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + "files.associations": { + "chrono": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "map": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "bitset": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "list": "cpp", + "set": "cpp", + "regex": "cpp", + "mutex": "cpp", + "stop_token": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "variant": "cpp" + } +} diff --git a/XNServiceGenServer/CMakeLists.txt b/XNServiceGenServer/CMakeLists.txt new file mode 100644 index 0000000..31f2985 --- /dev/null +++ b/XNServiceGenServer/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.16) + +project(XNServiceGenServer LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 获取环境变量 +if(DEFINED ENV{XNCore}) + set(XNCore_PATH $ENV{XNCore}) +else() + message(FATAL_ERROR "Environment variable XNCore is not set.") +endif() + +# 查找依赖包 +find_package(SQLite3 REQUIRED) +find_package(nlohmann_json 3.9.1 REQUIRED) +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBZIP REQUIRED libzip) + +add_library(XNServiceGenServer SHARED + XNServiceGenServer.h + XNServiceGenServer.cpp + XNServiceGenServer_global.h + XNServiceGen.h + XNServiceGen.cpp + XNCodeZip.h + XNCodeZip.cpp + XNServiceCompile.h + XNServiceCompile.cpp +) + +# 添加头文件搜索路径 +target_include_directories(XNServiceGenServer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(XNServiceGenServer PRIVATE ${LIBZIP_INCLUDE_DIRS}) + +# 链接依赖库 +target_link_libraries(XNServiceGenServer PRIVATE + SQLite::SQLite3 + nlohmann_json::nlohmann_json + ${LIBZIP_LIBRARIES} +) + +target_compile_definitions(XNServiceGenServer PRIVATE XNServiceGenServer_LIBRARY) + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}" CACHE PATH "Install path prefix" FORCE) +endif() + +include(GNUInstallDirs) +install(TARGETS XNServiceGenServer + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION . +) \ No newline at end of file diff --git a/XNServiceGenServer/XNCodeZip.cpp b/XNServiceGenServer/XNCodeZip.cpp new file mode 100644 index 0000000..3a989bd --- /dev/null +++ b/XNServiceGenServer/XNCodeZip.cpp @@ -0,0 +1,216 @@ +#include "XNCodeZip.h" +#include +#include +#include +#include +#include +namespace fs = std::filesystem; + +int XNCodeZip::Zip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg) +{ + // 检查源路径是否存在 + if (!fs::exists(srcPath)) { + errorMsg = "源路径不存在: " + srcPath; + return -1; + } + + // 确保目标目录存在 + fs::path dstDir = fs::path(dstPath).parent_path(); + if (!fs::exists(dstDir)) { + fs::create_directories(dstDir); + } + + // 打开zip文件 + int err = 0; + zip_t *zip = zip_open(dstPath.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &err); + if (zip == nullptr) { + char errstr[1024]; + zip_error_to_str(errstr, sizeof(errstr), err, errno); + errorMsg = "无法创建zip文件: " + std::string(errstr); + return -1; + } + + // 递归添加文件和目录 + std::function addToZip = + [&](const fs::path ¤tPath, const fs::path &relativePath) { + if (fs::is_directory(currentPath)) { + // 添加目录 + std::string dirName = relativePath.string() + "/"; + zip_dir_add(zip, dirName.c_str(), ZIP_FL_OVERWRITE); + + // 递归处理子目录和文件 + for (const auto &entry : fs::directory_iterator(currentPath)) { + fs::path newRelativePath = relativePath / entry.path().filename(); + addToZip(entry.path(), newRelativePath); + } + } else if (fs::is_regular_file(currentPath)) { + // 添加文件 + std::string fileName = relativePath.string(); + zip_source_t *source = zip_source_file(zip, currentPath.c_str(), 0, 0); + if (source == nullptr) { + errorMsg = "无法创建zip源: " + fileName; + return; + } + + if (zip_file_add(zip, fileName.c_str(), source, ZIP_FL_OVERWRITE) < 0) { + zip_source_free(source); + errorMsg = "无法添加文件到zip: " + fileName; + return; + } + } + }; + + // 开始压缩 + fs::path srcDir(srcPath); + fs::path baseName = srcDir.filename(); + addToZip(srcDir, baseName); + + // 关闭zip文件 + zip_close(zip); + + return 0; +} + +int XNCodeZip::Unzip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg) +{ + // 检查源路径是否存在 + if (!fs::exists(srcPath)) { + errorMsg = "源路径不存在: " + srcPath; + return -1; + } + + // 确保目标目录存在 + fs::path dstDir = fs::path(dstPath); + if (!fs::exists(dstDir)) { + fs::create_directories(dstDir); + } + + // 打开zip文件 + int err = 0; + zip_t *zip = zip_open(srcPath.c_str(), 0, &err); + if (zip == nullptr) { + char errstr[1024]; + zip_error_to_str(errstr, sizeof(errstr), err, errno); + errorMsg = "无法打开zip文件: " + std::string(errstr); + return -1; + } + + // 获取zip文件中的条目数量 + zip_int64_t numEntries = zip_get_num_entries(zip, 0); + if (numEntries < 0) { + errorMsg = "无法获取zip文件条目数量"; + zip_close(zip); + return -1; + } + + // 检测根目录名称(去除额外层级) + std::string rootDirName; + bool hasRootDir = false; + + // 检查第一个条目来确定根目录结构 + if (numEntries > 0) { + struct zip_stat st; + if (zip_stat_index(zip, 0, 0, &st) >= 0) { + std::string firstEntry = st.name; + size_t slashPos = firstEntry.find('/'); + if (slashPos != std::string::npos) { + rootDirName = firstEntry.substr(0, slashPos); + hasRootDir = true; + } + } + } + + // 遍历并解压所有条目 + for (zip_int64_t i = 0; i < numEntries; ++i) { + // 获取条目信息 + struct zip_stat st; + if (zip_stat_index(zip, i, 0, &st) < 0) { + errorMsg = "无法获取zip条目信息"; + zip_close(zip); + return -1; + } + + // 跳过空条目 + if (st.size == 0 && st.name[strlen(st.name) - 1] == '/') { + continue; + } + + // 构建目标文件路径,去除根目录层级 + std::string relativePath = st.name; + if (hasRootDir && relativePath.find(rootDirName + "/") == 0) { + relativePath = relativePath.substr(rootDirName.length() + 1); + } + + // 如果去除根目录后路径为空,跳过 + if (relativePath.empty()) { + continue; + } + + fs::path targetPath = dstDir / relativePath; + + // 如果是目录,创建目录 + if (relativePath[relativePath.length() - 1] == '/') { + fs::create_directories(targetPath); + continue; + } + + // 确保文件的父目录存在 + fs::create_directories(targetPath.parent_path()); + + // 检查文件是否已存在 + if (fs::exists(targetPath)) { + // 可以选择跳过、覆盖或询问用户 + // 这里选择覆盖已有文件 + fs::remove(targetPath); + } + + // 打开zip条目 + zip_file_t *zipFile = zip_fopen_index(zip, i, 0); + if (zipFile == nullptr) { + errorMsg = "无法打开zip条目: " + std::string(st.name); + zip_close(zip); + return -1; + } + + // 创建目标文件 + std::ofstream outFile(targetPath, std::ios::binary); + if (!outFile.is_open()) { + errorMsg = "无法创建目标文件: " + targetPath.string(); + zip_fclose(zipFile); + zip_close(zip); + return -1; + } + + // 读取并写入文件内容 + char buffer[8192]; + zip_int64_t bytesRead; + while ((bytesRead = zip_fread(zipFile, buffer, sizeof(buffer))) > 0) { + outFile.write(buffer, bytesRead); + if (!outFile.good()) { + errorMsg = "写入文件失败: " + targetPath.string(); + outFile.close(); + zip_fclose(zipFile); + zip_close(zip); + return -1; + } + } + + // 检查读取是否成功 + if (bytesRead < 0) { + errorMsg = "读取zip条目失败: " + std::string(st.name); + outFile.close(); + zip_fclose(zipFile); + zip_close(zip); + return -1; + } + + // 关闭文件 + outFile.close(); + zip_fclose(zipFile); + } + + // 关闭zip文件 + zip_close(zip); + + return 0; +} \ No newline at end of file diff --git a/XNServiceGenServer/XNCodeZip.h b/XNServiceGenServer/XNCodeZip.h new file mode 100644 index 0000000..240accb --- /dev/null +++ b/XNServiceGenServer/XNCodeZip.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +class XNCodeZip +{ +public: + XNCodeZip() = delete; + ~XNCodeZip() = delete; + + static int Zip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg); + static int Unzip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg); +}; \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceCompile.cpp b/XNServiceGenServer/XNServiceCompile.cpp new file mode 100644 index 0000000..84a12c9 --- /dev/null +++ b/XNServiceGenServer/XNServiceCompile.cpp @@ -0,0 +1,64 @@ +#include "XNServiceCompile.h" +#include +#include +#include +#include + +namespace fs = std::filesystem; +int XNServiceCompile::Compile(const std::string &srcPath, std::string &errorMsg) +{ + // 检查源路径是否存在 + if (!fs::exists(srcPath)) { + errorMsg = "源路径不存在: " + srcPath; + return -1; + } + + // 检查build目录是否存在 + fs::path buildPath = fs::path(srcPath) / "build"; + if (fs::exists(buildPath)) { + // 删除build目录 + if (fs::remove_all(buildPath) != static_cast(-1)) { + std::cout << "已删除build目录: " << buildPath.string() << std::endl; + } else { + errorMsg = "无法删除build目录: " + buildPath.string(); + return -1; + } + } + + // 创建build目录 + if (!fs::exists(buildPath)) { + if (!fs::create_directory(buildPath)) { + errorMsg = "无法创建build目录: " + buildPath.string(); + return -1; + } + } + + // 切换到build目录 + if (chdir(buildPath.c_str()) != 0) { + errorMsg = "无法切换到build目录: " + buildPath.string(); + return -1; + } + + // 执行 cmake .. + int cmakeResult = system("cmake .."); + if (cmakeResult != 0) { + errorMsg = "cmake配置失败"; + return -1; + } + + // 执行 make + int makeResult = system("make"); + if (makeResult != 0) { + errorMsg = "make 编译失败"; + return -1; + } + + // 执行 make install + int makeInstallResult = system("make install"); + if (makeInstallResult != 0) { + errorMsg = "make install失败"; + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceCompile.h b/XNServiceGenServer/XNServiceCompile.h new file mode 100644 index 0000000..f58b68c --- /dev/null +++ b/XNServiceGenServer/XNServiceCompile.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +class XNServiceCompile +{ +public: + XNServiceCompile() = delete; + ~XNServiceCompile() = delete; + + static int Compile(const std::string &srcPath, std::string &errorMsg); +}; \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceGen.cpp b/XNServiceGenServer/XNServiceGen.cpp new file mode 100644 index 0000000..2ca830a --- /dev/null +++ b/XNServiceGenServer/XNServiceGen.cpp @@ -0,0 +1,368 @@ +#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; +} \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceGen.h b/XNServiceGenServer/XNServiceGen.h new file mode 100644 index 0000000..813fae0 --- /dev/null +++ b/XNServiceGenServer/XNServiceGen.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +class XNServiceGen +{ +public: + XNServiceGen(); + ~XNServiceGen(); + + int Initialize(const std::string &className, const std::string &version, std::string &errorMsg); + + int GenerateCode(std::string &errorMsg); + + const std::string &GetCodePath() const; + +private: + std::string GetXNCorePath(); + std::string UpperCase(const std::string &str); + std::vector SplitString(const std::string &str); + + bool GenerateHeaderFile(); + bool GenerateSourceFile(); + bool GenerateCMakeLists(); + bool GenerateConfigFile(); + +private: + std::string m_className; + std::string m_version; + std::string m_name; + std::string m_author; + std::string m_description; + std::string m_createTime; + std::string m_changeTime; + std::string m_workPath; + std::string m_codePath; +}; \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceGenServer.cpp b/XNServiceGenServer/XNServiceGenServer.cpp new file mode 100644 index 0000000..f615958 --- /dev/null +++ b/XNServiceGenServer/XNServiceGenServer.cpp @@ -0,0 +1,157 @@ +#include "XNServiceGenServer.h" +#include "XNServiceGen.h" +#include "XNCodeZip.h" +#include "XNServiceCompile.h" +#include + +int XNServiceCodeGen(const char *className, int classNameLen, const char *version, int versionLen, + char *errorMsg, int errorMsgLen) +{ + std::string classNameStr(className, classNameLen); + std::string versionStr(version, versionLen); + if (classNameStr.empty() || versionStr.empty()) { + if (errorMsg != nullptr) { + strncpy(errorMsg, "className or version is empty", errorMsgLen); + } + return -1; + } + + std::string errorMsgStr; + XNServiceGen serviceGen; + int ret = serviceGen.Initialize(classNameStr, versionStr, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + ret = serviceGen.GenerateCode(errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return 0; +} + +int XNServiceCodeZip(const char *className, int classNameLen, const char *version, int versionLen, + char *dstPath, int dstPathLen, char *errorMsg, int errorMsgLen) +{ + std::string classNameStr(className, classNameLen); + std::string versionStr(version, versionLen); + if (classNameStr.empty() || versionStr.empty()) { + if (errorMsg != nullptr) { + strncpy(errorMsg, "className or version is empty", errorMsgLen); + } + return -1; + } + XNServiceGen serviceGen; + std::string errorMsgStr; + int ret = serviceGen.Initialize(classNameStr, versionStr, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + std::string srcPath = serviceGen.GetCodePath(); + std::string dstPathStr = srcPath; + size_t lastSlash = dstPathStr.find_last_of("/\\"); + if (lastSlash != std::string::npos) { + dstPathStr = dstPathStr.substr(0, lastSlash); + std::string dirName = srcPath.substr(lastSlash + 1); + dstPathStr += "/" + dirName + ".zip"; + } else { + dstPathStr += ".zip"; + } + ret = XNCodeZip::Zip(srcPath, dstPathStr, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + + // 将生成的zip文件路径复制到输出参数 + if (dstPath != nullptr) { + strncpy(dstPath, dstPathStr.c_str(), dstPathLen); + } + + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return 0; +} + +int XNServiceCodeUnzip(const char *className, int classNameLen, const char *version, int versionLen, + const char *srcPath, int srcPathLen, char *errorMsg, int errorMsgLen) +{ + std::string classNameStr(className, classNameLen); + std::string versionStr(version, versionLen); + if (classNameStr.empty() || versionStr.empty()) { + if (errorMsg != nullptr) { + strncpy(errorMsg, "className or version is empty", errorMsgLen); + } + return -1; + } + XNServiceGen serviceGen; + std::string errorMsgStr; + int ret = serviceGen.Initialize(classNameStr, versionStr, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + std::string srcPathStr(srcPath, srcPathLen); + std::string dstPathStr = serviceGen.GetCodePath(); + ret = XNCodeZip::Unzip(srcPathStr, dstPathStr, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return 0; +} + +int XNServiceCodeCompile(const char *className, int classNameLen, const char *version, + int versionLen, char *errorMsg, int errorMsgLen) +{ + std::string classNameStr(className, classNameLen); + std::string versionStr(version, versionLen); + if (classNameStr.empty() || versionStr.empty()) { + if (errorMsg != nullptr) { + strncpy(errorMsg, "className or version is empty", errorMsgLen); + } + return -1; + } + XNServiceGen serviceGen; + std::string errorMsgStr; + int ret = serviceGen.Initialize(classNameStr, versionStr, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + std::string srcPath = serviceGen.GetCodePath(); + ret = XNServiceCompile::Compile(srcPath, errorMsgStr); + if (ret != 0) { + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return ret; + } + if (errorMsg != nullptr) { + strncpy(errorMsg, errorMsgStr.c_str(), errorMsgLen); + } + return 0; +} \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceGenServer.h b/XNServiceGenServer/XNServiceGenServer.h new file mode 100644 index 0000000..c2e4f94 --- /dev/null +++ b/XNServiceGenServer/XNServiceGenServer.h @@ -0,0 +1,23 @@ +#pragma once + +#include "XNServiceGenServer_global.h" +#include + +extern "C" XNSERVICEGENSERVER_EXPORT int XNServiceCodeGen(const char *className, int classNameLen, + const char *version, int versionLen, + char *errorMsg, int errorMsgLen); + +extern "C" XNSERVICEGENSERVER_EXPORT int XNServiceCodeZip(const char *className, int classNameLen, + const char *version, int versionLen, + char *dstPath, int dstPathLen, + char *errorMsg, int errorMsgLen); + +extern "C" XNSERVICEGENSERVER_EXPORT int XNServiceCodeUnzip(const char *className, int classNameLen, + const char *version, int versionLen, + const char *srcPath, int srcPathLen, + char *errorMsg, int errorMsgLen); + +extern "C" XNSERVICEGENSERVER_EXPORT int XNServiceCodeCompile(const char *className, + int classNameLen, const char *version, + int versionLen, char *errorMsg, + int errorMsgLen); \ No newline at end of file diff --git a/XNServiceGenServer/XNServiceGenServer_global.h b/XNServiceGenServer/XNServiceGenServer_global.h new file mode 100644 index 0000000..f4da368 --- /dev/null +++ b/XNServiceGenServer/XNServiceGenServer_global.h @@ -0,0 +1,18 @@ +#ifndef XNSERVICEGENSERVER_GLOBAL_H +#define XNSERVICEGENSERVER_GLOBAL_H + +#if defined(_WIN32) +# if defined(XNSERVICEGENSERVER_LIBRARY) +# define XNSERVICEGENSERVER_EXPORT __declspec(dllexport) +# else +# define XNSERVICEGENSERVER_EXPORT __declspec(dllimport) +# endif +#else +# if defined(XNSERVICEGENSERVER_LIBRARY) +# define XNSERVICEGENSERVER_EXPORT __attribute__((visibility("default"))) +# else +# define XNSERVICEGENSERVER_EXPORT +# endif +#endif + +#endif // XNSERVICEGENSERVER_GLOBAL_H diff --git a/XNServiceGenServer/test/CMakeLists.txt b/XNServiceGenServer/test/CMakeLists.txt new file mode 100644 index 0000000..5e2dc7d --- /dev/null +++ b/XNServiceGenServer/test/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.10) +project(XNModelGenTest) + +# 设置C++标准 +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 查找必要的库 +find_library(DL_LIBRARY dl) + +# 创建测试可执行文件 +add_executable(test_xnmodel test_xnmodel.cpp) + +# 链接动态库 +target_link_libraries(test_xnmodel ${DL_LIBRARY}) + +# 设置运行时库路径 +set_target_properties(test_xnmodel PROPERTIES + BUILD_WITH_INSTALL_RPATH TRUE + INSTALL_RPATH "${CMAKE_SOURCE_DIR}/.." +) \ No newline at end of file diff --git a/XNServiceGenServer/test/test_xnmodel.cpp b/XNServiceGenServer/test/test_xnmodel.cpp new file mode 100644 index 0000000..0d46c44 --- /dev/null +++ b/XNServiceGenServer/test/test_xnmodel.cpp @@ -0,0 +1,129 @@ +#include +#include +#include + +// 函数指针类型定义 +typedef int (*XNModelCodeGenFunc)(const char *className, int classNameLen, const char *version, + int versionLen, const char *planeName, int planeNameLen, + char *errorMsg, int errorMsgLen); + +typedef int (*XNModelCodeZipFunc)(const char *className, int classNameLen, const char *version, + int versionLen, const char *planeName, int planeNameLen, + char *dstPath, int dstPathLen, char *errorMsg, int errorMsgLen); + +typedef int (*XNModelCodeUnzipFunc)(const char *className, int classNameLen, const char *version, + int versionLen, const char *planeName, int planeNameLen, + const char *srcPath, int srcPathLen, char *errorMsg, + int errorMsgLen); + +typedef int (*XNModelCodeCompileFunc)(const char *className, int classNameLen, const char *version, + int versionLen, const char *planeName, int planeNameLen, + char *errorMsg, int errorMsgLen); + +// 测试参数 +const char *className = "XNAerodynamics"; +const char *version = "2.0.3.5"; +const char *planeName = "C909"; + +void printResult(const std::string &testName, int result, const char *errorMsg) +{ + std::cout << testName << " 结果: " << result << std::endl; + if (result == 0) { + std::cout << "✓ " << testName << " 成功!" << std::endl; + } else { + std::cout << "✗ " << testName << " 失败!" << std::endl; + } + + if (strlen(errorMsg) > 0) { + std::cout << "错误信息: " << errorMsg << std::endl; + } + std::cout << std::endl; +} + +int main() +{ + // 动态加载.so库 - 修改路径指向build目录 + void *handle = dlopen("../../build/libXNModelGenServer.so", RTLD_LAZY); + if (!handle) { + std::cerr << "无法加载库文件: " << dlerror() << std::endl; + return -1; + } + + // 获取函数指针 + XNModelCodeGenFunc XNModelCodeGen = (XNModelCodeGenFunc)dlsym(handle, "XNModelCodeGen"); + XNModelCodeZipFunc XNModelCodeZip = (XNModelCodeZipFunc)dlsym(handle, "XNModelCodeZip"); + XNModelCodeUnzipFunc XNModelCodeUnzip = (XNModelCodeUnzipFunc)dlsym(handle, "XNModelCodeUnzip"); + XNModelCodeCompileFunc XNModelCodeCompile = + (XNModelCodeCompileFunc)dlsym(handle, "XNModelCodeCompile"); + + if (!XNModelCodeGen || !XNModelCodeZip || !XNModelCodeUnzip || !XNModelCodeCompile) { + std::cerr << "无法找到函数: " << dlerror() << std::endl; + dlclose(handle); + return -1; + } + + int classNameLen = strlen(className); + int versionLen = strlen(version); + int planeNameLen = strlen(planeName); + + // 错误消息缓冲区 + char errorMsg[1024]; + int errorMsgLen = sizeof(errorMsg); + + std::cout << "开始测试XNModelGen函数..." << std::endl; + std::cout << "参数:" << std::endl; + std::cout << " className: " << className << " (长度: " << classNameLen << ")" << std::endl; + std::cout << " version: " << version << " (长度: " << versionLen << ")" << std::endl; + std::cout << " planeName: " << planeName << " (长度: " << planeNameLen << ")" << std::endl; + std::cout << std::endl; + + // 测试1: XNModelCodeGen + std::cout << "=== 测试1: XNModelCodeGen ===" << std::endl; + memset(errorMsg, 0, sizeof(errorMsg)); + int result1 = XNModelCodeGen(className, classNameLen, version, versionLen, planeName, + planeNameLen, errorMsg, errorMsgLen); + printResult("XNModelCodeGen", result1, errorMsg); + + // 测试2: XNModelCodeZip + std::cout << "=== 测试2: XNModelCodeZip ===" << std::endl; + char dstPath[1024]; + int dstPathLen = sizeof(dstPath); + memset(errorMsg, 0, sizeof(errorMsg)); + memset(dstPath, 0, sizeof(dstPath)); + + int result2 = XNModelCodeZip(className, classNameLen, version, versionLen, planeName, + planeNameLen, dstPath, dstPathLen, errorMsg, errorMsgLen); + printResult("XNModelCodeZip", result2, errorMsg); + + if (result2 == 0 && strlen(dstPath) > 0) { + std::cout << "生成的zip文件路径: " << dstPath << std::endl; + } + + // 测试3: XNModelCodeUnzip + std::cout << "=== 测试3: XNModelCodeUnzip ===" << std::endl; + const char *srcZipPath = dstPath; // 使用上面生成的zip文件路径 + int srcZipPathLen = strlen(srcZipPath); + memset(errorMsg, 0, sizeof(errorMsg)); + + int result3 = XNModelCodeUnzip(className, classNameLen, version, versionLen, planeName, + planeNameLen, srcZipPath, srcZipPathLen, errorMsg, errorMsgLen); + printResult("XNModelCodeUnzip", result3, errorMsg); + + // 测试4: XNModelCodeCompile + std::cout << "=== 测试4: XNModelCodeCompile ===" << std::endl; + memset(errorMsg, 0, sizeof(errorMsg)); + int result4 = XNModelCodeCompile(className, classNameLen, version, versionLen, planeName, + planeNameLen, errorMsg, errorMsgLen); + printResult("XNModelCodeCompile", result4, errorMsg); + + // 清理资源 + dlclose(handle); + + std::cout << "=== 测试总结 ===" << std::endl; + std::cout << "XNModelCodeGen: " << (result1 == 0 ? "成功" : "失败") << std::endl; + std::cout << "XNModelCodeZip: " << (result2 == 0 ? "成功" : "失败") << std::endl; + std::cout << "XNModelCodeUnzip: " << (result3 == 0 ? "成功" : "失败") << std::endl; + std::cout << "XNModelCodeCompile: " << (result4 == 0 ? "成功" : "失败") << std::endl; + + return (result1 == 0 && result2 == 0 && result3 == 0 && result4 == 0) ? 0 : -1; +} \ No newline at end of file