V0.35.0.250624_alpha:新增了服务代码模板生成的C++后端

This commit is contained in:
jinchao 2025-06-24 16:53:06 +08:00
parent ac6c62730e
commit 38b224f0c4
15 changed files with 1187 additions and 0 deletions

Binary file not shown.

View File

@ -466,6 +466,7 @@ bool XNModelGen::GenerateSourceFile()
}
sourceFile << "}" << std::endl;
sourceFile << std::endl;
sourceFile.close();
return true;
}

View File

@ -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"
}
}

View File

@ -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 .
)

View File

@ -0,0 +1,216 @@
#include "XNCodeZip.h"
#include <filesystem>
#include <fstream>
#include <zip.h>
#include <cstring>
#include <functional>
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<void(const fs::path &, const fs::path &)> addToZip =
[&](const fs::path &currentPath, 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;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <string>
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);
};

View File

@ -0,0 +1,64 @@
#include "XNServiceCompile.h"
#include <filesystem>
#include <cstdlib>
#include <iostream>
#include <unistd.h>
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<std::uintmax_t>(-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;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <string>
class XNServiceCompile
{
public:
XNServiceCompile() = delete;
~XNServiceCompile() = delete;
static int Compile(const std::string &srcPath, std::string &errorMsg);
};

View File

@ -0,0 +1,368 @@
#include "XNServiceGen.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;
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 <XNCore/XNServiceObject.h>" << 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 <XNCore/XNServiceObject_p.h>" << 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 <XNCore/XNServiceManager.h>" << 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 << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
configFile << "<Service>" << 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;
// TODO: 添加命令列表
configFile << " <CommandList/>" << std::endl;
configFile << "</Service>" << 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<std::string> XNServiceGen::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;
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <string>
#include <vector>
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<std::string> 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;
};

View File

@ -0,0 +1,157 @@
#include "XNServiceGenServer.h"
#include "XNServiceGen.h"
#include "XNCodeZip.h"
#include "XNServiceCompile.h"
#include <cstring>
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;
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "XNServiceGenServer_global.h"
#include <string>
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);

View File

@ -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

View File

@ -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}/.."
)

View File

@ -0,0 +1,129 @@
#include <iostream>
#include <cstring>
#include <dlfcn.h>
// 函数指针类型定义
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;
}