You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1288 lines
72 KiB

/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
namespace Magnum {
/** @page developers Developers guide
@brief Checklists for developing new things in Magnum itself
@tableofcontents
This guide is meant mainly for core Magnum developers to avoid forgetting about
things. If you are contributing a pull-request, you can use these checklists as
a guide and save the maintainers a bit of work --- but you are not strictly
required to follow them to the point.
@section developers-library Checklist for adding / removing a library
1. Add a `MAGNUM_WITH_LIBRARYNAME` CMake option to:
- root `CMakeLists.txt` (if it has some inter-library dependencies,
update the others / convert them to @cmake cmake_dependent_option() @ce,
adding `NOT MAGNUM_WITH_LIBRARYNAME` to their condition --- note the
conditions are ANDed so they need to be specified in reverse)
- the list in `doc/building.dox` (and similar files in other repos)
2. Update `FindMagnum.cmake` (or similar in other repos):
- mention the new lib in the list of components in the docs
- if it has some inter-library dependencies, add a corresponding
`_MAGNUM_Component_DEPENDENCIES` entry
- add its name to the `_MAGNUM_LIBRARY_COMPONENT_LIST` list
- add a new @cmake elseif(_component STREQUAL LibraryName) @ce section
with special setup of includes or dependencies or explicitly say
@cmake # No special setup for LibraryName library @ce
3. Add the library to the list in `doc/cmake.dox` (or similar files in other
repos)
4. Add a conditional @cmake add_subdirectory() @ce to `src/Magnum/CMakeLists.txt`
5. Create a new `src/Magnum/LibraryName/CMakeLists.txt`, copy over up-to-date
license header from other CMake files, add your name to it and populate it:
- add source files to `MagnumLibraryName_SRCS` variable
- add installable headers to `MagnumLibraryName_HEADERS` variable
- add private headers to `MagnumLibraryName_PRIVATE_HEADERS` variable (if
any)
- if the test needs some extra setup (such as e.g. @cpp CORRADE_NO_ASSERT @ce
enabled for particular files), create a new `MagnumLibraryNameObjects`
`OBJECT` library with files that can be compiled the same way in both
cases to speed up compilation
- verify that the @cmake add_library() @ce command references all input
files (needed so QtCreator lists all project files properly)
- verify that debug postfix is set
(@cmake set_target_properties(MagnumLibraryName PROPERTIES DEBUG_POSTFIX "-d") @ce)
- verify that folder is correctly set for the `CMakeLists.txt` file
(@cmake set(CMAKE_FOLDER "Magnum/LibraryName") @ce)
- verify that target installation is done in proper places (separate
`RUNTIME` / `LIBRARY` / `ARCHIVE` destinations)
- verify that @cmake set_target_properties(MagnumLibraryName PROPERTIES VERSION ${MAGNUM_LIBRARY_VERSION} SOVERSION ${MAGNUM_LIBRARY_SOVERSION}) @ce
is done in case `MAGNUM_BUILD_STATIC` is *not* set
- verify that @cmake set_target_properties(MagnumLibraryName PROPERTIES POSITION_INDEPENDENT_CODE ON) @ce
is done in case `MAGNUM_BUILD_STATIC_PIC` is set
- verify that @cmake add_library(Magnum::LibraryName ALIAS MagnumLibraryName) @ce
(or equivalent) is added to make the library visible for CMake
subprojects
6. Create a new `src/Magnum/LibraryName/Test/` directory:
- add a `CMakeLists.txt` with pre-populated license header, add your name
to it
- verify that folder is correctly set for the `CMakeLists.txt` file
(@cmake set(CMAKE_FOLDER "Magnum/LibraryName/Test") @ce)
- conditionally @cmake add_subdirectory() @ce it if `MAGNUM_BUILD_TESTS`
is enabled
7. Create a new `src/Magnum/LibraryName/LibraryName.h` header for forward
declarations (if needed), add a file-level doc block with
<tt>Forward declarations for the \@ref Magnum::LibraryName namespace</tt>
as brief docs
- reference it from `doc/compilation-speedup.dox`
8. Create a new `src/Magnum/LibraryName/visibility.h` header with
`MAGNUM_LIBRARYNAME_EXPORT` and `MAGNUM_LIBRARYNAME_LOCAL` macros by
copypasting it from another library:
- adapt @cpp #ifdef MagnumLibraryName_EXPORTS @ce so it matches CMake
target name
- if the library is combined from an `OBJECT` library, add its name to
the above @cpp #ifdef @ce as well (and then explicitly add
@cmake target_compile_definitions(MagnumLibraryNameObjects PRIVATE "MagnumLibraryNameObjects_EXPORTS") @ce
to `CMakeLists.txt` in case `MAGNUM_BUILD_STATIC` is not set)
- the macro *does not* contain the full namespace path but rather mirrors
the library *file* name
9. Mention the directory and namespace in `doc/namespaces.dox`, basically
copy-pasting the following from existing documentation:
- directory-level doc block referencing the namespace
- namespace-level doc block mentioning the `MAGNUM_WITH_LIBRARYNAME`
option, dependencies (if any) and a code snippet showing how to use it
with CMake
10. Code and test the rest of the library, see @ref developers-file and
@ref developers-symbol for more information
11. Add the `MAGNUM_WITH_LIBRARYNAME` option to all files in the `package/ci`
directory, explicitly saying either `ON` or `OFF` based on platform
support and whether it makes sense to enable it for given job if it's off
by default, or disable it for given job if it's enabled by default:
- all `package/ci/appveyor-*.bat` files (`^` is a line continuation)
- all `package/ci/``*.sh` files (@c \\ is a line continuation)
12. Add the `MAGNUM_WITH_LIBRARYNAME` option to other files in `package/`
directory if it's off by default but it makes sense to include it in given
package (such as, say, @ref Audio which is off by default because it
relies on OpenAL, but makes sense to be included on Linux and macOS because
there it's easy to get OpenAL):
- all `package/archlinux/PKGBUILD*` files (and the AUR package(s))
- all `package/msys/PKGBUILD*` files (and the AUR package(s))
- the `package/debian/rules` file (watch out, tabs!)
- the `package/gentoo/` `*.ebuild` file
- the `package/homebrew/` `*.rb` file (watch out, Ruby!)
13. If the library is enabled by default, disable it in `package/ci/` of
depending projects if not needed for a particular job to save CI times
14. If the library has dependencies:
- make sure they are mentioned in the library documentation
- make sure they are mentioned in building and CMake docs
- make sure they are mentioned in `CREDITS.md`
- make sure AppVeyor and CircleCI downloads them (based on platform
support)
15. Add the library to the graph in `doc/custom-buildsystem-order.dot`, listing
also its depdendencies to the rest of the project
16. Mention the library in `doc/changelog.dox` (or similar files in other
repos)
17. @ref building-doc "Build documentation":
- run [doxygen.py](https://mcss.mosra.cz/documentation/doxygen/) on
`Doxyfile-mcss` and verify there are no new warnings
- eyeball the namespace and directory docs, fix suspicious things, look
also in the building and cmake docs
18. Build a coverage build (`package/archlinux/PKGBUILD-coverage`), or abuse
the CI for that later
19. Push to a temporary branch (e.g., `next`)
20. Iterate until the CIs are green and the code coverage is good enough
21. Merge to `master`
In order to remove a library, be sure to touch all places mentioned above, only
in inverse --- but usually @ref developers-deprecation "deprecate first".
@section developers-application Checklist for adding / removing an application library
Similarly to @ref developers-library except points 2 and 5, with:
1. Update `FindMagnum.cmake` (replaces point 2 in @ref developers-library):
- mention the new lib in the list of components in the docs
- add its name to the `_MAGNUM_LIBRARY_COMPONENTS` regex
- add a new @cmake elseif(_component STREQUAL ApplicationName) @ce section
with special setup of includes or dependencies or explicitly say
@cmake # Name application has no additional dependencies @ce
2. Add a condition to `src/Magnum/Platform/CMakeLists.txt`:
- add the source file to `MagnumApplicationName_SRCS` variable
- add the installable header to `MagnumApplicationName_HEADERS` variable
- add a `STATIC` `MagnumApplicationName` library, verify that the
@cmake add_library() @ce command references all input files (needed so
QtCreator lists all project files properly)
- verify that debug postfix is set
(@cmake set_target_properties(MagnumApplicationName PROPERTIES DEBUG_POSTFIX "-d") @ce)
- verify that folder is set to avoid cluttering project tree view in IDEs
(@cmake set_target_properties(MagnumApplicationName PROPERTIES FOLDER "Magnum/Platform") @ce)
- verify that target installation is done in proper places (separate
`RUNTIME` / `LIBRARY` / `ARCHIVE` destinations)
- verify that @cmake add_library(Magnum::ApplicationName ALIAS MagnumApplicationName) @ce
is added to make the application visible for CMake subprojects
3. If desired, provide a new bootstrap project:
- new `base-applicationname` branch, forked from some `_modules_*`
branch, with the rest copied from a subset of e.g. the `base` branch
- update `README.md` in master, mentioning this
- update `package/ci` files to build this project (probably a new matrix
entry)
4. Mention the bootstrap project in the class documentation
5. Mention all extra files and setup in the class documentation
In order to remove an application library, be sure to touch all places
mentioned above, only in inverse --- but usually
@ref developers-deprecation "deprecate first".
@section developers-plugin Checklist for adding / removing a plugin
Similarly to @ref developers-library except points 2 and 5, with:
1. Update `FindMagnumPlugins.cmake` (or `FindMagnum.cmake` in the core repo)
(replaces point 2 in @ref developers-library):
- mention the new plugin in the list of components in the docs
- add its name to the `_MAGNUMPLUGINS_PLUGIN_COMPONENT_LIST` list
- add a new @cmake elseif(_component STREQUAL PluginName) @ce section
with special setup of includes or dependencies or explicitly say
@cmake # PluginName has no dependencies @ce
2. Create `PluginName.conf` and list all plugin dependencies (if any). The
file has to be present even if empty.
4. Create `importStaticPlugin.cpp` by copypasting it from another plugin and
adapting plugin name. This will get installed along with plugin headers to
aid with automatic import.
5. Create `configure.h.cmake` for plugin-specific information about whether
the library was built as static or not
6. Create a new `src/MagnumPlugins/PluginName/CMakeLists.txt`, copy over
up-to-date license header from other CMake files and populate it (replaces
point 5 in @ref developers-library):
- add source files to `PluginName_SRCS` variable
- add installable headers to `PluginName_HEADERS` variable
- add private headers to `PluginName_PRIVATE_HEADERS` variable (if any)
- use @cmake add_plugin() @ce command (which is aliased to either
@ref corrade-cmake-add-plugin "corrade_add_plugin()" or
@ref corrade-cmake-add-static-plugin "corrade_add_static_plugin()") to
create the `PluginName` library, use `${MAGNUM_PLUGINS_*_DEBUG_BINARY_INSTALL_DIR}`
/ `${MAGNUM_PLUGINS_*_RELEASE_BINARY_INSTALL_DIR}` and
`${MAGNUM_PLUGINS_*_DEBUG_LIBRARY_INSTALL_DIR}` /
`${MAGNUM_PLUGINS_*_RELEASE_LIBRARY_INSTALL_DIR}` variables that
correspond to given plugin interface
- verify that both @cmake add_library() @ce and @cmake add_plugin() @ce
commands reference all input files (needed so QtCreator lists all
project files properly)
- verify that folder is set for all other targets to avoid cluttering
project tree view in IDEs
(@cmake set_target_properties(PluginExtraTarget PROPERTIES FOLDER "MagnumPlugins/PluginName") @ce)
--- for the plugin library it's done automatically inside
@cmake add_plugin() @ce
- verify that @cmake set_target_properties(PluginName PROPERTIES POSITION_INDEPENDENT_CODE ON) @ce
is done in case `MAGNUM_BUILD_STATIC_PIC` is set
- verify that in case of `MAGNUM_BUILD_PLUGINS_STATIC` the
`importStaticPlugin.cpp` file is installed is set and that an
*absolute* path to it is added to @cmake target_sources() @ce
- verify that @cmake add_library(MagnumPlugins::PluginName ALIAS PluginName) @ce
(or equivalent) is added to make the library visible for CMake
subprojects
7. If there is more than one interface header (other than just `PluginName.h`
being installed), add a new `visibility.h` header. Otherwise put the
visibility macros directly in `PluginName.h`.
8. If the plugin handles a new format:
- if the plugin is not named directly after the format, add an alias to
it (for example the @ref Trade::MiniExrImageConverter "MiniExrImageConverter"
plugin is aliased to `OpenExrImageConverter`)
- update the @ref Trade::AnyImageImporter "AnyImageImporter",
@ref Trade::AnySceneImporter "AnySceneImporter",
@ref Trade::AnyImageConverter "AnyImageConverter" or
@ref Audio::AnyImporter "AnyAudioImporter" plugins to delegate to this
plugin (or its alias) upon encountering corresponding file extension
In order to remove a plugin, be sure to touch all places mentioned above, only
in inverse --- but usually @ref developers-deprecation "deprecate first".
@section developers-plugin-interface Checklist for adding / removing a plugin interface
@todoc write
In order to remove a plugin interface, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first".
@section developers-plugin-interface-updating Checklist for updating a plugin interface
When updating a plugin interface, the interface string (and thus also the
interface string in all plugin implementations) should be updated if any of the
following cases apply:
- Bump major version if the plugin usage changes significantly (and thus most
user code changes as well), for example when renaming a "open file" method
- Bump only the minor version if signature of some methods change,
potentially requiring changes in user code, for example when porting from
@ref std::string to @relativeref{Corrade,Containers::StringView}
- Bump only the patch version if the change doesn't affect existing user code
but breaks ABI, for example when adding a new virtual function --- this is
mainly to prevent crashes when loading of plugins built against an older
interface. A rather exhaustive list of ABI-affecting changes is in the KDE
Community Wiki: https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B
@subsection developers-plugin-interface-updating-importers Checklist for updating the `Trade::AbstractImporter` plugin interface
- Newly added `do*()` APIs need to be also handled in all proxies:
- @relativeref{Trade,AnyImageImporter}
- @relativeref{Trade,AnySceneImporter}
- Newly added data types need to be reflected in all APIs operating with
whole importers:
- @ref Trade::SceneContent
- @ref Trade::AbstractSceneConverter::addImporterContents()
- @ref Trade::AbstractSceneConverter::addSupportedImporterContents()
- @ref magnum-sceneconverter "magnum-sceneconverter" /
@ref magnum-imageconverter "magnum-imageconverter", at the very least
the `--info`
- Newly added @ref Trade::ImporterFlag values need to be reflected in:
- All plugins that may make use of them, together with documenting if
they're recognized
- New command-line options in
@ref magnum-sceneconverter "magnum-sceneconverter" /
@ref magnum-imageconverter "magnum-imageconverter"
- It's highly likely that APIs added to / changed in the importer will also
need a corresponding change in @ref Trade::AbstractImageConverter and
@ref Trade::AbstractSceneConverter
@subsection developers-plugin-interface-updating-image-converters Checklist for updating the `Trade::AbstractImageConverter` plugin interface
- Newly added `do*()` APIs need to be also handled in all proxies:
- @relativeref{Trade,AnyImageConverter}
- Corresponding changes in @ref magnum-imageconverter "magnum-imageconverter"
and possibly also @ref magnum-sceneconverter "magnum-sceneconverter"
- Newly added @ref Trade::ImageConverterFlag values need to be reflected in:
- All plugins that may make use of them, together with documenting if
they're recognized
- New command-line options in
@ref magnum-sceneconverter "magnum-sceneconverter" /
@ref magnum-imageconverter "magnum-imageconverter"
- It's highly likely that APIs added to / changed in the image converter will
also need a corresponding change in @ref Trade::AbstractSceneConverter
@subsection developers-plugin-interface-updating-scene-converters Checklist for updating the `Trade::AbstractSceneConverter` plugin interface
- Newly added `do*()` APIs need to be also handled in all proxies:
- @relativeref{Trade,AnySceneConverter}
- Corresponding changes in @ref magnum-sceneconverter "magnum-sceneconverter"
- Newly added @ref Trade::SceneConverterFlag values need to be reflected in:
- All plugins that may make use of them, together with documenting if
they're recognized
- New command-line options in
@ref magnum-sceneconverter "magnum-sceneconverter"
- Translation to @ref Trade::ImageConverterFlag in plugins that proxy
image conversion to image converter plugins
@section developers-tool Checklist for adding / removing a tool
@todoc write
In order to remove a tool, be sure to touch all places mentioned above, only in
inverse --- but usually @ref developers-deprecation "deprecate first".
@section developers-example Checklist for adding / removing an example
1. Add a `MAGNUM_WITH_EXAMPLENAME_EXAMPLE` CMake option to:
- root `CMakeLists.txt`
- the list in `doc/building-examples.dox`
2. Add a new `src/example-name` directory, copy up-to-date UNLICENSE headers
from other files in the repo
3. Verify that `src/example-name/CMakeLists.txt` contains @cmake cmake_minimum_required() @ce,
@cmake project() @ce and all @cmake cmake_policy() @ce commands so it can
be used as a top-level project level
4. If the example needs extra code to run on non-desktop platforms (and
running on non-desktop platforms is not the primary goal), consider moving
them to the `ports` branch to keep code in `master` as simple as possible
5. Add a new `doc/example-name.dox` page with @c \@brief, @c \@m_footernavigation
and @c \@page name equivalent to filename
6. Add a new `doc/example-name.png` image, scaled down to 400x300 from
800x600, reference it as `@image html example-name.png` from the `*.dox`
file
7. In case there's a web demo, add a button link to it (copy over other
example pages and adapt)
8. Add a new `examples-examplename-source` section with:
- link to GitHub
- referencing all textual example sources as
<tt>- \@ref example-name/file.ext "file.ext"</tt>
- breadcrumb and navigation setup for all example sources as
<tt>\@example example-name/file.ext \@m_examplenavigation{examples-example-name,example-name/} \@m_footernavigation</tt>
9. Update `doc/example-index.dox` and list the example there, optionally
adding a badge to advertise the web demo
10. Mention the example in `doc/changelog-examples.dox`
11. Push to a temporary branch (e.g., `next` or `ports-next`)
12. Iterate until the CIs are green
13. Merge to `master` / `ports`
In order to remove an example, be sure to touch all places mentioned above, but
in inverse.
@section developers-file Checklist for adding / removing a new source / header file
1. Copy over a up-to-date license header (note that example code uses
UNLICENSE instead of MIT) and add your name + year to it, if not already
there
2. Add a <tt>\@file</tt>-level documentation block, with @c \@brief listing
all classes, functions, typedefs, enums, macros etc. that are in the file
3. Annotate it with a correct variant of the <tt>\@m_since_latest</tt> command
for given repository
4. Add the file to corresponding `*_SRCS`, `*_HEADERS`, `*_PRIVATE_HEADERS`
list in `CMakeLists.txt`
5. If applicable, add a new test class file in the `Test/` directory
- name it `FileNameTest.cpp`, put a class named `FileNameTest` inside,
wrapped in a `Test` subnamespace of the original file namespace
- use @cmake corrade_add_test() @ce to add it to tests
- if some tests need GL context, add a separate test with `GLTest`
suffix, wrapping the corresponding @cmake corrade_add_test() @ce in
@cmake if(MAGNUM_BUILD_GL_TESTS) @ce
6. Populate the file, see @ref developers-symbol and @ref coding-style for
more information.
7. Mention the new functionality in `doc/changelog.dox` (and similar files in
other repos)
8. @ref building-doc "Build documentation":
- run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-mcss`
and verify there are no new warnings
- eyeball the relevant docs and fix suspicious things
9. Build a coverage build (`package/archlinux/PKGBUILD-coverage`), or abuse
the CI for that later
10. Push to a temporary branch (e.g., `next`)
11. Iterate until the CIs are green and the code coverage is good enough
12. Merge to `master`
In order to remove a file, be sure to touch all places mentioned above, only
in inverse --- but usually @ref developers-deprecation "deprecate first".
@section developers-symbol Checklist for adding / removing a symbol
1. If the symbol is standalone (i.e., not member of a class), list it in the
<tt>\@file</tt>-level @c \@brief docs
2. Document it
3. Annotate it with a correct variant of the <tt>\@m_since_latest</tt> command
for given repository
4. Add a test for it to corresponding file, verify the test gets actually run
5. Mention the new functionality in `doc/changelog.dox` (and similar files in
other repos)
6. @ref building-doc "Build documentation":
- run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-mcss`
and verify there are no new warnings
- eyeball the relevant docs and fix suspicious things
7. Build a coverage build (`package/archlinux/PKGBUILD-coverage`), or abuse
the CI for that later
8. Push to a temporary branch (e.g., `next`)
9. Iterate until the CIs are green and the code coverage is good enough
10. Merge to `master`
In order to remove a symbol, be sure to touch all places mentioned above, only
in inverse --- but usually @ref developers-deprecation "deprecate first".
@section developers-page Checklist for adding a new CMake documentation page
1. Add a `doc/pagename.dox` file, copy up-to-date license header and add your
name + year to it, if not already there
2. If the page is top-level, list it in `doc/00-page-order.dox` to ensure it
gets listed at a proper place
3. If the page is not top-level, list it using @c \@subpage in its parent page
and add @c \@m_footernavigation for automatic linking to parent and
prev/next pages
4. Add a @c \@brief documentation, if applicable
5. Populate it, see @ref coding-style for more information
6. Mention the new page in `doc/changelog.dox` (and similar files in other
repos)
7. @ref building-doc "Build documentation":
- run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-mcss`
and verify there are no new warnings
- eyeball the relevant docs and fix suspicious things
8. Push to `master`
@section developers-deprecation Checklist for deprecating a feature
1. If the feature is publicly exposed, think about the best way of deprecation
that preserves source compatibility:
- Add a compatibility @cpp typedef @ce / @cpp using @ce for a renamed
symbol, marking it with @ref CORRADE_DEPRECATED() / @ref CORRADE_DEPRECATED_ALIAS()
- Add a compatibility header for a renamed include, including the
original file from it and marking it with @ref CORRADE_DEPRECATED_FILE().
Ensure the file is not included from anywhere else anymore, since that
would mean the user then gets spammed with more than just one warning
per included file. This macro also can't easily be disabled on most
platforms.
- Add a compatibility inline function for a function that got renamed or
its arguments changed, mark it with @ref CORRADE_DEPRECATED()
- Add a compatibility enum value for a value that got renamed or deleted,
mark it with @ref CORRADE_DEPRECATED_ENUM()
- Don't *ever* change semantics of function arguments without changing
the function signature. That would silently break with no possibility
to let the user know.
- Function return type changes are hard. One possibility is working
around that by returning a wrapper type that's implicitly convertible
to both the old and new type, another is introducing a differently
named function instead. The last resort is breaking the API without
preserving backwards compatibility --- but that makes people angry, so
avoid that if possible.
2. Add just a <tt>\@brief \@copybrief</tt> from the replacement functionality
together with a @c \@deprecated line to the deprecated feature
3. Reference the replacement functionality in both the deprecation macro and
in the @c \@deprecated line to make porting easier
4. Ensure the deprecated symbol is wrapped in @cpp #ifndef MAGNUM_BUILD_DEPRECATED @ce,
5. Ensure deprecated files @cpp #error @ce in case they get used in
non-deprecated build, ensure they are not installed in non-deprecated
builds
6. Build all tests and dependent projects and verify that:
- using the old functionality still compiles and works as intended
- deprecation warnings are emitted in proper places
7. Upon verifying the above, start updating dependent code
8. Mention the deprecated API in the deprecation section of `doc/changelog.dox`
(and similar files in other repos)
9. @ref building-doc "Build documentation":
- run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-mcss`
and verify there are no new warnings
- eyeball the relevant docs and fix suspicious things
10. Push to a temporary branch (e.g., `next`)
11. Iterate until the CIs are green
12. Merge to `master`
13. If possible, trigger builds of dependent projects (where they are still
using the old API) and verify they are still green (and red in
non-deprecated build)
14. Update dependent projects
@section developers-deprecation-library Checklist for deprecating a whole library
1. If there's no compatible replacement (for example when removing support for
an outdated toolkit), think about possible alternatives, external libraries
or other ways to reach the same goal.
2. Add deprecation notes, listing alternatives
- to docs of the whole namespace and all its members
- to docs of the directory and all files inside
- to all feature overview pages
- to each symbol using one of the @ref CORRADE_DEPRECATED() macros, with
a shorter note mentioning alternatives
- ensure each public headers (transitively) contains exactly one
@ref CORRADE_DEPRECATED_FILE() macro to warn the user *exactly once*
about including a deprecated header --- in particular, putting it in
every file would spam the user way too much
- since the files are still compiled and included by the library, wrap it
in @cpp #ifndef _MAGNUM_DO_NOT_WARN_DEPRECATED_LIBRARYNAME @ce and
@cpp #define @ce this macro in all `*.cpp` files and tests to avoid
spamming the compiler log
- an @cpp #error @ce to each header file in case @ref MAGNUM_BUILD_DEPRECATED
is not enabled
- wrap contents of every header, source and test file in
@ref CORRADE_IGNORE_DEPRECATED_PUSH and @ref CORRADE_IGNORE_DEPRECATED_POP
to avoid warnings when compiling the library itself (no, this doesn't
disable warnings for library *users*)
- a @cmake message(FATAL_ERROR) @ce to corresponding `CMakeLists.txt` in
case @ref MAGNUM_BUILD_DEPRECATED is not enabled
- a @m_class{m-label m-danger} **deprecated** label next to the
`MAGNUM_WITH_*` CMake option in the corresponding `doc/building.dox`
page and next to the CMake component name in the corresponding
`doc/cmake.dox` page (and similar files in other repos), possibly also
to all pages that list it (if any)
3. If the library was enabled by default, make it disabled by default. Update
relevant sections in `doc/building.dox` and `doc/cmake.dox`.
4. Include the library component in the corresponding `Find` module component
list only if @ref MAGNUM_BUILD_DEPRECATED is enabled.
5. Remove the deprecated library from all packages except developer `PKGBUILD`s
and CIs, remove also its no-longer-needed dependencies from these packages
6. Verify no other libraries, projects or examples depend on given library
anymore. If they do:
- rework examples to not use the deprecated functionality anymore
- if there are dependencies in other libraries or projects, make the
related features deprecated in the same manner, building them only
if @ref MAGNUM_BUILD_DEPRECATED is enabled
- update corresponding `Find` modules to require dependency on this
library only if @ref MAGNUM_BUILD_DEPRECATED is enabled
7. Verify no CIs in dependent projects have this library enabled. If they do,
it should be only if @ref MAGNUM_BUILD_DEPRECATED is enabled and only if
there is a (deprecated) feature depending on this library.
8. Mention the deprecated library in the deprecation section of `doc/changelog.dox`
(and similar files in other repos), note the alternatives and note that
it's no longer built by default or included in any packages (in case it was
before)
@section developers-removing Checklist for removing a feature
1. Check that it was in deprecated state for more than a year with at least
one release in between. Check that no important clients depend on it
anymore. If not, wait a bit more.
2. Remove relevant blocks wrapped in @cpp #ifndef MAGNUM_BUILD_DEPRECATED @ce,
remove relevant deprecated files and update `CMakeLists.txt`
3. Mention the removed API in the compatibility section of `doc/changelog.dox`
(or similar files in other repos)
4. @ref building-doc "Build documentation":
- run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-mcss`
and verify there are no new warnings --- sometimes it happens that a
deprecated API is still being referenced
5. Push to a temporary branch (e.g., `next`)
6. Iterate until the CIs are green
7. Merge to `master`
8. If possible, trigger builds of dependent projects and verify they are still
green (or wait for the scheduled builds)
@section developers-adding-attribute Checklist for adding a new mesh attribute
1. Extend @ref Trade::MeshAttribute with the new entry
2. Add a corresponding reserved type to @ref Shaders::GenericGL, if not there
already
- Also update `src/Magnum/Shaders/generic.glsl` with the reserved ID
3. Update the type assertion in the @ref Trade::MeshAttributeData constructor
to account for the new type
4. Add a pair of convenience getters to @ref Trade::MeshData similar to e.g.
@ref Trade::MeshData::normalsInto() / @ref Trade::MeshData::normalsAsArray()
with a type that's the same as the one used in the @ref Shaders::GenericGL
definition, test that it does the right thing for every supported type
5. Update @ref Trade::operator<<(Debug&, MeshAttribute) for the new entry
6. Update @ref MeshTools::compile() to recognize the new attribute. If there
is already a builtin shader capable of using this attribute, add new test
to `MeshToolsCompileGLTest`.
7. Push to a temporary branch (e.g., `next`)
8. Iterate until the CIs are green
9. Merge to `master`
@section developers-adding-vertex-format Checklist for adding a new vertex format
1. Extend @ref VertexFormat with the new entry, if it's not there already,
document mapping to GL, Vulkan, D3D and Metal (if exists)
2. Update docs of @ref Trade::MeshAttribute to mention where the format can be
newly used
3. Appropriately relax the assertion in the @ref Trade::MeshAttributeData
constructor
3. Extend `Trade::Implementation::vertexFormatFor()`, add a mapping between
this entry and a C++ type, optionally also
`isVertexFormatCompatibleWithAttribute()` if there's more than one entry
corresponding to a particular C++ type. If the mapping is unconventional,
be sure to mention it in the
@ref Trade::MeshAttributeData::MeshAttributeData(MeshAttribute, const Containers::StridedArrayView1D<T>&, Int)
constructor docs.
4. Update corresponding `Trade::MeshData::*Into()` convenience getters to
ensure they can handle this type
5. Update `src/Magnum/Implementation/vertexFormatMapping.hpp` and
`src/Magnum/Vk/Implementation/vertexFormatMapping.hpp` with the new entry
6. Update @ref vertexFormatSize(), @ref vertexFormatComponentFormat(),
@ref vertexFormatComponentCount() and @ref isVertexFormatNormalized() to
handle this format
7. Update the @ref GL::hasVertexFormat() utility and
@ref GL::DynamicAttribute::DynamicAttribute(Kind, UnsignedInt, VertexFormat)
constructor to provide mapping of the new type to GL; add a test for the
new type, if it's special in some way, otherwise the all-catching loop will
check it
8. Update @ref MeshTools::compile() to recognize the new type (if anything
extra needs to be done, usually doesn't as everything is handled by
@ref GL::DynamicAttribute already); add corresponding new test(s) to
`MeshToolsCompileGLTest`.
9. Push to a temporary branch (e.g., `next`)
10. Iterate until the CIs are green
11. Merge to `master`
@section developers-gl-extensions Checklist for adding / removing GL extensions
1. Add new extensions to the GL, GLES and WebGL sections of
`src/Magnum/GL/Extensions.h`
- Order them by extension ID that is mentioned in every extension spec
file. If the extension isn't in the official Khronos registry (such as
various ANGLE extensions), at it at the end of the range.
- Update the numbering to stay monotonic and unique, round up start index
of next section to nearest ten to make the updates bearable
- In case there's a lot of new extensions,
@cpp Implementation::ExtensionCount @ce might needed to be increased.
2. Add them alphabetically ordered to the correct list in
`src/magnum/GL/Context.cpp`
- run GL, ES2, ES3, WebGL1 and WebGL2 build of `GLContextTest` to verify
everything is still okay
- run GL, ES2, ES3, WebGL1 and WebGL2 build of `magnum-gl-info`
- the extension should be listed unless it's not available on given
GL flavor
- and also marked as supported unless the machine doesn't support it
(cross-check with `--extension-strings`)
3. Get [flextGL](https://github.com/mosra/flextgl) and go to
`src/MagnumExternal/OpenGL/`:
- Add/remove extensions in `GL/extensions.txt`, `GLES2/extensions.txt`,
`GLES2/Emscripten/extensions.txt`, `GLES3/extensions.txt`,
`GLES3/Emscripten/extensions.txt`, in the same order as in
`src/Magnum/GL/Extensions.h`
- For GLES and WebGL extensions, if they aren't in the official Khronos
registry (such as various ANGLE extensions), check if they're in
ANGLE's [gl_angle_ext.xml](https://raw.githubusercontent.com/google/angle/master/scripts/gl_angle_ext.xml)
at least. If not, like with core WebGL functionality that has no match
in the base GLES spec, you may need to craft your own XML file. See
`src/MagnumExternal/OpenGL/GLES3/webgl.xml` for an example.
- WebGL extensions usually have a GLES extension as a base, but then may
remove certains entrypoints from it. If that's the case, add it to the
function blacklist at the end of the Emscripten-specific files.
- Run `./update-flextgl.sh` to update everything. Reason there is so many
variants of the files are the following:
- Desktop GLES on Windows still links to the ancient `opengl32.dll`
which exports only OpenGL 1.1 symbols, so we have a special set of
headers that queries pointers for everything above OpenGL 1.1
(instead of everything above OpenGL ES 2.0).
- iOS, on the other hand, doesn't have any extension loader mechanism
and all supported entrypoints are exported from the library, so we
set the function pointers to those exported symbols in case the
system GL header defines them.
- Emscripten doesn't have the ability to manually load extension
pointers either, thus it has only header files.
4. Check @cb{.sh} git diff @ce for suspicious changes and whitespace-at-EOL
- If any extensions don't add any useful symbols, comment them out in
the `extensions.txt` files and regenerate to avoid needless bloat
5. For every new function that appeared in the regenerated extension headers,
add an entry to `doc/opengl-mapping.dox`
6. For every new added limit query that appeared in the regenerated extension
headers (various `GL_MIN_*` and `GL_MAX_*` macros etc.), add an entry to
the bottom of `doc/opengl-mapping.dox`
7. Add new extensions to the general GL, GLES and WebGL lists in
`doc/opengl-support.dox`, again matching the order in `Extensions.h` ---
grouped by prefix, but then ordered by extension number
In order to remove GL functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@see @ref developers-gl-versions, @ref developers-vk-extensions
@section developers-gl-versions Checklist for adding / removing GL versions
1. Add new version enum value:
- to `src/Magnum/GL/Version.h`
- to debug output in `src/Magnum/GL/Version.cpp`
- to @cpp GL::Extension::extensions() @ce in `src/Magnum/GL/Context.cpp`
- to @cpp GL::Context::tryCreate() @ce in `src/Magnum/GL/Context.cpp`
- to specify GLSL version in `src/Magnum/GL/Shader.cpp`
- to the list in `src/Magnum/Platform/gl-info.cpp`
- to the test in `src/Magnum/GL/Test/ContextTest.cpp`
2. Update existing extensions with version in which they became core (last
parameter of the `_extension()` macro in `src/Magnum/GL/Extensions.h`)
3. Go to `src/MagnumExternal/OpenGL/`, bump versions in `GL/extensions.txt`,
`GLES2/extensions.txt`, `GLES2/Emscripten/extensions.txt`,
`GLES3/extensions.txt`, `GLES3/Emscripten/extensions.txt`
4. Continue with @ref developers-gl-extensions for all extensions that were
added by the new version and were not already present
5. For all existing extensions APIs that lose their suffix in the new version,
update doc references to be without the suffix
6. Add a table listing the new version and all new extensions in it to
`doc/opengl-support.dox` (take a list of them from the changelog in the
official spec PDF). Some extensions might be already present in the general
extension list, move them out of there.
7. Add a new `requires-glXY`, `requires-glesXY` or `requires-webglXY` page
with @c \@m_footernavigation to `doc/opengl-support.dox`, mention it as a
@c \@subpage at a correct position in the list
8. Add a new `requires-glXY`, `requires-glesXY` or `requires-webglXY` alias
to `Doxyfile`, `Doxyfile-mcss` and `Doxyfile-public`, copypaste it from
existing and change the numbers
In order to remove GL functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@see @ref developers-vk-versions
@section developers-gl-functionality Checklist for adding / removing GL functionality
1. Check if given desktop functionality has equivalent in ES or WebGL:
- check for similarly named APIs in `MagnumExternal/OpenGL/GLES2/flextGL.h`
and others
- if not there or if there only in a core version and not an extension,
the extension may not be included --- check the cached `spec/gl.xml`
file inside the flextGL clone
- for WebGL it might also be ANGLE-only, look for it in
https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions
- add missing extensions as described in @ref developers-gl-extensions
2. Check if there's a DSA / non-DSA way to do the thing. Omit the non-DSA way
if all drivers that support given functionality support DSA as well (i.e.,
the functionality was not introduced before DSA became core) and there's no
corresponding non-DSA functionality in ES or WebGL.
3. If the functionality uses different entry points / defines on desktop and
ES / WebGL platforms, use @cpp #ifdef MAGNUM_TARGET_GLES @ce,
@cpp #ifdef MAGNUM_TARGET_GLES2 @ce and @cpp #ifdef MAGNUM_TARGET_WEBGL @ce
to cover the differences
4. If the functionality can use different entry points based on driver
capabilities on the same platform (DSA / non-DSA is one of them), add
separate code paths:
- new private and `MAGNUM_LOCAL` `thingImplementation*()` functions, each
implementing one code path, preferably @cpp static @ce
- ideally make the signature in a way that makes it possible to just
call the GL API directly via a function pointer and have
`thingImplementation*()` only for fallbackse
- a `thingImplementation` (member) function pointer in `src/Magnum/Implementation/SomeState.h`
that gets populated in `src/Magnum/GL/Implementation/SomeState.cpp`
based on extension / version availability
- a public function, dispatching to
@cpp Context::current().state().some->thingImplementation @ce in the
implementation
5. If the functionality is a limit query, add a cache for it:
- a member variable that's either set to @cpp 0 @ce or
@ref Corrade::Containers::NullOpt in `src/Magnum/Implementation/SomeState.cpp`
- the query first checks for presence of cached value and queries it only
if not cached yet
- in case the limit query depends on some extension which might not be
available, return some reasonable value (@cpp 0 @ce) in that case
6. Implement the functionality (see @ref developers-file, @ref developers-symbol)
7. Document the functionality
- if important, describe the different code paths (DSA / non-DSA) or
functionality fallbacks
- list the DSA / non-DSA distinction among function list in the
class-level docs
- a @c \@see block listing GL APIs used with @c \@fn_gl{}, @c \@def_gl{}
etc., use @c \@fn_gl_keyword{} etc. to expose them in search if
desired (see @ref coding-style-documentation-commands-ref)
- list version / extension requirements using @c \@requires_glXY etc.
(see @ref coding-style-documentation-commands-requires), check how
similar requirements are listed elsewhere and try to match that
8. Add the function or limit query to the mapping table in `doc/opengl-mapping.dox`,
possibly to multiple places
9. Update relevant extension support in tables in `doc/opengl-support.dox`
10. Mention the new stuff in `doc/changelog.dox`
11. @ref building-doc "Build documentation":
- run [doxygen.py](https://mcss.mosra.cz/documentation/doxygen/) on
`Doxyfile-mcss` and verify there are no new warnings
- eyeball the relevant docs and fix suspicious things
- make sure links to GL APIs and extensions are working
12. Build and test for relevant platforms locally (as the public CI can't test
GL things in full, only the ES subset)
13. Push to a temporary branch (e.g., `next`)
14. Iterate until the CIs are green
15. Merge to `master`
In order to remove GL functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@section developers-driver-workaround Checklist for adding / removing a driver workaround
1. Put a descriptive string with even more descriptive comment into the
`KnownWorkarounds` array in `src/Magnum/GL/Implementation/driverSpecific.cpp`,
ideally reuse some of the already existing vendor prefixes
2. If the workaround can be tied down to a particular platform / target, add
appropriate @cpp #ifdef @ce around it
3. Create (or extend) a pair of (member) @cpp private @ce `MAGNUM_LOCAL`
`*Implementation*()` functions in the affected class, `*ImplementationDefault()`
having the optimistic default behavior, the other having the workaround.
Add the appropriate @cpp #ifdef @ce around, if any.
4. Add a new (member) function pointer in `src/GL/Implementation/SomeState.h`
and call it from the affected class instead of executing the implementation
directly. Add the appropriate @cpp #ifdef @ce around, if any.
5. Add a branch into `src/GL/Implementation/SomeState.cpp` (with appropriate
@cpp #ifdef @ce around, if any). First check for driver and other
circumstances and call the @cpp !context.isDriverWorkaroundDisabled("the-workaround-string") @ce
<em>last</em> after you are really sure you need to use it --- calling this
function will append the workaround string to the engine startup log and
it's not desirable to list workarounds that weren't used.
6. Test the affected functionality with the workaround enabled and verify it
works
7. Disable the workaround using `--magnum-disable-workarounds` on command-line
and verify it's still broken --- if not, there's something off!
8. Add a changelog entry.
9. Verify the driver workaround is listed in the snippet in
@ref opengl-workarounds
Removeing a workaround is simply a matter of searching for its string, removing
all occurrences of that string and removing all `*Implementation*()` functions
that were used only if the workaround was in place. No need to deprecate
anything, users explicitly disabling given workaround will only be informed
that such workaround does not exist anymore.
@section developers-al-extensions Checklist for adding / removing OpenAL versions and extensions
@todoc adapt from the GL section
In order to remove OpenAL functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@section developers-al-functionality Checklist for adding / removing OpenAL functionality
@todoc adapt from the GL section
In order to remove OpenAL functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@section developers-vk-extensions Checklist for adding / removing Vulkan extensions
1. Add new extensions to `src/Magnum/Vk/Extensions.h`
- there's a separate list for instance and device extensions, ensure each
is in the right list
- order them by extension ID that is mentioned on every extension spec
page
- update the numbering to stay monotonic and unique, round up start index
of next section to nearest ten to make the updates bearable
- in case there's a lot of new extensions,
@cpp Implementation::InstanceExtensionCount @ce in `Instance.h` /
@cpp Implementation::DeviceExtensionCount @ce in `Device.h` might
need to be increased
2. Add them alphabetically ordered to the correct list in
`src/Magnum/Vk/Extensions.cpp`
- run `VkExtensionsTest` to verify everything is still okay
- run `magnum-vk-info`, the extension should be listed and also marked as
supported, unless the machine doesn't support it (cross-check with
`--extension-strings`)
3. Get [flextGL](https://github.com/mosra/flextgl) and go to
`src/MagnumExternal/Vulkan/`:
- Add/remove extensions in `extensions.txt`, in the same order as in
`src/Magnum/Vk/Extensions.h`
- Run `./update-flexgl.sh` to update everything
4. Check @cb{.sh} git diff @ce for suspicious changes and whitespace-at-EOL
- If any extensions don't add any useful symbols, comment them out in
the `extensions.txt` file and regenerate to avoid needless bloat
5. For every new added function and structure, add an entry to
`doc/vulkan-mapping.dox`
6. For every new `*Feature` structure, expand the @ref Vk::DeviceFeatures
enum according to @ref developers-vk-features
7. Add new extensions to the general list in `doc/vulkan-support.dox`, again
matching the order in `Extensions.h` --- grouped by prefix, but then
ordered by extension number
In order to remove Vulkan functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@see @ref developers-vk-versions, @ref developers-gl-extensions
@section developers-vk-versions Checklist for adding / removing Vulkan versions
1. Add new version enum value:
- to `src/Magnum/Vk/Version.h`
- to the list in `src/Magnum/Vk/vk-info.cpp`
- to @cpp Vk::InstanceExtension::extensions() @ce and
@cpp Vk::Extension::extensions() @ce in `src/Magnum/Vk/Extensions.cpp`
2. Update existing extensions with version in which they became core (last
parameter of the `_extension()` macro)
3. Continue with @ref developers-vk-extensions for all extensions that were
added by the new version and were not already present
4. For all existing extensions APIs that lose their suffix in the new version,
update doc references to be without the suffix
5. Add a table listing the new version and all new extensions in it to
`doc/vulkan-support.dox` (take a list of them from the changelog in the
official spec). Some extensions might be already present in the general
extension list, move them out of there.
6. Add a new `requires-vkXY` page with @c \@m_footernavigation to
`doc/vulkan-support.dox`, mention it as a @c \@subpage at a correct
position in the list
7. Add a new `requires-vkXY` alias to `Doxyfile`, `Doxyfile-mcss` and
`Doxyfile-public`, copypaste it from existing and change the numbers
In order to remove Vulkan functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@see @ref developers-gl-versions
@section developers-vk-functionality Checklist for adding / removing Vulkan functionality
@todoc adapt from the GL section
In order to remove Vulkan functionality, be sure to touch all places mentioned
above, only in inverse --- but usually @ref developers-deprecation "deprecate first",
unless it doesn't affect public API at all.
@section developers-vk-createinfo Checklist for Vulkan CreateInfo wrappers
- A `ThingCreateInfo` structure and its dependencies that aren't needed by
`Thing` itself should be in a dedicated `ThingCreateInfo.h` header, and
including the `Thing.h` at the end for convenience
- Every class should have a `Flag` and `Flags` members even if the spec lists
no usable flags, exception is the rare structures that don't have any
`flags` member (@ref Vk::MemoryAllocateInfo, until Vulkan 1.1 at least)
- The main constructor(s) should explicitly list what structure fields are
filled to which value, and if the constructor isn't enough to get a working
state, it should also clearly mention what needs to be done next
- For everything non-essential or what isn't practical to be set in
constructor a setter should be added. If applicable, document what
subsequent calls to the same function result in (for example when a list
gets cleared while all other functions append to lists). The docs should
again list what underlying structure fields are set to which value.
- Every class should have a @ref NoInitT constructor, which keeps the
structure uninitialized and *doesn't* allocate any internal state
- Every class should have a constructor taking the underlying Vulkan
structure, it should not allocate either but instead reference the original
data
- Every class should provide a set of @cpp operator*() @ce,
@cpp operator->() @ce and their const variants providing direct access to
the underlying Vulkan structure
- Every class should have a @cpp operator const VkThing*() const @ce that
returns a pointer to the underlying Vulkan structure for convenient use
directly in `vkCreate*()` APIs (or alternatively returning a reference, if
the structure is commonly used in arrays as is the case with
@ref Vk::AttachmentReference for example)
- Classes should be implicitly copyable, with no copy/move constructors,
destructor or copy/move assignments listed. If a class needs to store some
heap-allocated state (such as @ref Vk::FramebufferCreateInfo image view
handles), it should be made move-only with the `other._info` members
pointing to the stolen state cleared so the old instance doesn't reference
state that's owned by something else after the move.
- Additionally, if a move-only class needs to be itself moved into a
containing structure (such as @ref Vk::SubpassDescription inside a
@ref Vk::RenderPassCreateInfo), all its setters should have @cpp & @ce
and @cpp && @ce overloads so it can be set up completely and passed to
its destination in a single expression without any explicit
@m_class{m-doc-external} [std::move()](https://en.cppreference.com/w/cpp/utility/move).
The overloads can be tested for correctness rather easily, see
`RenderPassTest::subpassDescriptionRvalue()` for an example.
@section developers-vk-extension-dependent Checklist for Vulkan extension-dependent code paths
Every time an extension-dependent code path is expected to be used several
times (such as render pass creation, but not one-time device property query,
for example), it should be implemented through a `*Implementation*()` function
pointers on a class that needs them:
- The `*Implementation()` functions should be suffixed depending on version /
extension that adds them (so e.g. `ImplementationDefault`,
`ImplementationKHR`, `Implementation12`)
- The implementation should be `MAGNUM_VK_LOCAL` and @cpp static @ce, taking
the class via @cpp Type& self @ce if necessary. This avoids extra overhead
coming from member function pointers and doesn't require an @cpp #include @ce
of the full type on MSVC in order to avoid ABI issues (as insane as it
sounds, MSVC member function pointer size is different depending if the
type is incomplete or not, causing hard-to-debug crashes).
- Their API should match the latest functionality and doing compatibility
steps for previous versions, not the other way around (so for example
extracting "version 1" structures from "version 2" in order to call the
default functionality)
- The return value of the concrete Vulkan call should be always propagated
upwards with a @cpp return @ce, *even if* the call returns @cpp void @ce,
and the call site should be wrapping it in a
@ref MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(). This is preferred over having the
assert repeated for each code path, as it generates less code.
- @cpp Implementation::InstanceState @ce / @cpp Implementation::DeviceState @ce
then contains the dispatching function pointer, choosing the appropriate
version based on what version and extensions are available.
- Finally, the extension should be implicitly enabled during instance /
device creation as appropriate --- for example, if the extension is core in
1.2, the extension should be enabled only on 1.1 and below.
@section developers-vk-features Checklist for adding Vulkan features
1. For every new `VkPhysicalDevice*Features` structure, add its boolean
members to the @ref Vk::DeviceFeature enum. There are headings referring
the full `VkPhysicalDevice*Features` structure name and either the version
or extension number, put the new members under a new heading at a correct
place.
2. Formulate the documentation to start with "Whether" and replace verbose
phrases like "the implementation supports ..." from the spec with "... is
supported".
3. Add a `@see` block, referencing related features if applicable,
crossreference the newly added value from the values it refers to as well
4. Reference the extension / version it was added in via `@requires_vkXY`
5. If APIs depending on this feature are already exposed, reference the
feature from those
6. Add the new members to `Magnum/Vk/Implementation/deviceFeatureMapping.hpp`
to the correct place with a `_cver()` or `_cext()` macro as appropriate
7. Extend `Magnum/Vk/Implementation/DeviceFeatures.h` with the new feature
struct, added to relatively the same place as in the enum header
8. Extend @ref Vk::DeviceProperties::features():
- connecting the new structure to the chain, insert to the correct place
again,
- expand the function docs to mention the new structure (again correct
order),
- verify that the features were fetched correctly (and especially that a
correct structure type was set) with @ref magnum-vk-info "magnum-vk-info"
--- (a subset) the new features should be shown as supported and
* *especially* everything after still looks the same as it looked
before. For some reason the Khronos validation layer doesn't check
`sType` fields in this query so it's easy to make a hard-to-discover
error
9. Extend @ref Vk::DeviceCreateInfo::setEnabledFeatures():
- a similar addition as above, connecting the structure to the chain at
correct place,
- to the correct place in the structureChainDisconnect() call,
- and function documentation again
10. Add a link to the new Feature structure in `doc/vulkan-mapping.dox`
@section developers-dependency Checklist for adding, removing or updating a dependency
1. Verify that there are no important clients stuck on the old version with no
easy way to upgrade
- Corrade's root `CMakeLists.txt` (and `UseCorrade.cmake`) contains
checks for minimal CMake and compiler version, together with a comment
explaining which distribution / system has the minimal version.
2. In case of CMake:
- it's usually possible to jump more than one version, check what's the
version on the oldest supported system
- bump all @cmake cmake_minimum_required() @ce in all repos
- remove @cmake cmake_policy() @ce calls that are not needed anymore
- remove old workarounds, check changelogs for functionality that can be
used now
- update building docs to say what version is required now
- add an entry to the dependencies section in `doc/changelog.dox`
- update `package/ci/``*.yml` to download a newer version, possibly
removing 32-bit compat libraries
3. In case of a compiler:
- remove everything related to `CORRADE_GCCXY_COMPATIBILITY` of the old
version, if applicable
- update building docs to say what version is required now
- add an entry to the dependencies section in `doc/changelog.dox`
- update files in `package/ci/` to use a newer version
4. In case given dependency is external:
- Create a dedicated `Find*.cmake` module and does not have a builtin one
in CMake
- update packages in `package/` to depend on the new library
- update files in `package/ci/` to install it
5. In case given dependency is single-file:
- verify it's reasonably small (&lt;50kB is okay, `nlohmann/json` is a
prime example of *not okay*)
- add it to `src/external/` without any modifications except for trailing
whitespace cleanup
- add it in a separate Git commit, mentioning its version (or Git hash)
for easier upgrades later
6. Update `CREDITS.md` of affected repo to mention the added/removed
dependency, its homepage and its license
In order to remove a dependency, be sure to touch all places mentioned above,
only in inverse.
@section developers-port Checklist for adding or removing a port
1. Add a new `TARGET_*` variable:
- to root `CMakeLists.txt`, which either gets enabled automatically based
on system introspection or is exposed through an @cmake option() @ce
command
- to the list of variables extracted out of `configure.h` in
`modules/FindMagnum.cmake`
2. Add a `MAGNUM_TARGET_*` variable:
- set it in root `CMakeLists.txt` in case `TARGET_*` is enabled
- add it as a @cpp #cmakedefine @ce macro to `src/Magnum/configure.h.cmake`
- add documentation for it to `src/Magnum/Magnum.h`
- mention it in `modules/FindMagnum.cmake` docs
- mention it in `doc/cmake.dox` and `doc/building.dox`
3. Add a new Travis / AppVeyor matrix build for this port (or update existing)
4. Add a new `PKGBUILD-*` file in `package/archlinux` for testing (or update
existing)
5. Enable or disable functionality using @cmake if(MAGNUM_TARGET_*) @ce in
CMake and @cpp #ifdef MAGNUM_TARGET_* @ce in C++
6. Mention the new stuff in `doc/changelog.dox`
7. Push to a temporary branch (e.g., `next`)
8. Iterate until the CIs are green
9. Merge to `master`
In order to remove a port, be sure to touch all places mentioned above, only in
inverse.
@section developers-bootstrap Checklist for updating the bootstrap repo
1. Check out the `_modules_` branch and update files in `modules/`
2. Check out the `_modules_sdl2_` branch, merge `_modules_` to it, update
remaining files in `modules/`
3. Check out the `_modules_es_` branch, merge `_modules_sdl2_` to it, update
remaining files in `modules/`
4. Check out all other (non-underscored) branches one by one
- use @cb{.sh} git branch --list -v @ce to keep track
- merge proper `_modules_*` branches to them, fix potential file deletion
conflicts
- update `toolchain` submodule, if present
5. Push all branches
6. Trigger build on `master`, update the `README.md` or files in `package/ci`
if necessary
@section developers-copyright-year Checklist for updating copyright year
1. Verify there are no uncommitted changes in any repos, as that would
significantly complicate reverting a potential fuck-up
2. Use [msrp](https://github.com/malex984/msrp) to batch replace copyright
info in all files, replacing existing `Copyright © ...` with
`Copyright © ..., 20XZ` in the root directory of every project, so nothing
gets left out
- If the line gets over 79 characters, wrap the name on the new line
where the first letter is aligned under the `©`
3. Examples use partially MIT (mainly in docs) and partially UNLICENSE,
replace `... —` with `..., 20XZ —` there as well
4. Copy all `Find*.cmake` modules to dependent projects to update the
copyright year in these as well
5. Update other occurrences by hand:
- `COPYING`
- `doc/conf.py`
- `doc/mainpage.dox`
- `package/debian/copyright`
- All flextGL `*.template` files in `src/external/OpenGL` and
`src/external/Vulkan` because wheezy template needs the `@` escaped to
`@@`
6. Use @cb{.sh} git diff @ce to verify the change went well and the new year
is specified exactly once everywhere
7. Do a local verification build, push to `master`
@section developers-documentation Checklist for uploading documentation
1. (Optionally) remove `build/doc-public` to get rid of stale files
2. Verify there are no untracked files, modifications or branches different
than `master` checked out that could mess up the docs
3. Run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-public`,
look for suspicious warnings
4. Upload contents of `build/doc-public/html/` to `doc/magnum-new/` and remove
`doc/magnum-old/` if any
5. Once the upload is finished, rename `doc/magnum/` to `doc/magnum-old/` and
`doc/magnum-new/` to `doc/magnum/`
6. Quickly check that the docs still look as they should, if not, revert the
backup and try again
@section developers-pr Checklist for merging a PR
1. After the public round of review, pull the changes locally to a temporary
branch (i.e., `next`)
2. Verify a coverage build, verify that there are no compiler warnings
3. Go over and fix issues that slipped through cracks in the public review
4. Verify the contributor is mentioned in all relevant license headers, add if
necessary
5. Add the contributor to `CREDITS.md`, if not already there
6. Update `doc/changelog.dox` (and similar files in other repos), if not
already done
7. @ref building-doc "Build documentation:
- run [doxygen.py](http://mcss.mosra.cz/doxygen/) on `Doxyfile-mcss`
and verify there are no new warnings
- eyeball the relevant docs and fix suspicious things
8. Push to a temporary branch (e.g., `next`)
9. Iterate until the CIs are green
10. Merge to `master`, put a "thank you" comment to the PR, explaining
additional changes if necessary
@section developers-release Checklist for making a release
1. Open a new `20XY.ac` milestone
2. Verify that there are no blocking issues in the current (`20XY.ab`)
milestone, either fix them or move to the next milestone
3. Verify that all CIs are green
4. Go through `doc/changelog.dox` and update it, in case it doesn't contain
all changes (use `gitk` to check when it was last updated)
5. Go through fixed issues and merged PRs and add either a
@m_span{m-label m-success m-flat} changelog mention added @m_endspan (and
add a mention to the changelog), @m_span{m-label m-danger m-flat} scrapped @m_endspan
or @m_span{m-label m-dim m-flat} no action needed @m_endspan label to wrap
them up
- Don't forget about the bootstrap repository and toolchains as well
6. Go through merged PRs (and the *most important* issues) and add new people
to `dox/credits.md` (and similar files in other repositories) and
https://magnum.graphics/about/ , if they are not there yet
7. Update changelog for the next release:
- change section names for the latest release from `latest` to `20XY-ab`
- change the title from `Changes since 20XY.aa` to `20XY.ab`
- add a paragraph stating date of release and referencing the to-be-added
tag on GitHub
- add a temporary <tt>\@<b></b>anchor changelog-latest</tt> (and
equivalent in other repos) on top so the links from main page work
properly
8. Convert all occurrences of
- <tt>\@m_since_latest_{thing}</tt> to <tt>\@m_since_{thing,20XY,ab}</tt>
- <tt>\@m_since_latest</tt> to <tt>\@m_since{20XY,ab}</tt>
- <tt>\@m_deprecated_since_latest_{thing}</tt> to
<tt>\@m_deprecated_since_{thing,20XY,ab}</tt>
- <tt>\@m_deprecated_since_latest</tt> to
<tt>\@m_deprecated_since{20XY,ab}</tt>
9. Bump `MAGNUM*_LIBRARY_VERSION`, `MAGNUM*_LIBRARY_SOVERSION`
`MAGNUM*_VERSION_YEAR` and `MAGNUM*_VERSION_MONTH` in all projects. Ensure
all projects have the exact same version.
10. Rebuild all projects with the new shared library version numbers, verify
all tools and examples still behave properly
11. Build and upload public docs (see @ref developers-documentation), verify
that there are no new warnings and the changelog looks correct
12. Push all new changes to a temporary branch (e.g., `next`), don't forget the
`ports` branch in examples
13. Wait for the CIs to get green
14. Update `conanfile.py` in all projects that have it with a new version ---
this *has to be* done before the version is tagged.
15. Update Debian package changelog in `package/debian/changelog`, copypasting
the last entry, updating it and using @cb{.sh} date -R @ce for a date ---
again, this *should be* done before the version is tagged so stable
releases in PPAs can be done directly from the tag with no extra patching
16. Tag a new version using @cb{.sh} git tag -a v20XY.ab @ce, say just
`Version 20XY.ab` as a message
17. Push the tag, verify that the CIs are still green; if not, retry and tag
again
- to GitLab as well
18. Regenerate singles with changelogs for what changed *and only then*
commit the changelog updates so the generated singles refer to the actual
tag
19. Update the Corrade and Magnum tagfiles on the website using the
freshly-built *public* docs
20. Write a release announcement for the blog
- highlight the most prominent features, mention detailed blog posts
about them, if any
- reference detailed changelogs for all projects at the end
- don't forget to say thanks to significant contributors
- create some fancy eye-catchy cover image featuring nice screenshots of
new functionality
- add release annoucement link under the button on front page
21. Publish the release announcement, verify it looks correct
22. Advertise the release announcement, preferably Monday 5 PM, never Friday
or weekends
- come up with some 100-character-long extended title
- Twitter (extended title + url and some hashtags), first dry-run the
link on https://cards-dev.twitter.com/validator to ensure the cover
image gets displayed
- GitHub Release Radar (releaseradar@github.com)
- Reddit `r/cpp`, `r/gamedev`, `r/webassembly`, `r/vulkan`, `r/webgl`,
`r/gltf`; Hacker News (extended title + url)
- summarize the release to mailing list
- summarize the release highlighting GL- and Vulkan-related functionality
and submit that to Khronos, with a 500x500 downsized cover image
- send an e-mail to companies and universities on the private list
- add a message to the Gitter chat (title as heading, cover image,
summary in a blockquote and "read more" link, `@` contributors)
23. Reference Twitter, Reddit, Hacker News and mailing list in a "Discussion"
note at the end of the article, reupload that change
24. Update versions of ArchLinux AUR packages:
- run `makepkg` in `package/archlinux/magnum*-git`, verify it builds and
says correct version, ideally with `r0` at the end
- copy the updated `PKGBUILD` to the AUR package repo, run
@cb{.sh} makepkg --printsrcinfo > .SRCINFO @ce there
- commit the updated `PKGBUILD` and `.SRCINFO`, push
- after pushing all, verify that the version is updated in the AUR web
interface as well
25. Update Homebrew package versions
26. Ask someone to update the Ubuntu PPA
27. Ask someone to update Vcpkg packages
28. Close the 20XY.ab GitHub milestone
29. Add link to the release notes to the tag on GitHub
30. Have a drink and take two days off
*/
}