#include "cmakegenerator.h" #include #include #include #include #include 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"; } // ===== 编译器必须在 project() 之前设置,否则 CMake 会默认用 NMake ===== content += "# ========================================\n"; content += "# 编译器配置(必须在 project() 之前)\n"; content += "# ========================================\n\n"; QString compilerPath = config->getCompilerPath(); QString assemblerPath = config->getAssemblerPath(); QString linkerPath = config->getLinkerPath(); if (!compilerPath.isEmpty() && compilerPath != "gcc") { content += "set(CMAKE_C_COMPILER \"" + compilerPath + "\")\n"; // 如果编译器是 MinGW 路径,自动推导 make 程序目录 // 例如:C:/msys2/mingw64/bin/gcc.exe → C:/msys2/mingw64/bin/mingw32-make.exe if (compilerPath.contains("mingw", Qt::CaseInsensitive)) { QString makeDir = QFileInfo(compilerPath).path(); // path() 正确保留绝对路径的盘符 content += "set(CMAKE_MAKE_PROGRAM \"" + makeDir + "/mingw32-make.exe\")\n"; } } if (!assemblerPath.isEmpty() && assemblerPath != "gcc") { content += "set(CMAKE_ASM_COMPILER \"" + assemblerPath + "\")\n"; } if (!linkerPath.isEmpty() && linkerPath != "gcc" && linkerPath != compilerPath) { content += "set(CMAKE_C_LINK_EXECUTABLE \"" + linkerPath + " -o \")\n"; } content += "\n"; 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"; return content; } QString CMakeGenerator::generateSourceFiles(const ProjectConfig *config) { QString content; content += "# ========================================\n"; content += "# 源文件配置(虚拟目录结构)\n"; content += "# ========================================\n\n"; QMap 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; }