From f14b04157a9cacaf60f815f164939cc42dad04da Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 2 Sep 2021 19:42:24 +0200 Subject: Require CMake 3.16; drop qmake; use C++20 and newer compilers Also, refresh the documentation a bit. --- CMakeLists.txt | 30 +++++++------- CONTRIBUTING.md | 2 +- README.md | 125 +++++++++++++++++++++++++------------------------------- 3 files changed, 72 insertions(+), 85 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62fa43de..c0a39932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.16) if (POLICY CMP0092) cmake_policy(SET CMP0092 NEW) endif() @@ -207,15 +207,14 @@ if (API_GENERATION_ENABLED) message( STATUS "${CLANG_FORMAT} is NOT FOUND; API files won't be reformatted") endif () - if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.12.0") - # We use globbing with CONFIGURE_DEPENDS to produce two file lists: - # one of all API files for clang-format and another of just .cpp - # files to supply for library source files. Since we expect these - # file lists to only change due to GTAD invocation, we only use - # CONFIGURE_DEPENDS when pre-requisites to update API are met. - # Read comments next to each file(GLOB_RECURSE) for caveats. - set(add_CONFIGURE_DEPENDS "CONFIGURE_DEPENDS") - endif() + # We use globbing with CONFIGURE_DEPENDS to produce two file lists: + # one of all API files for clang-format and another of just .cpp + # files to supply for library source files. Since we expect these + # file lists to only change due to GTAD invocation, we only use + # CONFIGURE_DEPENDS when pre-requisites to update API are met. + # Read comments next to each file(GLOB_RECURSE) for caveats. + set(add_CONFIGURE_DEPENDS "CONFIGURE_DEPENDS") + set(FULL_CSAPI_SRC_DIR ${ABS_API_DEF_PATH}/client-server) file(GLOB_RECURSE API_DEFS RELATIVE ${PROJECT_SOURCE_DIR} ${FULL_CSAPI_SRC_DIR}/*.yaml @@ -280,14 +279,12 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE QT_NO_JAVA_STYLE_ITERATORS QT target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} ${PROJECT_NAME}_VERSION_MINOR=${PROJECT_VERSION_MINOR} ${PROJECT_NAME}_VERSION_PATCH=${PROJECT_VERSION_PATCH} ${PROJECT_NAME}_VERSION_STRING=\"${PROJECT_VERSION}\") -if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" - AND NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 - target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) -endif () if (${PROJECT_NAME}_ENABLE_E2EE) target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_E2EE_ENABLED) endif() set_target_properties(${PROJECT_NAME} PROPERTIES + CXX_STANDARD 20 + CXX_EXTENSIONS OFF VERSION "${PROJECT_VERSION}" SOVERSION ${API_VERSION} INTERFACE_${PROJECT_NAME}_MAJOR_VERSION ${API_VERSION} @@ -295,8 +292,13 @@ set_target_properties(${PROJECT_NAME} PROPERTIES set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY COMPATIBLE_INTERFACE_STRING ${PROJECT_NAME}_MAJOR_VERSION) +# C++17 required, C++20 desired (see above) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) +if (NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 + target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) +endif () + target_include_directories(${PROJECT_NAME} PUBLIC $ $ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4fdab602..c9296df1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -408,7 +408,7 @@ I (Kitsune) will be very glad to help you out. The types map in `gtad.yaml` is the central switchboard when it comes to matching OpenAPI types with C++ (and Qt) ones. It uses the following type attributes aside from pretty obvious "imports:": * `avoidCopy` - this attribute defines whether a const ref should be used instead of a value. For basic types like int this is obviously unnecessary; but compound types like `QVector` should rather be taken by reference when possible. * `moveOnly` - some types are not copyable at all and must be moved instead (an obvious example is anything "tainted" with a member of type `std::unique_ptr<>`). The template will use `T&&` instead of `T` or `const T&` to pass such types around. -* `useOmittable` - wrap types that have no value with "null" semantics (i.e. number types and custom-defined data structures) into a special `Omittable<>` template defined in `converters.h` - a substitute for `std::optional` from C++17 (we're still at C++14 yet). +* `useOmittable` - wrap types that have no value with "null" semantics (i.e. number types and custom-defined data structures) into a special `Omittable<>` template defined in `converters.h`, a drop-in upgrade over `std::optional`. * `omittedValue` - an alternative for `useOmittable`, just provide a value used for an omitted parameter. This is used for bool parameters which normally are considered false if omitted (or they have an explicit default value, passed in the "official" GTAD's `defaultValue` variable). * `initializer` - this is a _partial_ (see GTAD and Mustache documentation for explanations but basically it's a variable that is a Mustache template itself) that specifies how exactly a default value should be passed to the parameter. E.g., the default value for a `QString` parameter is enclosed into `QStringLiteral`. diff --git a/README.md b/README.md index 05c629f2..71f2d04c 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,7 @@ The Quotient project aims to produce a Qt5-based SDK to develop applications for [Matrix](https://matrix.org). libQuotient is a library that enables client applications. It is the backbone of [Quaternion](https://github.com/quotient-im/Quaternion), -[Spectral](https://matrix.org/docs/projects/client/spectral.html) and -other projects. +[NeoChat](https://matrix.org/docs/projects/client/neo-chat) and other projects. Versions 0.5.x and older use the previous name - libQMatrixClient. ## Contacts @@ -38,61 +37,62 @@ and bundle it with your application. ### Pre-requisites - A recent Linux, macOS or Windows system (desktop versions are known to work; mobile operating systems where Qt is available might work too) - - Recent enough Linux examples: Debian Buster; Fedora 28; openSUSE Leap 15; - Ubuntu Bionic Beaver. -- Qt 5 (either Open Source or Commercial), 5.9 or higher; - 5.12 is recommended, especially if you use qmake -- A build configuration tool (CMake is recommended, qmake is supported): - - CMake 3.10 or newer (from your package management system or - [the official website](https://cmake.org/download/)) - - or qmake (comes with Qt) -- A C++ toolchain with _reasonably complete_ C++17 support: - - GCC 7 (Windows, Linux, macOS), Clang 6 (Linux), Apple Clang 10 (macOS) - and Visual Studio 2017 (Windows) are the oldest officially supported. -- Any build system that works with CMake and/or qmake should be fine: - GNU Make, ninja (any platform), NMake, jom (Windows) are known to work. + - Recent enough Linux examples: Debian Bullseye; Fedora 33; openSUSE Leap 15.3; + Ubuntu Focal Fossa. +- Qt 5 (either Open Source or Commercial), 5.12 or higher +- CMake 3.16 or newer (from your package management system or + [the official website](https://cmake.org/download/)) +- A C++ toolchain with complete (as much as possible) C++17 and basic C++20: + - GCC 10 (Windows, Linux, macOS), Clang 11 (Linux), Apple Clang 12 (macOS) + and Visual Studio 2019 (Windows) are the oldest officially supported. +- Any build system that works with CMake should be fine: + GNU Make and ninja on any platform, NMake and jom on Windows are known to work. + Ninja is recommended. #### Linux -Just install things from the list above using your preferred package manager. If your Qt package base is fine-grained you might want to run cmake/qmake and look at error messages. The library is entirely offscreen (QtCore and QtNetwork are essential) but it also depends on QtGui in order to handle avatar thumbnails. +Just install things from the list above using your preferred package manager. +If your Qt package base is fine-grained you might want to run cmake and look +at error messages. The library is entirely offscreen but aside from QtCore and +QtNetwork it also depends on QtGui in order to handle avatar thumbnails. #### macOS -`brew install qt5` should get you a recent Qt5. If you plan to use CMake, you will need to tell it about the path to Qt by passing `-DCMAKE_PREFIX_PATH=$(brew --prefix qt5)` +`brew install qt5` should get you a recent Qt5. You may need to pass +`-DCMAKE_PREFIX_PATH=$(brew --prefix qt5)` to make it aware of the Qt location. #### Windows -Install Qt5, using their official installer; if you plan to build with CMake, -make sure to tick the CMake box in the list of installed components. - -The commands in further sections imply that cmake/qmake is in your PATH, -otherwise you have to prepend those commands with actual paths. As an option -it's a good idea to run a `qtenv2.bat` script that can be found in -`C:\Qt\\\bin` (assuming you installed Qt to `C:\Qt`); -the only thing it does is adding necessary paths to PATH. You might not want -to run that script on system startup but it's very handy to setup -the environment before building. For CMake you can alternatively point -`CMAKE_PREFIX_PATH` to your Qt installation and leave PATH unchanged; but -in that case you'll have to supply the full path to CMake when calling it. +Install Qt5 using their official installer; make sure to tick the CMake box +in the list of installed components unless you already have it installed. + +The commands in further sections imply that cmake is in your PATH, otherwise +you have to prepend those commands with actual paths. It's a good idea to run +a `qtenv2.bat` script that can be found in `C:\Qt\\\bin` +(assuming you installed Qt to `C:\Qt`) if you're building from the command line; +the script adds necessary paths to PATH. You might not want to run that script +on system startup but it's very handy to setup the environment before building. +Alternatively you can add the Qt path to `CMAKE_PREFIX_PATH` and leave PATH +unchanged. ### Using the library -If you use CMake, `find_package(Quotient)` sets up the client code to use -libQuotient, assuming the library development files are installed. There's no -documented procedure to use a preinstalled library with qmake; consider -introducing a submodule in your source tree and build it along with the rest -of the application for now. Note also that qmake is considered for phase-out -in Qt 6 so you should probably think of moving over to CMake eventually. +If you're just starting a project using libQuotient from scratch, you can copy +`quotest/CMakeLists.txt` to your project and change `quotest` to your +project name. If you already have an existing CMakeLists.txt, you need to insert +a `find_package(Quotient REQUIRED)` line to an appropriate place in it (use +`find_package(Quotient)` if libQuotient is not a hard dependency for you) and +then add `Quotient` to your `target_link_libraries()` line. Building with dynamic linkage is only tested on Linux at the moment and is a recommended way of linking your application with libQuotient on this platform. Static linkage is the default on Windows/macOS; feel free to experiment with dynamic linking and submit PRs if you get reusable results. -[Quotest](quotest), the test application that comes with libQuotient, includes -most common use cases such as sending messages, uploading files, -setting room state etc.; for more extensive usage check out the source code -of [Quaternion](https://github.com/quotient-im/Quaternion) -(the reference client of Quotient) or [Spectral](https://gitlab.com/b0/spectral). - -To ease the first step, `quotest/CMakeLists.txt` is a good starting point -for your own CMake-based project using libQuotient. +As for the actual API usage, a (very basic) overview can be found at +[the respective wiki page](https://github.com/quotient-im/libQuotient/wiki/libQuotient-overview). +Beyond that, looking at [Quotest](quotest) - the test application that comes +with libQuotient - may help you with most common use cases such as sending +messages, uploading files, setting room state etc. For more extensive usage +feel free to check out (and copy, with appropriate attribution) the source code +of [Quaternion](https://github.com/quotient-im/Quaternion) (the reference client +for libQuotient) or [NeoChat](https://invent.kde.org/network/neochat). ## Building the library [The source code is at GitHub](https://github.com/quotient-im/libQuotient). @@ -101,28 +101,29 @@ along with submodules is strongly recommended. If you want to hack on the library as a part of another project (e.g. you are working on Quaternion but need to do some changes to the library code), it makes sense to make a recursive check out of that project (in this case, Quaternion) -and update the library submodule (also recursively) to its master branch. +and update the library submodule (also recursively) within the appropriate +branch. Be mindful of API compatibility restrictions: e.g., Quaternion 0.0.95 +will not build with the master branch of libQuotient. Tags consisting of digits and periods represent released versions; tags ending with `-betaN` or `-rcN` mark pre-releases. If/when packaging pre-releases, it is advised to replace a dash with a tilde. -### CMake-based -In the root directory of the project sources: +The following commands issued in the root directory of the project sources: ```shell script mkdir build_dir cd build_dir cmake .. # [-D=...], see below cmake --build . --target all ``` -This will get you the compiled library in `build_dir` inside your project -sources. Static builds are tested on all supported platforms, building -the library as a shared object (aka dynamic library) is supported on Linux -and macOS but is very likely to be broken on Windows. - -The first CMake invocation configures the build. You can pass CMake variables, -such as `-DCMAKE_PREFIX_PATH="path1;path2;..."` and -`-DCMAKE_INSTALL_PREFIX=path` here if needed. +will get you a compiled library in `build_dir` inside your project sources. +Static builds are tested on all supported platforms, building the library as +a shared object (aka dynamic library) is supported on Linux and macOS but is +very likely to be broken on Windows. + +The first CMake invocation above configures the build. You can pass CMake +variables (such as `-DCMAKE_PREFIX_PATH="path1;path2;..."` and +`-DCMAKE_INSTALL_PREFIX=path`) here if needed. [CMake documentation](https://cmake.org/cmake/help/latest/index.html) (pick the CMake version at the top of the page that you use) describes the standard variables coming with CMake. On top of them, Quotient introduces: @@ -160,22 +161,6 @@ with the _installed_ library. Installation of the `quotest` binary along with the rest of the library can be skipped by setting `Quotient_INSTALL_TESTS` to `OFF`. -### qmake-based -The library provides a .pri file with an intention to be included from a bigger project's .pro file. As a starting point you can use `quotest.pro` that will build a minimal example of library usage for you. In the root directory of the project sources: -```shell script -qmake quotest.pro -make all -``` -This will get you `debug/quotest` and `release/quotest` -console executables that login to the Matrix server at matrix.org with -credentials of your choosing (pass the username and password as arguments), -run a sync long-polling loop and do some tests of the library API. Note that -qmake didn't really know about C++17 until Qt 5.12 so if your Qt is older -you may have quite a bit of warnings during the compilation process. - -Installing the standalone library with qmake is not implemented yet; PRs are -welcome though. - ## Troubleshooting #### Building fails -- cgit v1.2.3 From ee678fac0ee09c6262c7a39b2b1072660e6db9ca Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 2 Sep 2021 22:18:14 +0200 Subject: CI experiment: requires GCC 10 and Clang 11 --- .github/workflows/ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 670153eb..47e31d55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,16 +72,17 @@ jobs: - name: Setup build environment run: | if [ "${{ matrix.compiler }}" == "GCC" ]; then - if [ -n "${{ matrix.update-api }}" ]; then VERSION_POSTFIX='-9'; fi - echo "CC=gcc$VERSION_POSTFIX" >>$GITHUB_ENV - echo "CXX=g++$VERSION_POSTFIX" >>$GITHUB_ENV + CXX_VERSION_POSTFIX='-10' + echo "CC=gcc$CXX_VERSION_POSTFIX" >>$GITHUB_ENV + echo "CXX=g++$CXX_VERSION_POSTFIX" >>$GITHUB_ENV elif [[ '${{ matrix.compiler }}' == 'Clang' ]]; then - echo "CC=clang" >>$GITHUB_ENV - echo "CXX=clang++" >>$GITHUB_ENV if [[ '${{ runner.os }}' == 'Linux' ]]; then + CXX_VERSION_POSTFIX='-11' # Do CodeQL analysis on one of Linux branches echo "CODEQL_ANALYSIS=true" >>$GITHUB_ENV fi + echo "CC=clang$CXX_VERSION_POSTFIX" >>$GITHUB_ENV + echo "CXX=clang++$CXX_VERSION_POSTFIX" >>$GITHUB_ENV fi if grep -q 'refs/tags' <<<'${{ github.ref }}'; then VERSION="$(git describe --tags)" -- cgit v1.2.3 From 2736eb8ff2e95daf6ec8b2616d70381054d1a238 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Fri, 3 Sep 2021 06:54:29 +0200 Subject: CONTRIBUTING.md: update code conventions to C++20 --- CONTRIBUTING.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9296df1..3eeac68c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,18 +155,20 @@ just don't bankrupt us with it. Refactoring is welcome. ### Code style and formatting -As of Quotient 0.6, the C++ standard for newly written code is C++17, with a few -restrictions, notably: +As of Quotient 0.6, the C++ standard for newly written code is C++17 with C++20 +compatibility and a few restrictions, notably: * standard library's _deduction guides_ cannot be used to lighten up syntax in template instantiation, i.e. you have to still write - `std::array { 1, 2 }` instead of `std::array { 1, 2 }` or use helpers - like `std::make_pair` - once we move over to the later Apple toolchain, this - will be no more necessary. -* enumerators and slots cannot have `[[attributes]]` because moc of Qt 5.9 - chokes on them. This will be lifted when we move on to Qt 5.12 for the oldest - supported version. -* things from `std::filesystem` cannot be used until we push the oldest - required g++/libc to version 8. + `std::array { 1, 2 }` instead of `std::array { 1, 2 }` (or use + `Quotient::make_array` helper from `util.h`), use `std::make_pair` to create + pairs etc. - once we move over to the later Apple toolchain, this will be + no more necessary; +* enumerators and slots cannot have `[[attributes]]` because moc from Qt 5.12 + chokes on them - this will be lifted when we move on to Qt 5.13 for the oldest + supported version, in the meantime use `Q_DECL_DEPRECATED` and similar Qt + macros - they expand to nothing when the code is passed to moc. +* explicit lists in lambda captures are preferred over `[=]`; note that C++20 + deprecates implicit `this` capture in `[=]`. The code style is defined by `.clang-format`, and in general, all C++ files should follow it. Files with minor deviations from the defined style are still -- cgit v1.2.3 From df66314bb47f1a824f35e9d5c7764305a4f103cb Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Fri, 3 Sep 2021 07:20:27 +0200 Subject: Tacitly allow CMake 3.13 to keep LGTM working Also: drop olm from the LGTM build environment, it's of no use there for now. --- .lgtm.yml | 18 ++++++++---------- CMakeLists.txt | 9 +++++++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.lgtm.yml b/.lgtm.yml index f6dfb229..308675a8 100644 --- a/.lgtm.yml +++ b/.lgtm.yml @@ -6,15 +6,13 @@ path_classifiers: extraction: cpp: prepare: - packages: # Assuming package base of cosmic - - ninja-build - - qt5-default + packages: # Assuming package base of eoan - qtmultimedia5-dev - after_prepare: - - git clone https://gitlab.matrix.org/matrix-org/olm.git - - pushd olm - - cmake . -Bbuild -GNinja - - cmake --build build - - popd +# after_prepare: +# - git clone https://gitlab.matrix.org/matrix-org/olm.git +# - pushd olm +# - cmake . -Bbuild -GNinja +# - cmake --build build +# - popd configure: - command: "cmake . -GNinja -DOlm_DIR=olm/build" + command: "cmake . -GNinja" # -DOlm_DIR=olm/build" diff --git a/CMakeLists.txt b/CMakeLists.txt index c0a39932..7043a653 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,6 @@ -cmake_minimum_required(VERSION 3.16) +# Officially CMake 3.16+ is needed but LGTM.com still sits on eoan that only +# has CMake 3.13 +cmake_minimum_required(VERSION 3.13) if (POLICY CMP0092) cmake_policy(SET CMP0092 NEW) endif() @@ -295,7 +297,10 @@ set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY # C++17 required, C++20 desired (see above) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) -if (NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 +# TODO: Bump the CMake requirement and drop the version check here once +# LGTM upgrades +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.16.0" + AND NOT CMAKE_CXX_COMPILER_ID STREQUAL GNU) # https://bugzilla.redhat.com/show_bug.cgi?id=1721553 target_precompile_headers(${PROJECT_NAME} PRIVATE lib/converters.h) endif () -- cgit v1.2.3