CMake: Introduce a CMake coding style document
Better to have something, than nothing at all. Mention it in the cmake readme. Task-number: QTBUG-120225 Change-Id: Ieffeeaac714b89d5d8b5a8b0c51abf3fe8e0a6c6 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io> Reviewed-by: Alexey Edelev <alexey.edelev@qt.io>
This commit is contained in:
parent
6bfdfea6d6
commit
573778de60
197
cmake/CODESTYLE.md
Normal file
197
cmake/CODESTYLE.md
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
# 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 function takes more than 1 parameter, consider using `cmake_parse_arguments`
|
||||||
|
* If an internal Qt function takes more than 1 parameter, consider using `qt_parse_all_arguments`
|
||||||
|
* 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`
|
||||||
|
|
@ -4,6 +4,11 @@ This document gives an overview of the Qt 6 build system. For a hands-on guide o
|
|||||||
to build Qt 6, see https://doc.qt.io/qt-6/build-sources.html and
|
to build Qt 6, see https://doc.qt.io/qt-6/build-sources.html and
|
||||||
https://wiki.qt.io/Building_Qt_6_from_Git
|
https://wiki.qt.io/Building_Qt_6_from_Git
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
See qtbase/cmake/CODESTYLE.md for the code style you should follow when contributing
|
||||||
|
to Qt's cmake files.
|
||||||
|
|
||||||
# CMake Versions
|
# CMake Versions
|
||||||
|
|
||||||
* You need CMake 3.16.0 or later for most platforms (due to new AUTOMOC json feature).
|
* You need CMake 3.16.0 or later for most platforms (due to new AUTOMOC json feature).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user