XNSim/XNMonitorServer/PluginGenerator.cpp

387 lines
11 KiB
C++
Raw Permalink 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.

/**
* @file PluginGenerator.cpp
* @brief 简化的插件生成器实现
*/
#include "PluginGenerator.h"
std::string GetXNCorePath()
{
const char *xnCorePath = std::getenv("XNCore");
if (xnCorePath != nullptr) {
return std::string(xnCorePath);
}
return "";
}
PluginGenerator::PluginGenerator()
{
}
PluginGenerator::~PluginGenerator()
{
}
bool PluginGenerator::loadPluginFromDatabase(const int confID)
{
std::string xncorePath = GetXNCorePath();
if (xncorePath.empty()) {
m_lastError = "无法获取XNCore环境变量的值";
return false;
}
std::string dbPath = xncorePath + "/database/XNSim.db";
if (!std::filesystem::exists(dbPath)) {
m_lastError = "数据库文件不存在!";
return false;
}
sqlite3 *db = nullptr;
int rc = sqlite3_open(dbPath.c_str(), &db);
if (rc != SQLITE_OK) {
m_lastError = "无法打开数据库: " + std::string(sqlite3_errmsg(db));
sqlite3_close(db);
return false;
}
// 准备SQL语句查询Configuration表
const char *sql = "SELECT ConfName FROM Configuration WHERE ConfID = ?";
sqlite3_stmt *stmt = nullptr;
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
m_lastError = "SQL准备失败: " + std::string(sqlite3_errmsg(db));
sqlite3_close(db);
return false;
}
// 绑定参数
sqlite3_bind_int(stmt, 1, confID);
// 执行查询
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *text = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
m_pluginInfo.pluginName = text ? text : "";
m_pluginInfo.interfaceHeaderPath = "../IDL/" + m_pluginInfo.pluginName + "_Interface.h";
m_pluginInfo.outputDirectory =
xncorePath + "/Configuration/" + m_pluginInfo.pluginName + "/PluginCode";
} else {
m_lastError = "未找到ConfID为 " + std::to_string(confID) + " 的配置";
sqlite3_finalize(stmt);
sqlite3_close(db);
return false;
}
// 清理资源
sqlite3_finalize(stmt);
// 查询DataInterface_{ConfID}表获取接口信息
std::string dataInterfaceTableName = "DataInterface_" + std::to_string(confID);
std::string dataInterfaceSql =
"SELECT DISTINCT ModelStructName, SystemName, PlaneName, ATAName FROM "
+ dataInterfaceTableName;
sqlite3_stmt *dataInterfaceStmt = nullptr;
rc = sqlite3_prepare_v2(db, dataInterfaceSql.c_str(), -1, &dataInterfaceStmt, nullptr);
if (rc != SQLITE_OK) {
m_lastError = "DataInterface表SQL准备失败: " + std::string(sqlite3_errmsg(db));
sqlite3_close(db);
return false;
}
// 执行查询并收集接口信息
while (sqlite3_step(dataInterfaceStmt) == SQLITE_ROW) {
InterfaceInfo interface;
interface.interfaceName =
reinterpret_cast<const char *>(sqlite3_column_text(dataInterfaceStmt, 0));
std::string systemName =
reinterpret_cast<const char *>(sqlite3_column_text(dataInterfaceStmt, 1));
std::string planeName =
reinterpret_cast<const char *>(sqlite3_column_text(dataInterfaceStmt, 2));
std::string ataName =
reinterpret_cast<const char *>(sqlite3_column_text(dataInterfaceStmt, 3));
interface.templateType = systemName + "::" + planeName + "::" + ataName
+ "::" + interface.interfaceName + "_Interface";
// 使用ModelStructName去重
bool isDuplicate = false;
for (const auto &existingInterface : m_pluginInfo.interfaces) {
if (existingInterface.interfaceName == interface.interfaceName) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
m_pluginInfo.interfaces.push_back(interface);
}
}
// 清理DataInterface查询资源
sqlite3_finalize(dataInterfaceStmt);
sqlite3_close(db);
return true;
}
bool PluginGenerator::generatePluginCpp()
{
std::string content = generatePluginCppContent();
std::string filePath =
m_pluginInfo.outputDirectory + "/" + m_pluginInfo.pluginName + "_plugin.cpp";
return writeFile(filePath, content);
}
bool PluginGenerator::generateCMakeLists()
{
std::string content = generateCMakeListsContent();
std::string filePath = m_pluginInfo.outputDirectory + "/CMakeLists.txt";
return writeFile(filePath, content);
}
bool PluginGenerator::compilePlugin()
{
std::string buildDir = m_pluginInfo.outputDirectory + "/build";
// 如果build目录已存在则删除
if (std::filesystem::exists(buildDir)) {
try {
std::filesystem::remove_all(buildDir);
} catch (const std::exception &e) {
m_lastError = "Failed to remove existing build directory: " + std::string(e.what());
return false;
}
}
// 创建build目录
if (!createDirectory(buildDir)) {
m_lastError = "Failed to create build directory: " + buildDir;
return false;
}
// 构建命令
std::string cmakeCmd = "cd " + buildDir + " && cmake ..";
std::string makeCmd = "cd " + buildDir + " && make";
std::string installCmd = "cd " + buildDir + " && make install";
// 执行cmake
int cmakeResult = system(cmakeCmd.c_str());
if (cmakeResult != 0) {
m_lastError = "CMake failed with exit code: " + std::to_string(cmakeResult);
return false;
}
// 执行make
int makeResult = system(makeCmd.c_str());
if (makeResult != 0) {
m_lastError = "Make failed with exit code: " + std::to_string(makeResult);
return false;
}
// 执行make install
int installResult = system(installCmd.c_str());
if (installResult != 0) {
m_lastError = "Make install failed with exit code: " + std::to_string(installResult);
return false;
}
return true;
}
std::string PluginGenerator::getLastError() const
{
return m_lastError;
}
std::string PluginGenerator::generatePluginCppContent()
{
std::stringstream ss;
// 生成头文件包含
ss << "#include <XNMonitor/PluginInterface.h>\n";
ss << "#include <XNMonitor/DataMonitor.h>\n";
ss << "// " << m_pluginInfo.pluginName << "接口头文件 - 只在插件中包含\n";
ss << "#include \"" << m_pluginInfo.interfaceHeaderPath << "\"\n\n";
// 生成插件信息
ss << "// 插件信息\n";
ss << "static PluginInfo plugin_info = {\"" << m_pluginInfo.pluginName << "\", \""
<< "" << "\", DATAMONITOR_PLUGIN_INTERFACE_VERSION};\n\n";
// 生成支持的接口列表
ss << "// 支持的接口列表\n";
ss << "static const char *supported_interfaces[] = {\n";
for (size_t i = 0; i < m_pluginInfo.interfaces.size(); ++i) {
ss << " \"" << m_pluginInfo.interfaces[i].interfaceName << "\"";
if (i < m_pluginInfo.interfaces.size() - 1) {
ss << ",";
}
ss << "\n";
}
ss << "};\n\n";
ss << "static const int interface_count = sizeof(supported_interfaces) / "
"sizeof(supported_interfaces[0]);\n\n";
// 生成导出的插件函数
ss << "// 导出的插件函数\n";
ss << "extern \"C\"\n";
ss << "{\n\n";
// get_plugin_info函数
ss << " PluginInfo *get_plugin_info()\n";
ss << " {\n";
ss << " return &plugin_info;\n";
ss << " }\n\n";
// create_monitor函数
ss << " DataMonitorBasePtr create_monitor(const char *interfaceName)\n";
ss << " {\n";
ss << " std::string name(interfaceName);\n\n";
for (size_t i = 0; i < m_pluginInfo.interfaces.size(); ++i) {
const auto &interface = m_pluginInfo.interfaces[i];
ss << " if (name == \"" << interface.interfaceName << "\") {\n";
ss << " return std::make_shared<DataMonitorProduct<" << interface.templateType
<< ">>();\n";
ss << " }";
if (i < m_pluginInfo.interfaces.size() - 1) {
ss << " else";
}
ss << "\n";
}
ss << " return nullptr;\n";
ss << " }\n\n";
// destroy_monitor函数
ss << " void destroy_monitor(const char *interfaceName)\n";
ss << " {\n";
ss << " // 智能指针会自动管理内存,这里可以添加额外的清理逻辑\n";
ss << " }\n\n";
// get_supported_interfaces函数
ss << " const char **get_supported_interfaces(int *count)\n";
ss << " {\n";
ss << " if (count) {\n";
ss << " *count = interface_count;\n";
ss << " }\n";
ss << " return const_cast<const char **>(supported_interfaces);\n";
ss << " }\n\n";
// free_string_array函数
ss << " void free_string_array(const char **array)\n";
ss << " {\n";
ss << " // 这里不需要释放,因为使用的是静态数组\n";
ss << " }\n";
ss << "}\n";
return ss.str();
}
std::string PluginGenerator::generateCMakeListsContent()
{
std::stringstream ss;
std::string projectName = m_pluginInfo.pluginName + "_Monitor";
ss << "# CMakeLists.txt for " << projectName << " plugin\n";
ss << "cmake_minimum_required(VERSION 3.10)\n\n";
ss << "# 设置项目名称\n";
ss << "project(" << projectName << "_plugin)\n\n";
ss << "# 设置C++标准\n";
ss << "set(CMAKE_CXX_STANDARD 17)\n";
ss << "set(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n";
// 设置默认构建类型为Release
ss << "if(NOT CMAKE_BUILD_TYPE)" << std::endl;
ss << "\tset(CMAKE_BUILD_TYPE Release CACHE STRING "
<< "\"Choose the type of build (Debug, Release, RelWithDebInfo, MinSizeRel)\""
<< " FORCE)" << std::endl;
ss << "endif()" << std::endl;
ss << std::endl;
ss << "# 查找必要的包\n";
ss << "find_package(PkgConfig REQUIRED)\n";
ss << "find_package(FastDDS REQUIRED)\n";
ss << "if(DEFINED ENV{XNCore})\n";
ss << " set(XNCore_PATH $ENV{XNCore})\n";
ss << "else()\n";
ss << " message(FATAL_ERROR \"Environment variable XNCore is not set.\")\n";
ss << "endif()\n";
ss << "include_directories(${XNCore_PATH}/include)\n";
ss << "# 创建插件库\n";
ss << "add_library(" << projectName << " SHARED\n";
ss << " " << m_pluginInfo.pluginName << "_plugin.cpp\n";
ss << ")\n\n";
ss << "# 链接库\n";
ss << "target_link_libraries(" << projectName << "\n";
ss << " fastcdr\n";
ss << " fastdds\n";
ss << " OpenSSL::SSL\n";
ss << " OpenSSL::Crypto\n";
ss << " ${XNCore_PATH}/lib/lib" << m_pluginInfo.pluginName << "_Interface.so\n";
ss << " ${XNCore_PATH}/lib/libXNMonitorServer.so\n";
ss << ")\n\n";
ss << "target_compile_definitions(" << projectName << " PRIVATE " << projectName
<< "_LIBRARY)\n";
ss << "if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n";
ss << " set(CMAKE_INSTALL_PREFIX \"${XNCore_PATH}/Configuration/" << m_pluginInfo.pluginName
<< "/Plugins\" CACHE PATH \"Install path prefix\" "
"FORCE)\n";
ss << "endif()\n";
ss << "include(GNUInstallDirs)\n";
ss << "install(TARGETS " << projectName << "\n";
ss << " BUNDLE DESTINATION .\n";
ss << " LIBRARY DESTINATION .\n";
ss << " RUNTIME DESTINATION .\n";
ss << ")\n";
return ss.str();
}
bool PluginGenerator::writeFile(const std::string &filePath, const std::string &content)
{
try {
// 确保目录存在
std::filesystem::path path(filePath);
if (path.has_parent_path()) {
createDirectory(path.parent_path().string());
}
std::ofstream file(filePath);
if (!file.is_open()) {
m_lastError = "无法创建文件: " + filePath;
return false;
}
file << content;
file.close();
return true;
} catch (const std::exception &e) {
m_lastError = "写入文件错误: " + std::string(e.what());
return false;
}
}
bool PluginGenerator::createDirectory(const std::string &dirPath)
{
try {
if (!std::filesystem::exists(dirPath)) {
return std::filesystem::create_directories(dirPath);
}
return true;
} catch (const std::exception &e) {
m_lastError = "创建目录错误: " + std::string(e.what());
return false;
}
}
const GenPluginInfo &PluginGenerator::getPluginInfo() const
{
return m_pluginInfo;
}