Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simple Qt example #9

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.20)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMake 3.20 required for the presets

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is aligned and serve as a example towards showing up a time-series of events.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meged it in my fork mm-s/DebugVision.git

project(DebugVision)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# may be enable later once we have a way to install them.
#set(Boost_USE_STATIC_LIBS ON)
Expand All @@ -10,26 +12,42 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
#find_package(GMock REQUIRED)
#find_package(fmt REQUIRED)

option(BUILD_WITH_ASAN "Build with address sanitizer" ON)
option(BUILD_WITH_UBSAN "Build with undefined behaviour sanitizer" ON)
option(BUILD_WITH_ASAN "Build with address sanitizer" OFF)
option(BUILD_WITH_UBSAN "Build with undefined behaviour sanitizer" OFF)
option(BUILD_WITH_TSAN "Build with address sanitizer" OFF)

add_compile_options(-Wall -Wextra -pedantic -Wmissing-include-dirs -Wformat=2 -Wunused -Wno-error=unused-variable -Wcast-align -Wno-vla -Wnull-dereference -Wmaybe-uninitialized)
add_compile_options(-Werror -fdiagnostics-color=auto)

if(BUILD_WITH_ASAN)
add_compile_options(-fsanitize=address)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
endif(BUILD_WITH_ASAN)

if(BUILD_WITH_UBSAN)
add_compile_options(-fsanitize=undefined)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
endif(BUILD_WITH_UBSAN)

if(BUILD_WITH_TSAN)
add_compile_options(-fsanitize=thread)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
endif(BUILD_WITH_TSAN)
# Qt
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Concurrent REQUIRED)
message("QT_VERSION=${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}")

if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_options(/W4 /external:W3 /WX /permissive-)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /GL /Ox")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
if (QT_VERSION_MAJOR EQUAL 5)
# with Qt5, setting /external:W3 is not enough to get rid of all warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd5054")
endif()
else()
add_compile_options(-Wall -Wextra -pedantic -Wmissing-include-dirs -Wformat=2 -Wunused -Wno-error=unused-variable -Wcast-align -Wno-vla -Wnull-dereference -Wmaybe-uninitialized)
add_compile_options(-Werror -fdiagnostics-color=auto)

if(BUILD_WITH_ASAN)
add_compile_options(-fsanitize=address)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
endif(BUILD_WITH_ASAN)

if(BUILD_WITH_UBSAN)
add_compile_options(-fsanitize=undefined)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
endif(BUILD_WITH_UBSAN)

if(BUILD_WITH_TSAN)
add_compile_options(-fsanitize=thread)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
endif(BUILD_WITH_TSAN)
endif()

add_subdirectory(tools)
42 changes: 42 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"version": 2,
"configurePresets": [
{
"name": "base-preset",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/${presetName}/install"
}
},
{
"name": "debug",
"inherits": "base-preset",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"inherits": "base-preset",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "visual-studio",
"inherits": "base-preset",
"generator": "Visual Studio 16 2019",
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;RelWithDebInfo"
}
}
],
"buildPresets": [
{
"name": "release",
"configurePreset": "release"
}
]
}
11 changes: 6 additions & 5 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rm -rf build/release
mkdir -p build/release
cd build/release
cmake -G Ninja ../.. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install
ninja
#/bin/bash
set -eu

rm -rf build/release
cmake --preset="release"
cmake --build --preset="release"
cmake --build --preset="release" --target install
41 changes: 41 additions & 0 deletions launch-msvc.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@echo off
REM script to be used on Windows to generate and open a VC++ solution

REM where to put the build files
set BUILDDIR=%~dp0build

REM the VC++ solution file
set SLNFILE=%BUILDDIR%\visual-studio\DebugVision.sln

REM make Qt visible
set QTDIR=C:\Qt\6.2.2\msvc2019_64
if not exist %QTDIR% (echo invalid Qt bin path: "%QTDIR%" && GOTO:FAILURE)
set PATH=%QTDIR%\bin;%PATH%

REM find VC++
set "VCPATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community"
if not exist "%VCPATH%" (
set "VCPATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional"
)

REM generate build files if not already done
if not exist %SLNFILE% (
REM make VC++ & cmake visible
REM make sure to install "C++ CMake tools for Windows" in VS installer
call "%VCPATH%\VC\Auxiliary\Build\vcvars64.bat" || GOTO:FAILURE

if exist %BUILDDIR% rmdir /s/q %BUILDDIR%
mkdir %BUILDDIR% || GOTO:FAILURE
compact /c /q %BUILDDIR% > nul
cmake --preset="visual-studio" || GOTO:FAILURE
)

REM open the VC++ solution
start %SLNFILE%

REM success!
GOTO:EOF

:FAILURE
echo Failure!
pause
16 changes: 16 additions & 0 deletions scripts/install_recent_cmake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
# script to install a recent cmake version in CI build env

set -eu

