VoiletCStudio v1.0 - 紫罗兰 C 工程配置器
功能特性: - JSON 格式工程配置文件 - 虚拟目录管理(类似 MDK) - 跨平台 CMake 自动生成 - 一键编译 Debug/Release - 拖拽文件打开工程 - 实时编译输出显示 作者:虾哥 日期:2026-04-09
This commit is contained in:
293
src/cmakegenerator.cpp
Normal file
293
src/cmakegenerator.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
#include "cmakegenerator.h"
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
|
||||
CMakeGenerator::CMakeGenerator(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool CMakeGenerator::generate(const ProjectConfig *config, const QString &outputPath)
|
||||
{
|
||||
if (!config) {
|
||||
emit errorOccurred("配置对象为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
QString content = generateContent(config);
|
||||
|
||||
QFileInfo fileInfo(outputPath);
|
||||
QDir dir = fileInfo.absoluteDir();
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
|
||||
QFile file(outputPath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
emit errorOccurred("无法创建 CMakeLists.txt: " + file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(&file);
|
||||
out.setCodec("UTF-8");
|
||||
out << content;
|
||||
file.close();
|
||||
|
||||
m_lastGeneratedPath = outputPath;
|
||||
emit cmakeGenerated(outputPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::getLastGeneratedPath() const
|
||||
{
|
||||
return m_lastGeneratedPath;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateContent(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
|
||||
content += generateHeader(config);
|
||||
content += "\n";
|
||||
content += generateProjectConfig(config);
|
||||
content += "\n";
|
||||
content += generateSourceFiles(config);
|
||||
content += "\n";
|
||||
content += generateIncludeDirs(config);
|
||||
content += "\n";
|
||||
content += generateLibraries(config);
|
||||
content += "\n";
|
||||
content += generateDefines(config);
|
||||
content += "\n";
|
||||
content += generateCompilerOptions(config);
|
||||
content += "\n";
|
||||
content += generateBuildTargets(config);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateHeader(const ProjectConfig *config)
|
||||
{
|
||||
QString header;
|
||||
header += "# ========================================\n";
|
||||
header += "# CMakeLists.txt - VoiletCStudio 自动生成\n";
|
||||
header += "# 工程名称:" + config->getProjectName() + "\n";
|
||||
header += "# 生成时间:" + QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") + "\n";
|
||||
header += "# 跨平台支持:Windows (MinGW) / Linux (GCC) / macOS (Clang)\n";
|
||||
header += "# ========================================\n\n";
|
||||
|
||||
header += "cmake_minimum_required(VERSION 3.10)\n\n";
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateProjectConfig(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
|
||||
QString projectName = config->getProjectName();
|
||||
if (projectName.isEmpty()) {
|
||||
projectName = "UntitledProject";
|
||||
}
|
||||
|
||||
content += "# 项目名称\n";
|
||||
content += "project(" + projectName + " C)\n\n";
|
||||
|
||||
content += "# C 标准\n";
|
||||
content += "set(CMAKE_C_STANDARD 11)\n";
|
||||
content += "set(CMAKE_C_STANDARD_REQUIRED ON)\n\n";
|
||||
|
||||
// 输出目录配置
|
||||
QString outputDir = config->getOutputDir();
|
||||
if (outputDir.isEmpty()) {
|
||||
outputDir = "./build";
|
||||
}
|
||||
|
||||
content += "# 输出目录配置\n";
|
||||
content += "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/" + outputDir + ")\n";
|
||||
content += "set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/" + outputDir + ")\n";
|
||||
content += "set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/" + outputDir + ")\n\n";
|
||||
|
||||
// 编译器配置
|
||||
content += "# 编译器配置\n";
|
||||
if (!config->getCompilerPath().isEmpty() && config->getCompilerPath() != "gcc") {
|
||||
content += "set(CMAKE_C_COMPILER \"" + config->getCompilerPath() + "\")\n";
|
||||
}
|
||||
content += "\n";
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateSourceFiles(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
content += "# ========================================\n";
|
||||
content += "# 源文件配置(虚拟目录结构)\n";
|
||||
content += "# ========================================\n\n";
|
||||
|
||||
QMap<QString, VirtualDir> virtualDirs = config->getVirtualDirs();
|
||||
|
||||
if (virtualDirs.isEmpty()) {
|
||||
content += "# 无源文件\n";
|
||||
} else {
|
||||
// 遍历虚拟目录
|
||||
for (auto it = virtualDirs.begin(); it != virtualDirs.end(); ++it) {
|
||||
content += "# 分组:" + it.key() + "\n";
|
||||
QString safeName = it.key();
|
||||
safeName.replace(" ", "_");
|
||||
safeName.replace("/", "_");
|
||||
content += "set(SRCS_" + safeName + "\n";
|
||||
for (const QString &file : it->files) {
|
||||
content += " " + file + "\n";
|
||||
}
|
||||
content += ")\n\n";
|
||||
}
|
||||
|
||||
// 合并所有源文件
|
||||
content += "# 合并所有源文件\n";
|
||||
content += "set(SOURCES\n";
|
||||
for (auto it = virtualDirs.begin(); it != virtualDirs.end(); ++it) {
|
||||
for (const QString &file : it->files) {
|
||||
content += " " + file + "\n";
|
||||
}
|
||||
}
|
||||
content += ")\n\n";
|
||||
}
|
||||
|
||||
content += "# 创建可执行文件\n";
|
||||
QString outputName = config->getProjectName();
|
||||
if (outputName.isEmpty()) {
|
||||
outputName = "output";
|
||||
}
|
||||
|
||||
content += "add_executable(" + outputName + " ${SOURCES})\n\n";
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateIncludeDirs(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
content += "# 包含目录\n";
|
||||
|
||||
QStringList includeDirs = config->getIncludeDirs();
|
||||
if (includeDirs.isEmpty()) {
|
||||
content += "# 无额外包含目录\n";
|
||||
} else {
|
||||
content += "target_include_directories(" + config->getProjectName() + " PRIVATE\n";
|
||||
for (const QString &dir : includeDirs) {
|
||||
content += " " + dir + "\n";
|
||||
}
|
||||
content += ")\n";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateLibraries(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
content += "# 链接库\n";
|
||||
|
||||
QStringList libraries = config->getLibraries();
|
||||
if (libraries.isEmpty()) {
|
||||
content += "# 无外部库文件\n";
|
||||
} else {
|
||||
content += "target_link_libraries(" + config->getProjectName() + " PRIVATE\n";
|
||||
for (const QString &lib : libraries) {
|
||||
content += " " + lib + "\n";
|
||||
}
|
||||
content += ")\n";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateDefines(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
content += "# 预编译宏定义\n";
|
||||
|
||||
QStringList defines = config->getDefines();
|
||||
if (defines.isEmpty()) {
|
||||
content += "# 无额外宏定义\n";
|
||||
} else {
|
||||
content += "target_compile_definitions(" + config->getProjectName() + " PRIVATE\n";
|
||||
for (const QString &def : defines) {
|
||||
content += " " + def + "\n";
|
||||
}
|
||||
content += ")\n";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateCompilerOptions(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
content += "# 自定义编译选项\n";
|
||||
|
||||
QStringList options = config->getCompilerOptions();
|
||||
if (options.isEmpty()) {
|
||||
content += "# 无自定义编译选项\n";
|
||||
} else {
|
||||
content += "target_compile_options(" + config->getProjectName() + " PRIVATE\n";
|
||||
for (const QString &opt : options) {
|
||||
content += " " + opt + "\n";
|
||||
}
|
||||
content += ")\n";
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
QString CMakeGenerator::generateBuildTargets(const ProjectConfig *config)
|
||||
{
|
||||
QString content;
|
||||
|
||||
content += "# ========================================\n";
|
||||
content += "# 构建类型配置\n";
|
||||
content += "# ========================================\n\n";
|
||||
|
||||
content += "# 默认构建类型:Debug\n";
|
||||
content += "if(NOT CMAKE_BUILD_TYPE)\n";
|
||||
content += " set(CMAKE_BUILD_TYPE Debug CACHE STRING \"Build type\" FORCE)\n";
|
||||
content += "endif()\n\n";
|
||||
|
||||
content += "# Debug 模式配置(自动添加 DEBUG 宏)\n";
|
||||
content += "set(CMAKE_C_FLAGS_DEBUG \"-g -O0 -DDEBUG\" CACHE STRING \"Debug flags\" FORCE)\n\n";
|
||||
|
||||
content += "# Release 模式配置\n";
|
||||
content += "set(CMAKE_C_FLAGS_RELEASE \"-O2 -DNDEBUG\" CACHE STRING \"Release flags\" FORCE)\n\n";
|
||||
|
||||
content += "# ========================================\n";
|
||||
content += "# 自定义 Make 目标:make debug / make release\n";
|
||||
content += "# ========================================\n\n";
|
||||
|
||||
content += "# make debug - 编译 Debug 版本(自动添加 DEBUG 宏)\n";
|
||||
content += "add_custom_target(debug\n";
|
||||
content += " COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}\n";
|
||||
content += " COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config Debug\n";
|
||||
content += " COMMENT \"Building Debug version\"\n";
|
||||
content += " VERBATIM\n";
|
||||
content += ")\n\n";
|
||||
|
||||
content += "# make release - 编译 Release 版本\n";
|
||||
content += "add_custom_target(release\n";
|
||||
content += " COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR}\n";
|
||||
content += " COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config Release\n";
|
||||
content += " COMMENT \"Building Release version\"\n";
|
||||
content += " VERBATIM\n";
|
||||
content += ")\n\n";
|
||||
|
||||
content += "# 使用说明:\n";
|
||||
content += "# cmake -B build # 配置(默认 Debug)\n";
|
||||
content += "# cmake --build build # 编译(使用当前 CMAKE_BUILD_TYPE)\n";
|
||||
content += "# make debug # 编译 Debug 版本(自动添加 DEBUG 宏)\n";
|
||||
content += "# make release # 编译 Release 版本\n";
|
||||
|
||||
return content;
|
||||
}
|
||||
Reference in New Issue
Block a user