XNSim/XNMonitorServer/PluginGenerator.cpp

387 lines
11 KiB
C++
Raw Normal View History

/**
* @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;
}