CMAKEVER=3.22.1
curl -sL https://github.com/Kitware/CMake/releases/download/v${CMAKEVER}/cmake-${CMAKEVER}-linux-x86_64.tar.gz -o cmake.tar.gz
tar xzf cmake.tar.gz
ls -l
mv cmake-${CMAKEVER}-linux-x86_64 /opt/cmake
ln -s /opt/cmake/bin/cmake /usr/bin/cmake
ln -s /opt/cmake/bin/ctest /usr/bin/ctest
ln -s /opt/cmake/bin/cpack /usr/bin/cpack
rm cmake.tar.gz

cmake -version
1 change: 1 addition & 0 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
add_subdirectory(debug.vision.application)
add_subdirectory(qt.demoapp)
104 changes: 104 additions & 0 deletions tools/qt.demoapp/AsyncFileScanner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "AsyncFileScanner.h"

#include <QDirIterator>
#include <QtConcurrent>

AsyncFileScanner::AsyncFileScanner()
{
qDebug() << __func__;
connect(&m_futureWatcher, &QFutureWatcher<void>::started, this, &AsyncFileScanner::scanStarted);
connect(&m_futureWatcher, &QFutureWatcher<void>::finished, this, &AsyncFileScanner::scanFinished);
}

AsyncFileScanner::~AsyncFileScanner()
{
qDebug() << __func__;
stop();
}

void AsyncFileScanner::startFolderScan(const QString& rootDir)
{
qDebug() << __func__;
if (isScanInProgress())
{
qWarning() << "can't start a new file scanning: another scan is already in progress";
return;
}

m_future = QtConcurrent::run([this, rootDir] {
qDebug() << "async file scanner started";
const QStringList files = performFileSearchStage(rootDir, {"*.log", "log*.txt"});
if (!m_future.isCanceled())
{
performFileReadStage(files);
}
qDebug() << "async file scanner ended";
});
m_futureWatcher.setFuture(m_future);
}

void AsyncFileScanner::stop()
{
qDebug() << __func__;
if (m_future.isRunning())
{
qDebug() << "stopping async file scanner...";
m_future.cancel();
m_future.waitForFinished();
}
}

QStringList AsyncFileScanner::performFileSearchStage(const QString& rootDir, const QStringList& patterns)
{
Q_ASSERT(m_future.isRunning()); // we expect to run as an async task

qDebug() << "searching for files of kind" << patterns;
QStringList result;
result.reserve(1'000);

QDirIterator it(rootDir, patterns, QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext())
{
if (m_future.isCanceled())
{
qDebug() << "file search was canceled";
break;
}

QString filePath = it.next();
result += filePath;
emit foundNewFile(rootDir, filePath);
}

qDebug() << "end of file search, number of file found:" << result.size();
return result;
}

static int countTextLinesInFile(const QString& filePath)
{
QFile file{filePath};
if (!file.open(QIODevice::ReadOnly))
{
qCritical() << "failed to read file" << filePath;
return 0;
}

QTextStream stream(&file);
const QString text = stream.readAll();
return text.isEmpty() ? 0 : 1 + text.count(QLatin1Char('\n'));
}

void AsyncFileScanner::performFileReadStage(const QStringList& files)
{
qDebug() << "starting to read file content";
for (const QString& filePath : files)
{
if (m_future.isCanceled())
{
qDebug() << "reading file content was canceled";
break;
}

emit countedFileLineNumbers(filePath, countTextLinesInFile(filePath));
}
}
34 changes: 34 additions & 0 deletions tools/qt.demoapp/AsyncFileScanner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

// Type used to scan folders for log files via a background task
class AsyncFileScanner : public QObject
{
Q_OBJECT
signals:
void scanStarted();
void scanFinished();
void foundNewFile(QString rootDir, QString filePath);
void countedFileLineNumbers(QString filePath, int lineCount);

public:
AsyncFileScanner();
~AsyncFileScanner();

[[nodiscard]] bool isScanInProgress() const
{
return m_future.isRunning();
}

void startFolderScan(const QString& rootDir);

void stop();

private:
QStringList performFileSearchStage(const QString& rootDir, const QStringList& patterns);
void performFileReadStage(const QStringList& files);

private:
bool m_isScanning = false;
QFuture<void> m_future;
QFutureWatcher<void> m_futureWatcher;
};
23 changes: 23 additions & 0 deletions tools/qt.demoapp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

add_executable(qt.demoapp
AsyncFileScanner.cpp
AsyncFileScanner.h
main.cpp
MainWindow.cpp
MainWindow.h
WidgetFileTextViewer.cpp
WidgetFileTextViewer.h
WidgetFileTreeView.cpp
WidgetFileTreeView.h
# special files
pch.h
images/images.qrc
)
target_precompile_headers(qt.demoapp PRIVATE pch.h)
target_link_libraries(qt.demoapp PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Concurrent)
set_target_properties(qt.demoapp PROPERTIES AUTOMOC ON AUTORCC ON)

if (WIN32)
# display the Win32 console only for debug builds
set_target_properties(qt.demoapp PROPERTIES WIN32_EXECUTABLE $<IF:$<CONFIG:Debug>,FALSE,TRUE>)
endif()
Loading