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
|
||||
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
|
||||
|
||||
* 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