Generate version files and integrate into build

Add CMake configure steps to produce version.h and version.sh from
templates and include the build dir for the generated header. Add
version.h.in and version.sh.in, include version.h in VulkanWidget and
use APP_VK_VERSION for the Vulkan applicationVersion. Update make_deb.sh
to source version.sh for the package version instead
This commit is contained in:
ubuntu1804 2025-11-11 17:59:09 +08:00
parent 3c52aa1ca3
commit ad3524bd23
6 changed files with 126 additions and 48 deletions

View File

@ -123,6 +123,20 @@ else()
message(STATUS "Vulkan support disabled") message(STATUS "Vulkan support disabled")
endif() endif()
# Generate version header from template (for C++ code)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/version.h"
@ONLY
)
# Generate version shell script from template (for shell scripts)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/version.sh.in"
"${CMAKE_CURRENT_SOURCE_DIR}/version.sh"
@ONLY
)
# Common source files # Common source files
set(SOURCES set(SOURCES
src/main.cpp src/main.cpp
@ -187,6 +201,11 @@ add_executable(${PROJECT_NAME}
${HEADERS} ${HEADERS}
) )
# Include build directory for generated version.h
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
# Link Qt5 libraries # Link Qt5 libraries
target_link_libraries(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME}
Qt5::Core Qt5::Core

View File

@ -12,13 +12,24 @@ NC='\033[0m' # No Color
# 配置变量 # 配置变量
APP_NAME="ScreenLockDetector" APP_NAME="ScreenLockDetector"
PACKAGE_NAME="ScreenLockDetector" PACKAGE_NAME="ScreenLockDetector"
# 从 CMakeLists.txt 中提取版本号
VERSION=$(grep -oP '(?<=project\(ScreenLockDetector VERSION )[0-9.]+' CMakeLists.txt) # 从自动生成的 version.sh 中读取版本号
if [ -z "$VERSION" ]; then if [ ! -f "version.sh" ]; then
echo -e "${RED}错误: 无法从 CMakeLists.txt 中提取版本号${NC}" echo -e "${RED}错误: version.sh 文件不存在${NC}"
echo -e "${YELLOW}请先运行 ./build.sh 生成版本文件${NC}"
exit 1 exit 1
fi fi
echo -e "${GREEN}✓ 从 CMakeLists.txt 读取版本号: ${VERSION}${NC}"
# Source version.sh to get APP_VERSION
source version.sh
if [ -z "$APP_VERSION" ]; then
echo -e "${RED}错误: 无法从 version.sh 中读取版本号${NC}"
exit 1
fi
VERSION="$APP_VERSION"
echo -e "${GREEN}✓ 从 version.sh 读取版本号: ${VERSION}${NC}"
ARCH="amd64" ARCH="amd64"
QT_DIR="$HOME/sdk/qt-5.15.2" QT_DIR="$HOME/sdk/qt-5.15.2"
LINUXDEPLOYQT="${LINUXDEPLOYQT:-$HOME/tools/sunvpack-py/bin/linuxdeployqt}" LINUXDEPLOYQT="${LINUXDEPLOYQT:-$HOME/tools/sunvpack-py/bin/linuxdeployqt}"

15
src/version.h.in Normal file
View File

@ -0,0 +1,15 @@
#ifndef VERSION_H
#define VERSION_H
// Auto-generated version information from CMakeLists.txt
// DO NOT EDIT THIS FILE MANUALLY - Edit CMakeLists.txt instead
#define APP_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define APP_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define APP_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define APP_VERSION_STRING "@PROJECT_VERSION@"
// Vulkan version macros
#define APP_VK_VERSION VK_MAKE_VERSION(APP_VERSION_MAJOR, APP_VERSION_MINOR, APP_VERSION_PATCH)
#endif // VERSION_H

View File

@ -1,5 +1,6 @@
#include "vulkanwidget.h" #include "vulkanwidget.h"
#include "vulkanrenderer.h" #include "vulkanrenderer.h"
#include "version.h"
#include <QDebug> #include <QDebug>
#include <QShowEvent> #include <QShowEvent>
#include <QHideEvent> #include <QHideEvent>
@ -68,7 +69,7 @@ VulkanWidget::VulkanWidget(QWidget *parent)
// Create render timer // Create render timer
m_renderTimer = new QTimer(this); m_renderTimer = new QTimer(this);
connect(m_renderTimer, &QTimer::timeout, this, &VulkanWidget::onRenderTimer); connect(m_renderTimer, &QTimer::timeout, this, &VulkanWidget::onRenderTimer);
// Initialize FPS calculation // Initialize FPS calculation
m_frameTimes.reserve(FPS_SAMPLE_COUNT); m_frameTimes.reserve(FPS_SAMPLE_COUNT);
@ -111,7 +112,7 @@ void VulkanWidget::setRenderingEnabled(bool enabled)
if (m_renderingEnabled) { if (m_renderingEnabled) {
qDebug() << "Vulkan rendering ENABLED - Resuming animations"; qDebug() << "Vulkan rendering ENABLED - Resuming animations";
// Check if device was lost (e.g., after wake from sleep) // Check if device was lost (e.g., after wake from sleep)
if (m_deviceLost) { if (m_deviceLost) {
qDebug() << "Device lost detected on resume, attempting recovery..."; qDebug() << "Device lost detected on resume, attempting recovery...";
@ -121,7 +122,7 @@ void VulkanWidget::setRenderingEnabled(bool enabled)
return; return;
} }
} }
// 恢复渲染时,重新启动定时器(锁屏时已停止) // 恢复渲染时,重新启动定时器(锁屏时已停止)
if (!m_renderTimer->isActive()) { if (!m_renderTimer->isActive()) {
m_renderTimer->start(16); // ~60 FPS m_renderTimer->start(16); // ~60 FPS
@ -291,7 +292,7 @@ bool VulkanWidget::createInstance()
VkApplicationInfo appInfo = {}; VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "VulkanWidget"; appInfo.pApplicationName = "VulkanWidget";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.applicationVersion = APP_VK_VERSION; // Auto-generated from CMakeLists.txt
appInfo.pEngineName = "No Engine"; appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0; appInfo.apiVersion = VK_API_VERSION_1_0;
@ -344,7 +345,7 @@ bool VulkanWidget::createSurface()
#elif defined(__linux__) #elif defined(__linux__)
VkXlibSurfaceCreateInfoKHR createInfo = {}; VkXlibSurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
// Reuse existing X11 display or open a new one // Reuse existing X11 display or open a new one
Display* x11Display = static_cast<Display*>(m_x11Display); Display* x11Display = static_cast<Display*>(m_x11Display);
if (!x11Display) { if (!x11Display) {
@ -358,7 +359,7 @@ bool VulkanWidget::createSurface()
} else { } else {
qDebug() << "Reusing existing X11 display"; qDebug() << "Reusing existing X11 display";
} }
createInfo.dpy = x11Display; createInfo.dpy = x11Display;
createInfo.window = static_cast<Window>(window->winId()); createInfo.window = static_cast<Window>(window->winId());
@ -772,7 +773,7 @@ void VulkanWidget::renderFrame()
if (!m_initialized || m_isClosing) { if (!m_initialized || m_isClosing) {
return; return;
} }
// Don't render if device is lost (recovery will be attempted on next enable) // Don't render if device is lost (recovery will be attempted on next enable)
if (m_deviceLost) { if (m_deviceLost) {
return; return;
@ -785,14 +786,14 @@ void VulkanWidget::renderFrame()
QDateTime currentTime = QDateTime::currentDateTime(); QDateTime currentTime = QDateTime::currentDateTime();
qint64 frameTimeUs = m_lastFrameTime.msecsTo(currentTime) * 1000; // Convert to microseconds qint64 frameTimeUs = m_lastFrameTime.msecsTo(currentTime) * 1000; // Convert to microseconds
m_lastFrameTime = currentTime; m_lastFrameTime = currentTime;
if (frameTimeUs > 0) { if (frameTimeUs > 0) {
// Add frame time to circular buffer // Add frame time to circular buffer
if (m_frameTimes.size() >= FPS_SAMPLE_COUNT) { if (m_frameTimes.size() >= FPS_SAMPLE_COUNT) {
m_frameTimes.erase(m_frameTimes.begin()); m_frameTimes.erase(m_frameTimes.begin());
} }
m_frameTimes.push_back(frameTimeUs); m_frameTimes.push_back(frameTimeUs);
// Calculate average FPS from recent frames // Calculate average FPS from recent frames
if (!m_frameTimes.empty()) { if (!m_frameTimes.empty()) {
qint64 totalTimeUs = 0; qint64 totalTimeUs = 0;
@ -857,7 +858,7 @@ void VulkanWidget::renderFrame()
result = vkQueueSubmit(m_queue, 1, &submitInfo, m_inFlightFences[m_currentFrame]); result = vkQueueSubmit(m_queue, 1, &submitInfo, m_inFlightFences[m_currentFrame]);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
qDebug() << "Failed to submit draw command buffer! Error code = " << result; qDebug() << "Failed to submit draw command buffer! Error code = " << result;
// Handle device lost error (e.g., after wake from sleep/hibernation) // Handle device lost error (e.g., after wake from sleep/hibernation)
if (result == VK_ERROR_DEVICE_LOST || result == -4) { if (result == VK_ERROR_DEVICE_LOST || result == -4) {
qDebug() << "VK_ERROR_DEVICE_LOST detected! Attempting to recover device..."; qDebug() << "VK_ERROR_DEVICE_LOST detected! Attempting to recover device...";
@ -957,7 +958,7 @@ void VulkanWidget::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t i
// Calculate elapsed time in seconds // Calculate elapsed time in seconds
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
qint64 elapsedTime = m_startTime.secsTo(now); qint64 elapsedTime = m_startTime.secsTo(now);
m_renderer->recordCommandBuffer(commandBuffer, imageIndex, imageView, m_renderer->recordCommandBuffer(commandBuffer, imageIndex, imageView,
m_frameCount, static_cast<double>(elapsedTime), m_frameCount, static_cast<double>(elapsedTime),
m_currentFps, m_currentFps,
@ -1083,7 +1084,7 @@ void VulkanWidget::cleanupVulkan()
if (m_surface != VK_NULL_HANDLE) { if (m_surface != VK_NULL_HANDLE) {
vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
} }
// Close X11 display if it was opened (Linux only) // Close X11 display if it was opened (Linux only)
#ifdef __linux__ #ifdef __linux__
if (m_x11Display) { if (m_x11Display) {
@ -1228,13 +1229,13 @@ std::vector<const char*> VulkanWidget::getRequiredDeviceExtensions()
bool VulkanWidget::handleDeviceLost() bool VulkanWidget::handleDeviceLost()
{ {
qDebug() << "=== Handling device lost error ==="; qDebug() << "=== Handling device lost error ===";
// Stop rendering timer to prevent more render attempts during recovery // Stop rendering timer to prevent more render attempts during recovery
if (m_renderTimer && m_renderTimer->isActive()) { if (m_renderTimer && m_renderTimer->isActive()) {
m_renderTimer->stop(); m_renderTimer->stop();
qDebug() << "Render timer stopped for device recovery"; qDebug() << "Render timer stopped for device recovery";
} }
// Wait for any pending operations to complete (may fail, but try anyway) // Wait for any pending operations to complete (may fail, but try anyway)
if (m_device != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE) {
VkResult result = vkDeviceWaitIdle(m_device); VkResult result = vkDeviceWaitIdle(m_device);
@ -1242,14 +1243,14 @@ bool VulkanWidget::handleDeviceLost()
qDebug() << "vkDeviceWaitIdle failed (expected with device lost), continuing recovery..."; qDebug() << "vkDeviceWaitIdle failed (expected with device lost), continuing recovery...";
} }
} }
// Attempt to recreate the device and all resources // Attempt to recreate the device and all resources
bool success = recreateDevice(); bool success = recreateDevice();
if (success) { if (success) {
m_deviceLost = false; m_deviceLost = false;
qDebug() << "Device recovery successful!"; qDebug() << "Device recovery successful!";
// Restart rendering timer if rendering was enabled // Restart rendering timer if rendering was enabled
if (m_renderingEnabled && m_renderTimer && !m_renderTimer->isActive()) { if (m_renderingEnabled && m_renderTimer && !m_renderTimer->isActive()) {
m_renderTimer->start(16); // ~60 FPS m_renderTimer->start(16); // ~60 FPS
@ -1258,21 +1259,21 @@ bool VulkanWidget::handleDeviceLost()
} else { } else {
qDebug() << "Device recovery failed!"; qDebug() << "Device recovery failed!";
} }
return success; return success;
} }
bool VulkanWidget::recreateDevice() bool VulkanWidget::recreateDevice()
{ {
qDebug() << "=== Recreating Vulkan device ==="; qDebug() << "=== Recreating Vulkan device ===";
// Clean up renderer first // Clean up renderer first
if (m_renderer) { if (m_renderer) {
delete m_renderer; delete m_renderer;
m_renderer = nullptr; m_renderer = nullptr;
qDebug() << "Renderer cleaned up"; qDebug() << "Renderer cleaned up";
} }
// Clean up sync objects // Clean up sync objects
if (m_device != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE) {
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
@ -1288,16 +1289,16 @@ bool VulkanWidget::recreateDevice()
} }
qDebug() << "Sync objects cleaned up"; qDebug() << "Sync objects cleaned up";
} }
m_renderFinishedSemaphores.clear(); m_renderFinishedSemaphores.clear();
m_imageAvailableSemaphores.clear(); m_imageAvailableSemaphores.clear();
m_inFlightFences.clear(); m_inFlightFences.clear();
// Clean up command objects // Clean up command objects
if (m_device != VK_NULL_HANDLE && m_commandPool != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE && m_commandPool != VK_NULL_HANDLE) {
if (!m_commandBuffers.empty()) { if (!m_commandBuffers.empty()) {
vkFreeCommandBuffers(m_device, m_commandPool, vkFreeCommandBuffers(m_device, m_commandPool,
static_cast<uint32_t>(m_commandBuffers.size()), static_cast<uint32_t>(m_commandBuffers.size()),
m_commandBuffers.data()); m_commandBuffers.data());
m_commandBuffers.clear(); m_commandBuffers.clear();
} }
@ -1305,10 +1306,10 @@ bool VulkanWidget::recreateDevice()
m_commandPool = VK_NULL_HANDLE; m_commandPool = VK_NULL_HANDLE;
qDebug() << "Command objects cleaned up"; qDebug() << "Command objects cleaned up";
} }
// Clean up swapchain // Clean up swapchain
cleanupSwapchain(); cleanupSwapchain();
// Destroy logical device // Destroy logical device
if (m_device != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE) {
vkDestroyDevice(m_device, nullptr); vkDestroyDevice(m_device, nullptr);
@ -1316,14 +1317,14 @@ bool VulkanWidget::recreateDevice()
m_queue = VK_NULL_HANDLE; m_queue = VK_NULL_HANDLE;
qDebug() << "Logical device destroyed"; qDebug() << "Logical device destroyed";
} }
// Destroy surface // Destroy surface
if (m_surface != VK_NULL_HANDLE) { if (m_surface != VK_NULL_HANDLE) {
vkDestroySurfaceKHR(m_instance, m_surface, nullptr); vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
m_surface = VK_NULL_HANDLE; m_surface = VK_NULL_HANDLE;
qDebug() << "Surface destroyed"; qDebug() << "Surface destroyed";
} }
// Close and reset X11 display (Linux only) - will be reopened when creating new surface // Close and reset X11 display (Linux only) - will be reopened when creating new surface
#ifdef __linux__ #ifdef __linux__
if (m_x11Display) { if (m_x11Display) {
@ -1332,21 +1333,21 @@ bool VulkanWidget::recreateDevice()
qDebug() << "X11 display closed for recreation"; qDebug() << "X11 display closed for recreation";
} }
#endif #endif
// Now recreate everything from surface onwards // Now recreate everything from surface onwards
// Important: Add a small delay to let the GPU driver fully reset // Important: Add a small delay to let the GPU driver fully reset
// This prevents VK_ERROR_SURFACE_LOST_KHR on some systems // This prevents VK_ERROR_SURFACE_LOST_KHR on some systems
qDebug() << "Waiting for GPU driver to stabilize..."; qDebug() << "Waiting for GPU driver to stabilize...";
QThread::msleep(200); // 200ms delay QThread::msleep(200); // 200ms delay
// Step 1: Recreate surface // Step 1: Recreate surface
if (!createSurface()) { if (!createSurface()) {
setError("Failed to recreate surface after device lost"); setError("Failed to recreate surface after device lost");
return false; return false;
} }
qDebug() << "Surface recreated"; qDebug() << "Surface recreated";
// Verify the physical device still supports this surface // Verify the physical device still supports this surface
VkBool32 surfaceSupported = VK_FALSE; VkBool32 surfaceSupported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, m_queueFamilyIndex, m_surface, &surfaceSupported); vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, m_queueFamilyIndex, m_surface, &surfaceSupported);
@ -1356,14 +1357,14 @@ bool VulkanWidget::recreateDevice()
return false; return false;
} }
qDebug() << "Surface support verified"; qDebug() << "Surface support verified";
// Step 2: Recreate logical device // Step 2: Recreate logical device
if (!createDevice()) { if (!createDevice()) {
setError("Failed to recreate device after device lost"); setError("Failed to recreate device after device lost");
return false; return false;
} }
qDebug() << "Logical device recreated"; qDebug() << "Logical device recreated";
// Step 3: Recreate swapchain // Step 3: Recreate swapchain
// Query surface capabilities again to ensure they're current // Query surface capabilities again to ensure they're current
VkSurfaceCapabilitiesKHR surfaceCaps; VkSurfaceCapabilitiesKHR surfaceCaps;
@ -1374,31 +1375,31 @@ bool VulkanWidget::recreateDevice()
return false; return false;
} }
qDebug() << "Surface capabilities validated"; qDebug() << "Surface capabilities validated";
if (!createSwapchain()) { if (!createSwapchain()) {
setError("Failed to recreate swapchain after device lost"); setError("Failed to recreate swapchain after device lost");
return false; return false;
} }
qDebug() << "Swapchain recreated"; qDebug() << "Swapchain recreated";
// Step 4: Recreate command objects // Step 4: Recreate command objects
if (!createCommandObjects()) { if (!createCommandObjects()) {
setError("Failed to recreate command objects after device lost"); setError("Failed to recreate command objects after device lost");
return false; return false;
} }
qDebug() << "Command objects recreated"; qDebug() << "Command objects recreated";
// Step 5: Recreate synchronization objects // Step 5: Recreate synchronization objects
if (!createSyncObjects()) { if (!createSyncObjects()) {
setError("Failed to recreate sync objects after device lost"); setError("Failed to recreate sync objects after device lost");
return false; return false;
} }
qDebug() << "Sync objects recreated"; qDebug() << "Sync objects recreated";
// Step 6: Recreate VulkanRenderer // Step 6: Recreate VulkanRenderer
if (m_surfaceWidth >= 100 && m_surfaceHeight >= 100) { if (m_surfaceWidth >= 100 && m_surfaceHeight >= 100) {
m_renderer = new VulkanRenderer(); m_renderer = new VulkanRenderer();
// Get swapchain format // Get swapchain format
VkSurfaceFormatKHR surfaceFormat; VkSurfaceFormatKHR surfaceFormat;
uint32_t formatCount = 0; uint32_t formatCount = 0;
@ -1408,7 +1409,7 @@ bool VulkanWidget::recreateDevice()
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data()); vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, formats.data());
surfaceFormat = formats[0]; surfaceFormat = formats[0];
} }
// Initialize renderer // Initialize renderer
if (!m_renderer->initialize(m_device, m_physicalDevice, if (!m_renderer->initialize(m_device, m_physicalDevice,
m_queue, m_queueFamilyIndex, m_queue, m_queueFamilyIndex,
@ -1419,13 +1420,13 @@ bool VulkanWidget::recreateDevice()
m_renderer = nullptr; m_renderer = nullptr;
return false; return false;
} }
qDebug() << "VulkanRenderer recreated successfully!"; qDebug() << "VulkanRenderer recreated successfully!";
} }
// Reset frame counter // Reset frame counter
m_currentFrame = 0; m_currentFrame = 0;
qDebug() << "=== Device recreation complete ==="; qDebug() << "=== Device recreation complete ===";
return true; return true;
} }

16
version.sh Normal file
View File

@ -0,0 +1,16 @@
#!/bin/bash
# Auto-generated version information from CMakeLists.txt
# DO NOT EDIT THIS FILE MANUALLY - Edit CMakeLists.txt instead
# This file is sourced by shell scripts to get version information
APP_VERSION_MAJOR=1
APP_VERSION_MINOR=3
APP_VERSION_PATCH=0
APP_VERSION="1.3.0"
# Export for use in other scripts
export APP_VERSION_MAJOR
export APP_VERSION_MINOR
export APP_VERSION_PATCH
export APP_VERSION

16
version.sh.in Normal file
View File

@ -0,0 +1,16 @@
#!/bin/bash
# Auto-generated version information from CMakeLists.txt
# DO NOT EDIT THIS FILE MANUALLY - Edit CMakeLists.txt instead
# This file is sourced by shell scripts to get version information
APP_VERSION_MAJOR=@PROJECT_VERSION_MAJOR@
APP_VERSION_MINOR=@PROJECT_VERSION_MINOR@
APP_VERSION_PATCH=@PROJECT_VERSION_PATCH@
APP_VERSION="@PROJECT_VERSION@"
# Export for use in other scripts
export APP_VERSION_MAJOR
export APP_VERSION_MINOR
export APP_VERSION_PATCH
export APP_VERSION