Revision control
++ # Unofficial Qt CMake Coding Style
++
++ CMake scripts are a bit of a wild west. Depending on when the code was written, there were
++ different conventions as well as syntax facilities available. It's also unfortunate that there is
++ no agreed upon CMake code formatter similar to clang-format.
++ https://github.com/cheshirekow/cmake_format exists, but appears abandoned. We might look into
++ using it at some point.
++
++ It's hard to convince people to use a certain code style for a language like CMake.
++
++ Nevertheless this short document aims to be a guideline for formatting CMake code within the Qt
++ project.
++
++ ## Common conventions
++
++ * When in doubt, prefer the local code conventions of the function or file you are editing.
++ * Prefer functions over macros (macros have certain problems with parameter escaping)
++ * Prefix macro local variables to avoid naming collisions
++
++ ## Case Styles
++
++ For CMake identifiers we refer to following case styles in the text below.
++
++ | Case style name | Example identifier |
++ |-------------------|----------------------------|
++ | Snake case | `moc_options` |
++ | Shouty case | `INTERFACE_LINK_LIBRARIES` |
++ | Pascal case | `QmlModels` |
++
++ ## Indentation
++
++ * When in doubt, follow local indentation
++ * Prefer indenting with 4 spaces, e.g.
++
++ ```
++ if(1)
++ if(2)
++ message("3")
++ endif()
++ endif()
++
++ ```
++
++ ## Variables
++
++ * local variables inside a function should be snake cased => `list_of_arguments`
++ * local variables inside a macro should be snake cased and have a unique prefix =>
++ `__qt_list_of_packages`
++ * If your macro is recursively called, you might need to prepend a dynamically computed prefix
++ to avoid overriding the same variable in nested calls =>
++ `__qt_${dependency_name}_list_of_packages`
++ * cache variables should be shouty cased => `BUILD_SHARED_LIBS`
++ * Qt cache variables should be prefixed with `QT_`
++
++ ## Properties
++
++ Currently the Qt property naming is a bit of a mess. The upstream issue
++ https://gitlab.kitware.com/cmake/cmake/-/issues/19261 mentions that properties prefixed with
++ `INTERFACE_` are reserved for CMake use.
++
++ Prefer to use snake case for new property names.
++
++ * Most upstream CMake properties are shouty cased => `INTERFACE_LINK_LIBRARIES`
++ * Properties created in Qt 5 times follow the same CMake convention => `QT_ENABLED_PUBLIC_FEATURES`
++ No such new properties should be added.
++ * New Qt properties should be snake cased and prefixed with `qt_` => `qt_qmake_module_name`
++ * Other internal Qt properties should be snake cased and prefixed with `_qt_` => `_qt_target_deps`
++
++ ## Functions
++
++ * Function names should be snake cased => `qt_add_module`
++ * public Qt functions should be prefixed with `qt_`
++ * internal Qt functions should be prefixed with `qt_internal_`
++ * internal Qt functions that live in public CMake API files should be prefixed with
++ `_qt_internal_`
++ * some internal functions that live in public CMake API files are prefixed with
++ `__qt_internal_`, prefer not to introduce such functions for now
++ * If a public or internal Qt function takes more than 1 parameter,
++ consider using `cmake_parse_arguments(PARSE_ARGV)` followed by
++ `_qt_internal_validate_all_args_are_parsed`
++ * Public functions should usually have both a version-full and version-less name => `qt_add_plugin`
++ and `qt6_add_plugin`
++
++ ### Macros
++
++ * Try to avoid macros where a function can be used instead
++ * A common case when a macro can not be avoided is when it wraps a CMake macro e.g
++ `find_package` => `qt_find_package`
++ * Macro names should be snake cased => `qt_find_package`
++ * Prefix macro local variables to avoid naming collisions => `__qt_find_package_arguments`
++
++ ## Commands
++
++ Command names in CMake are case-insensitive, therefore:
++ * Only use lower case command names e.g `add_executable(app main.cpp)` not `ADD_EXECUTABLE(app
++ main.cpp)`
++ * Command flags / options are usually shouty cased => `file(GENERATE OUTPUT "foo" CONTENT "bar")`
++
++ ## 'If' command
++
++ * Keep the parenthesis next to the `if()`, so don't write `if ()`. `if` is a command name and like
++ other command names e.g. `find_package(foo bar)` the parenethesis are next to the name.
++
++ * To check that a variable is an empty string (and not just a falsy value, think Javascript's
++ `foo === ""`) use the following snippet
++ ```
++ if(var_name STREQUAL "")
++ message("${var_name}")
++ endif()
++ ```
++
++ If you are not sure if the variable is defined, make sure to evaluate the variable name
++ ```
++ if("${var_name}" STREQUAL "")
++ message("${var_name}")
++ endif()
++ ```
++
++
++ * Falsy values are `0`, `OFF`, `NO`, `FALSE`, `N`, `IGNORE`, `NOTFOUND`, the empty string `""`, or
++ a string ending in `-NOTFOUND`. To check that a variable is NOT falsy use the first suggested
++ code snippet
++ ```
++ # Nice and clean
++ if(var_name)
++ message("${var_name}")
++ endif()
++
++ # Wrong, can lead to problems due to double variable evaluation
++ if(${var_name})
++ message("${var_name}")
++ endif()
++
++ # Incorrect if you want to check for all falsy values. This only checks for string emptiness.
++ if("${var_name}" STREQUAL "")
++ message("${var_name}")
++ endif()
++ ```
++
++ * To check if a variable is defined, use
++ ```
++ if(DEFINED var_name)
++ endif()
++ ```
++
++ * To compare a defined variable's contents to a string, use
++ ```
++ if(var_name STREQUAL "my_string")
++ endif()
++ ```
++
++ * To compare a defined variable's contents to another defined variable's contents, use
++ ```
++ if(var_name STREQUAL var_name_2)
++ endif()
++ ```
++
++ * To compare a possibly undefined variable make sure to explicitly evaluate it first
++ ```
++ if("${var_name}" STREQUAL "my_string")
++ endif()
++
++ if("${var_name}" STREQUAL "${var_name_2}")
++ endif()
++ ```
++
++ ## find_package
++
++ * Inside Qt module projects, use the private Qt-specific `qt_find_package` macro to look for
++ dependencies.
++ * Make sure to specify the `PROVIDED_TARGETS` option to properly register 3rd party target
++ dependencies with Qt's internal build system.
++ * Inside examples / projects (which only use public CMake API) use the regular `find_package`
++ command.
++
++ ## CMake Target names
++
++ * Qt target names should be pascal cased => `QuickParticles`.
++ * When Qt is installed, the Qt CMake targets are put inside the `Qt6::` namespace. Associated
++ versionless targets in the `Qt::` namespace are usually automatically created by appropriate
++ functions (`qt_internal_add_module`, `qt_internal_add_tool`)
++ * Wrapper 3rd party system libraries usually repeat the target name as the namespace e.g.
++ ```WrapSystemHarfbuzz::WrapSystemHarfbuzz```
++
++ ## Finding 3rd party libraries via Find modules (FindWrapFoo.cmake)
++
++ qmake-Qt uses `configure.json` and `configure.pri` and `QT_LIBS_FOO` variables to implement a
++ mechnism that searches for system 3rd party libraries.
++
++ The equivalent CMake mechanism are Find modules (and CMake package Config files; not to be confused
++ with pkg-config). Usually Qt provides wrapper Find modules that use any available upstream Find
++ modules or Config package files.
++
++ The naming convention for the files are:
++
++ * `FindWrapFoo.cmake` => `FindWrapPCRE2.cmake`
++ * `FindWrapSystemFoo.cmake` => `FindWrapSystemPCRE2.cmake`
++