From 163b93cd885f8a9e21b64a0c459a2c7c2972db9d Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Sat, 7 Sep 2024 19:39:05 -0500 Subject: [PATCH 1/2] Add working example and fix README for CMake. --- README.md | 49 +++++++++++++++++++----------------- example/cmake/CMakeLists.txt | 14 +++++++++++ example/cmake/breeze.cmake | 43 +++++++++++++++++++++++++++++++ example/cmake/test_qt.cpp | 20 +++++++++++++++ 4 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 example/cmake/CMakeLists.txt create mode 100644 example/cmake/breeze.cmake create mode 100644 example/cmake/test_qt.cpp diff --git a/README.md b/README.md index 55b054c..3ea6949 100644 --- a/README.md +++ b/README.md @@ -252,21 +252,18 @@ All generated themes will be in the [dist](/dist) subdirectory, and the compiled ## CMake Installation -Using CMake, you can download, configure, and compile the resources as part part of the build process. The following configurations are provided by @ruilvo. First, save the following as `BreezeThemes.cmake` +Using CMake, you can download, configure, and compile the resources as part part of the build process. The following configurations are provided by @ruilvo. You can see a full example in [example](/example/cmake/). First, save the following as `breeze.cmake`. ```cmake # Setup Qt: this works with both Qt5 and Qt6 +# NOTE: We use cached strings to specify the options for these. set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) find_package( - QT NAMES Qt6 Qt5 - COMPONENTS Core - REQUIRED) -find_package( - Qt${QT_VERSION_MAJOR} - COMPONENTS ${AE_REQUIRED_QT_COMPONENTS} + ${QT_VERSION} + COMPONENTS Core Gui Widgets REQUIRED) # ------------------- @@ -276,9 +273,7 @@ find_package(Python COMPONENTS Interpreter) include(FetchContent) -set(FETCHCONTENT_QUIET - OFF - CACHE BOOL "Silence fetch content" FORCE) +set(FETCHCONTENT_QUIET OFF CACHE BOOL "Silence fetch content" FORCE) FetchContent_Declare( breeze_stylesheets @@ -291,46 +286,55 @@ FetchContent_GetProperties(breeze_stylesheets) if(NOT breeze_stylesheets_POPULATED) FetchContent_Populate(breeze_stylesheets) - add_library(breeze_themes STATIC "${breeze_stylesheets_SOURCE_DIR}/dist/breeze.qrc") + add_library(breeze STATIC "${breeze_stylesheets_SOURCE_DIR}/dist/breeze.qrc") add_custom_target( run_python_breeze ALL - COMMAND ${Python_EXECUTABLE} configure.py --extensions= - --styles= --resource breeze.qrc + COMMAND ${Python_EXECUTABLE} configure.py --extensions=${BREEZE_EXTENSIONS} + --styles=${BREEZE_STYLES} --resource breeze.qrc WORKING_DIRECTORY ${breeze_stylesheets_SOURCE_DIR} BYPRODUCTS "${breeze_stylesheets_SOURCE_DIR}/dist/breeze.qrc" COMMENT "Generating themes") - add_dependencies(breeze_themes run_python_breeze) + add_dependencies(breeze run_python_breeze) endif() ``` -Next, make sure the path to `breeze_themes.cmake` is in your module search [path](https://cgold.readthedocs.io/en/latest/tutorials/cmake-sources/includes.html), and add the following to your CMakeLists.txt: +Next, make sure the path to `breeze.cmake` is in your module search [path](https://cgold.readthedocs.io/en/latest/tutorials/cmake-sources/includes.html), and add the following to your CMakeLists.txt: ```cmake -include(BreezeThemes) +set(QT_VERSION Qt5 CACHE STRING "The Qt version framework to use (Qt5 or Qt6).") +set(BREEZE_EXTENSIONS all CACHE STRING "The extensions to include in our stylesheets.") +set(BREEZE_STYLES all CACHE STRING "The styles to include in our stylesheets.") + +include(breeze) add_executable(myapp WIN32 MACOSX_BUNDLE "main.cpp") -target_link_libraries(myapp PRIVATE Qt${QT_VERSION_MAJOR}::Widgets breeze_themes) +target_link_libraries(myapp PRIVATE Qt${QT_VERSION_MAJOR}::Widgets breeze) ``` And then in your application start point, add the following: ```cpp -int main() +#include +#include +#include + +int main(int argc, char *argv[]) { - // ... QApplication app(argc, argv); // Need to initialize the resource, since we're using an external // build system and this isn't automatically handled by CMake. - Q_INIT_RESOURCE(breeze_themes); - QFile file(":/dark-green/stylesheet.qss"); + Q_INIT_RESOURCE(breeze); + QFile file(":/dark/stylesheet.qss"); file.open(QFile::ReadOnly | QFile::Text); QTextStream stream(&file); app.setStyleSheet(stream.readAll()); - // ... + // code goes here + + return app.exec(); } ``` @@ -349,7 +353,6 @@ RESOURCES = breeze.qrc To load the stylesheet in C++, load the file using QFile and read the data. For example, to load BreezeDark, run: ```cpp - #include #include #include diff --git a/example/cmake/CMakeLists.txt b/example/cmake/CMakeLists.txt new file mode 100644 index 0000000..83a0bd3 --- /dev/null +++ b/example/cmake/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.13) +cmake_policy(SET CMP0128 NEW) + +project(testing) +set(CMAKE_CXX_STANDARD 17) + +set(QT_VERSION Qt5 CACHE STRING "The Qt version framework to use (Qt5 or Qt6).") +set(BREEZE_EXTENSIONS all CACHE STRING "The extensions to include in our stylesheets.") +set(BREEZE_STYLES all CACHE STRING "The styles to include in our stylesheets.") + +include(${CMAKE_CURRENT_SOURCE_DIR}/breeze.cmake) +set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/test_qt.cpp) +add_executable(testing ${SOURCE_FILES}) +target_link_libraries(testing PRIVATE Qt${QT_VERSION_MAJOR}::Widgets breeze) diff --git a/example/cmake/breeze.cmake b/example/cmake/breeze.cmake new file mode 100644 index 0000000..0fa23d7 --- /dev/null +++ b/example/cmake/breeze.cmake @@ -0,0 +1,43 @@ +# Setup Qt: this works with both Qt5 and Qt6 +# NOTE: We use cached strings to specify the options for these. +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +find_package( + ${QT_VERSION} + COMPONENTS Core Gui Widgets + REQUIRED) +# ------------------- + +# Get Python to compile the stylesheets. +# Fetch the repository, configure, compile the stylesheets. +find_package(Python COMPONENTS Interpreter) + +include(FetchContent) + +set(FETCHCONTENT_QUIET OFF CACHE BOOL "Silence fetch content" FORCE) + +FetchContent_Declare( + breeze_stylesheets + GIT_REPOSITORY https://github.com/Alexhuszagh/BreezeStyleSheets.git + GIT_TAG origin/main + GIT_PROGRESS ON + USES_TERMINAL_DOWNLOAD TRUE) + +FetchContent_GetProperties(breeze_stylesheets) +if(NOT breeze_stylesheets_POPULATED) + FetchContent_Populate(breeze_stylesheets) + + add_library(breeze STATIC "${breeze_stylesheets_SOURCE_DIR}/dist/breeze.qrc") + + add_custom_target( + run_python_breeze ALL + COMMAND ${Python_EXECUTABLE} configure.py --extensions=${BREEZE_EXTENSIONS} + --styles=${BREEZE_STYLES} --resource breeze.qrc + WORKING_DIRECTORY ${breeze_stylesheets_SOURCE_DIR} + BYPRODUCTS "${breeze_stylesheets_SOURCE_DIR}/dist/breeze.qrc" + COMMENT "Generating themes") + + add_dependencies(breeze run_python_breeze) +endif() diff --git a/example/cmake/test_qt.cpp b/example/cmake/test_qt.cpp new file mode 100644 index 0000000..8523eef --- /dev/null +++ b/example/cmake/test_qt.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + // Need to initialize the resource, since we're using an external + // build system and this isn't automatically handled by CMake. + Q_INIT_RESOURCE(breeze); + QFile file(":/dark/stylesheet.qss"); + file.open(QFile::ReadOnly | QFile::Text); + QTextStream stream(&file); + app.setStyleSheet(stream.readAll()); + + // code goes here + + return app.exec(); +} From ecf241f6efe64e357d316b92b1dfade4298c250a Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Sat, 7 Sep 2024 20:03:18 -0500 Subject: [PATCH 2/2] Add CI for CMake. --- .github/workflows/cmake.yml | 22 ++++++++++++++++++ scripts/cmake.sh | 46 +++++++++++++++++++++++++++++++++++++ scripts/headless.sh | 10 ++++++++ 3 files changed, 78 insertions(+) create mode 100644 .github/workflows/cmake.yml create mode 100755 scripts/cmake.sh diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000..c0e788e --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,22 @@ +name: CMake + +on: [push, pull_request] + +jobs: + cmake: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install xvfb + sudo apt-get install build-essential libgl1-mesa-dev libgstreamer-gl1.0-0 libpulse-dev \ + libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \ + libxcb-render0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 \ + libxcb-xinerama0 libxcb1 libxkbcommon-dev libxkbcommon-x11-0 libxcb-xkb-dev cmake + sudo apt install qt6-base-dev qtbase5-dev + - name: Running our CMake flow. + run: | + scripts/cmake.sh diff --git a/scripts/cmake.sh b/scripts/cmake.sh new file mode 100755 index 0000000..79b3933 --- /dev/null +++ b/scripts/cmake.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# Run custom CMake build script which auto-downloads, +# builds, and then uses the compiled code in an application. +# sudo apt-get update +# sudo apt-get install xvfb +# sudo apt-get install build-essential libgl1-mesa-dev libgstreamer-gl1.0-0 libpulse-dev \ +# libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \ +# libxcb-render0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 \ +# libxcb-xinerama0 libxcb1 libxkbcommon-dev libxkbcommon-x11-0 libxcb-xkb-dev cmake +# sudo apt install qt6-base-dev qtbase5-dev + +set -eux pipefail + +scripts_home="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" +project_home="$(dirname "${scripts_home}")" +build_dir="${project_home}/dist/build" + +mkdir -p "${build_dir}/"{qt5,qt6} + +# we xcb installed for our headless running, so exit if we don't have it +if ! hash xvfb-run &>/dev/null; then + >&2 echo "Do not have xvfb installed..." + exit 1 +fi + +# first, try Qt5 +# NOTE: Since we're using `-e`, we need to specially +# capture the error code immediately. +export QT_QPA_PLATFORM=offscreen +cd "${build_dir}/qt5" +cmake "${project_home}/example/cmake" -D QT_VERSION=Qt5 +make -j +timeout 1 xvfb-run -a ./testing || error_code=$? +if [[ "${error_code}" != 124 ]]; then + exit "${error_code}" +fi + +# first, try Qt6 +cd "${build_dir}/qt6" +cmake "${project_home}/example/cmake" -D QT_VERSION=Qt6 +make -j +timeout 1 xvfb-run -a ./testing || error_code=$? +if [[ "${error_code}" != 124 ]]; then + exit "${error_code}" +fi diff --git a/scripts/headless.sh b/scripts/headless.sh index 1c8dd37..35b10d6 100755 --- a/scripts/headless.sh +++ b/scripts/headless.sh @@ -8,6 +8,16 @@ # - PySide6 # And if using Python 3.10 or earlier: # - PySide2 +# +# On Ubuntu, this requires the following install logic: +# python -m pip install --upgrade pip +# pip install PySide2 PySide6 PyQt5 PyQt6 +# sudo apt-get update +# sudo apt-get install xvfb +# sudo apt-get install build-essential libgl1-mesa-dev libgstreamer-gl1.0-0 libpulse-dev \ +# libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \ +# libxcb-render0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 \ +# libxcb-xinerama0 libxcb1 libxkbcommon-dev libxkbcommon-x11-0 libxcb-xkb-dev set -eux pipefail