Developers guide

Checklists for developing new things in Magnum itself.

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.

Checklist for adding / removing a library

  1. Add a WITH_LIBRARYNAME CMake option to:
    • root CMakeLists.txt (if it has some inter-library dependencies, update the others / convert them to cmake_dependent_option(), adding NOT 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 elseif(_component STREQUAL LibraryName) section with special setup of includes or dependencies or explicitly say # No special setup for LibraryName library
  3. Add the library to the list in doc/cmake.dox (or similar files in other repos)
  4. Add a conditional add_subdirectory() 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. CORRADE_NO_ASSERT 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 add_library() command references all input files (needed so QtCreator lists all project files properly)
    • verify that debug postfix is set (set_target_properties(MagnumLibraryName PROPERTIES DEBUG_POSTFIX "-d"))
    • verify that folder is set for all libraries and OBJECT libraries to avoid cluttering project tree view in IDEs (set_target_properties(MagnumLibraryName PROPERTIES FOLDER "Magnum/LibraryName"))
    • verify that target installation is done in proper places (separate RUNTIME / LIBRARY / ARCHIVE destinations)
    • verify that set_target_properties(MagnumLibraryName PROPERTIES VERSION ${MAGNUM_LIBRARY_VERSION} SOVERSION ${MAGNUM_LIBRARY_SOVERSION}) is done in case BUILD_STATIC is not set
    • verify that set_target_properties(MagnumLibraryName PROPERTIES POSITION_INDEPENDENT_CODE ON) is done in case BUILD_STATIC_PIC is set
    • verify that add_library(Magnum::LibraryName ALIAS MagnumLibraryName) (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
    • conditionally add_subdirectory() it if 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 Forward declarations for the @ref Magnum::LibraryName namespace as brief docs
  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 #ifdef MagnumLibraryName_EXPORTS so it matches CMake target name
    • if the library is combined from an OBJECT library, add its name to the above #ifdef as well (and then explicitly add target_compile_definitions(MagnumLibraryNameObjects PRIVATE "MagnumLibraryNameObjects_EXPORTS") to CMakeLists.txt in case 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 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 Checklist for adding / removing a new source / header file and Checklist for adding / removing a symbol for more information
  11. Add the WITH_LIBRARYNAME option to all files in package/ directory, explicitly saying either ON or OFF based on platform support:
    • all package/archlinux/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!)
    • all package/ci/appveyor-*.bat files (^ is a line continuation)
    • all package/ci/travis-*.sh files (\ is a line continuation)
  12. 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 Travis downloads them (based on platform support)
  13. Mention the library in doc/changelog.dox (or similar files in other repos)
  14. Build documentation:
    • run dox2html5.py 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
  15. Build a coverage build (package/archlinux/PKGBUILD-coverage), or abuse the CI for that later
  16. Push to a temporary branch (e.g., next)
  17. Iterate until the CIs are green and the code coverage is good enough
  18. Merge to master

In order to remove a library, be sure to touch all places mentioned above, only in inverse — but usually deprecate first.

Checklist for adding / removing an application library

Similarly to Checklist for adding / removing a library except points 2 and 5, with:

  1. Update FindMagnum.cmake (replaces point 2 in Checklist for adding / removing a 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 elseif(_component STREQUAL ApplicationName) section with special setup of includes or dependencies or explicitly say # Name application has no additional dependencies
  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 add_library() command references all input files (needed so QtCreator lists all project files properly)
    • verify that debug postfix is set (set_target_properties(MagnumApplicationName PROPERTIES DEBUG_POSTFIX "-d"))
    • verify that folder is set to avoid cluttering project tree view in IDEs (set_target_properties(MagnumApplicationName PROPERTIES FOLDER "Magnum/Platform"))
    • verify that target installation is done in proper places (separate RUNTIME / LIBRARY / ARCHIVE destinations)
    • verify that add_library(Magnum::ApplicationName ALIAS MagnumApplicationName) 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 deprecate first.

Checklist for adding / removing a plugin

Similarly to Checklist for adding / removing a library except points 2 and 5, with:

  1. Update FindMagnumPlugins.cmake (or FindMagnum.cmake in the core repo) (replaces point 2 in Checklist for adding / removing a 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 elseif(_component STREQUAL PluginName) section with special setup of includes or dependencies or explicitly say # PluginName has no dependencies
  2. Create PluginName.conf and list all plugin dependencies (if any). The file has to be present even if empty.
  3. 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.
  4. Create configure.h.cmake for plugin-specific information about whether the library was built as static or not
  5. 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 Checklist for adding / removing a 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 add_plugin() command (which is aliased to either corrade_add_plugin() or 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 add_library() and add_plugin() 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 (set_target_properties(PluginExtraTarget PROPERTIES FOLDER "MagnumPlugins/PluginName")) — for the plugin library it's done automatically inside add_plugin()
    • verify that set_target_properties(PluginName PROPERTIES POSITION_INDEPENDENT_CODE ON) is done in case BUILD_STATIC_PIC is set
    • verify that in case of BUILD_PLUGINS_STATIC the importStaticPlugin.cpp file is installed is set and that an absolute* path to it is added to target_sources()
    • verify that add_library(MagnumPlugins::PluginName ALIAS PluginName) (or equivalent) is added to make the library visible for CMake subprojects
  6. 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.
  7. If the plugin handles a new format:

In order to remove a plugin, be sure to touch all places mentioned above, only in inverse — but usually deprecate first.

Checklist for adding / removing a plugin interface

In order to remove a plugin interface, be sure to touch all places mentioned above, only in inverse — but usually deprecate first.

Checklist for adding / removing a tool

In order to remove a tool, be sure to touch all places mentioned above, only in inverse — but usually deprecate first.

Checklist for adding / removing an example

  1. Add a 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_minimum_required(), project() and all cmake_policy() 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 @brief, @m_footernavigation and @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 - @ref example-name/file.ext "file.ext"
    • breadcrumb and navigation setup for all example sources as @example example-name/file.ext @m_examplenavigation{examples-example-name,example-name/} @m_footernavigation
  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.

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 @file-level documentation block, with @brief listing all classes, functions, typedefs, enums, macros etc. that are in the file
  3. Add the file to corresponding *_SRCS, *_HEADERS, *_PRIVATE_HEADERS list in CMakeLists.txt
  4. 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 corrade_add_test() to add it to tests
    • if some tests need GL context, add a separate test with GLTest suffix, wrapping the corresponding corrade_add_test() in if(BUILD_GL_TESTS)
  5. Populate the file, see Checklist for adding / removing a symbol and Coding style for more information.
  6. Mention the new functionality in doc/changelog.dox (and similar files in other repos)
  7. Build documentation:
    • run dox2html5.py on Doxyfile-mcss and verify there are no new warnings
    • eyeball the relevant docs and fix suspicious things
  8. Build a coverage build (package/archlinux/PKGBUILD-coverage), or abuse the CI for that later
  9. Push to a temporary branch (e.g., next)
  10. Iterate until the CIs are green and the code coverage is good enough
  11. Merge to master

In order to remove a file, be sure to touch all places mentioned above, only in inverse — but usually deprecate first.

Checklist for adding / removing a symbol

  1. If the symbol is standalone (i.e., not member of a class), list it in the @file-level @brief docs
  2. Document it
  3. Add a test for it to corresponding file, verify the test gets actually run
  4. Mention the new functionality in doc/changelog.dox (and similar files in other repos)
  5. Build documentation:
    • run dox2html5.py on Doxyfile-mcss and verify there are no new warnings
    • eyeball the relevant docs and fix suspicious things
  6. Build a coverage build (package/archlinux/PKGBUILD-coverage), or abuse the CI for that later
  7. Push to a temporary branch (e.g., next)
  8. Iterate until the CIs are green and the code coverage is good enough
  9. Merge to master

In order to remove a symbol, be sure to touch all places mentioned above, only in inverse — but usually deprecate first.

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 @subpage in its parent page and add @m_footernavigation for automatic linking to parent and prev/next pages
  4. Add a @brief documentation, if applicable
  5. Populate it, see Coding style for more information
  6. Mention the new page in doc/changelog.dox (and similar files in other repos)
  7. Build documentation:
    • run dox2html5.py on Doxyfile-mcss and verify there are no new warnings
    • eyeball the relevant docs and fix suspicious things
  8. Push to master

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 typedef / using for a renamed symbol, marking it with CORRADE_DEPRECATED() / CORRADE_DEPRECATED_ALIAS()
    • Add a compatibility header for a renamed include, including the original file from it and marking it with 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 CORRADE_DEPRECATED()
    • Add a compatibility enum value for a value that got renamed or deleted, mark it with 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 @brief @copybrief from the replacement functionality together with a @deprecated line to the deprecated feature
  3. Reference the replacement functionality in both the deprecation macro and in the @deprecated line to make porting easier
  4. Ensure the deprecated symbol is wrapped in #ifndef MAGNUM_BUILD_DEPRECATED,
  5. Ensure deprecated files #error 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. Build documentation:
    • run dox2html5.py 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

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 CORRADE_DEPRECATED() macros, with a shorter note mentioning alternatives
    • ensure each public headers (transitively) contains exactly one 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 #ifndef _MAGNUM_DO_NOT_WARN_DEPRECATED_LIBRARYNAME and #define this macro in all *.cpp files and tests to avoid spamming the compiler log
    • an #error to each header file in case MAGNUM_BUILD_DEPRECATED is not enabled
    • wrap contents of every header, source and test file in CORRADE_IGNORE_DEPRECATED_PUSH and CORRADE_IGNORE_DEPRECATED_POP to avoid warnings when compiling the library itself (no, this doesn't disable warnings for library users)
    • a message(FATAL_ERROR) to corresponding CMakeLists.txt in case MAGNUM_BUILD_DEPRECATED is not enabled
    • a deprecated label next to the 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 MAGNUM_BUILD_DEPRECATED is enabled.
  5. Remove the deprecated library from all packages except developer PKGBUILDs 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 MAGNUM_BUILD_DEPRECATED is enabled
    • update corresponding Find modules to require dependency on this library only if MAGNUM_BUILD_DEPRECATED is enabled
  7. Verify no CIs in dependent projects have this library enabled. If they do, it should be only if 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)

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 #ifndef MAGNUM_BUILD_DEPRECATED, 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. Build documentation:
    • run dox2html5.py 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)

Checklist for adding / removing GL versions and extensions

  1. Install flextGL
  2. Go to src/MagnumExternal/OpenGL/GL/:
    • Update extensions.txt (bump a version or add/remove extensions)
    • Run .../flextGLgen.py -D . -t . extensions.txt to generate flextGL.h, flextGL.cpp and flextGLPlatform.cpp files
  3. Go to src/MagnumExternal/OpenGL/GLES2/:
    • Update extensions.txt and Emscripten/extensions.txt (add/remove extensions)
    • Run .../flextGLgen.py -D . -t . extensions.txt to generate flextGL.h, flextGL.cpp, flextGLPlatform.cpp, flextGLWindowsDesktop.h, flextGLWindowsDesktop.cpp, flextGLPlatformWindowsDesktop.cpp and flextGLPlatformIOS.cpp files. 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.
    • Run .../flextGLgen.py -D . -t Emscripten/ Emscripten/extensions.txt to generate a stripped-down flextGLEmscripten.h file. Emscripten doesn't have the ability to manually load extension pointers, thus it has only header files.
  4. Go to src/MagnumExternal/OpenGL/GLES3/:
    • Update extensions.txt and Emscripten/extensions.txt (bump a version or add/remove extensions)
    • Run .../flextGLgen.py -D . -t . extensions.txt to generate flextGL.h, flextGL.cpp, flextGLPlatform.cpp, flextGLWindowsDesktop.h, flextGLWindowsDesktop.cpp, flextGLPlatformWindowsDesktop.cpp and flextGLPlatformIOS.cpp files. See above why there are so many.
    • Run .../flextGLgen.py -D . -t Emscripten/ Emscripten/extensions.txt to generate a stripped-down flextGLEmscripten.h file. See above for details.
  5. Check git diff for suspicious changes and whitespace-at-EOL
  6. For every new added function, add an entry to doc/opengl-mapping.dox
  7. For every new added limit query (various GL_MIN_* and GL_MAX_* macros etc.), add an entry to the bottom of doc/opengl-mapping.dox
  8. 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.
  9. Add a new requires-glXY, requires-glesXY or requires-webglXY page with @m_footernavigation to doc/opengl-support.dox, mention it as a @subpage at a correct position in the list
  10. 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
  11. Add new version enum value:
    • to src/Magnum/GL/Version.h
    • to debug output in src/Magnum/GL/Version.cpp
    • to GL::Extension::extensions() in src/Magnum/GL/Context.cpp
    • to GL::Context::tryCreate() 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
  12. Add new extensions to src/Magnum/GL/Extensions.h
    • order them by extension ID that is mentioned in every extension spec file
    • 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, Implementation::ExtensionCount might needed to be increased
    • run ContextTest to verify everything is still okay
  13. Update existing extensions with version in which they become core (last parameter of the _extension() macro)
  14. Update extension list in src/magnum/GL/Context.cpp according to changes in src/Magnum/GL/Extensions.h

In order to remove GL functionality, be sure to touch all places mentioned above, only in inverse — but usually deprecate first, unless it doesn't affect public API at all.

Checklist for adding / removing GL functionality

  1. Check if given desktop functionality has equivalent in ES or WebGL, add missing extensions if needed (see Checklist for adding / removing GL versions and 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 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 #ifdef MAGNUM_TARGET_GLES, #ifdef MAGNUM_TARGET_GLES2 and #ifdef MAGNUM_TARGET_WEBGL 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, preferrably static
    • 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 Context::current().state().some->thingImplementation in the implementation
  5. If the functionality is a limit query, add a cache for it:
    • a member variable that's either set to 0 or 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 (0) in that case
  6. Implement the functionality (see Checklist for adding / removing a new source / header file, Checklist for adding / removing a symbol)
  7. Document the functionality
  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. Build documentation:
    • run dox2html5.py on Doxyfile-mcss and verify there are no new warnings
    • eyeball the relevant docs and fix suspicious things
  12. Build and test for relevant platforms locally (as the public CI can't test GL things yet)
  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 deprecate first, unless it doesn't affect public API at all.

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 apropriate #ifdef around it
  3. Create (or extend) a pair of (member) private MAGNUM_LOCAL *Implementation*() functions in the affected class, *ImplementationDefault() having the optimistic default behavior, the other having the workaround. Add the appropriate #ifdef 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 #ifdef around, if any.
  5. Add a branch into src/GL/Implementation/SomeState.cpp (with appropriate #ifdef around, if any). First check for driver and other circumstances and call the !context.isDriverWorkaroundDisabled("the-workaround-string") last 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 Driver workarounds

Removeing a workaround is simply a matter of searching for its string, removing all occurences 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.

Checklist for adding / removing OpenAL versions and extensions

In order to remove OpenAL functionality, be sure to touch all places mentioned above, only in inverse — but usually deprecate first, unless it doesn't affect public API at all.

Checklist for adding / removing OpenAL functionality

In order to remove OpenAL functionality, be sure to touch all places mentioned above, only in inverse — but usually deprecate first, unless it doesn't affect public API at all.

Checklist for adding / removing Vulkan versions and extensions

In order to remove Vulkan functionality, be sure to touch all places mentioned above, only in inverse — but usually deprecate first, unless it doesn't affect public API at all.

Checklist for adding / removing Vulkan functionality

In order to remove Vulkan functionality, be sure to touch all places mentioned above, only in inverse — but usually deprecate first, unless it doesn't affect public API at all.

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
  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_minimum_required() in all repos
    • remove cmake_policy() 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/travis.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 (<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.

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 option() 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 #cmakedefine 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 if(MAGNUM_TARGET_*) in CMake and #ifdef MAGNUM_TARGET_* 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.

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 git branch --list -v 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

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 dox2html5.py 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

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. Build documentation:
    • run dox2html5.py 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

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 changelog mention added (and add a mention to the changelog), scrapped or no action needed label to wrap them up
  6. Go through merged PRs (and the most important issues) and add new people to CREDITS.md 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 @anchor changelog-latest (and equivalent in other repos) on top so the links from main page work properly
  8. Bump MAGNUM_LIBRARY_VERSION and MAGNUM_LIBRARY_SOVERSION in all projects, if needed — ensure all projects have the exact same version
  9. Rebuild all projects with the new shared library version numbers, verify all tools and examples still behave properly
  10. Build and upload public docs (see Checklist for uploading documentation), verify that there are no new warnings and the changelog looks correct
  11. Push all new changes to a temporary branch (e.g., next), don't forget the ports branch in examples
  12. Wait for the CIs to get green
  13. Tag a new version using git tag -a v20XY.ab, say just Version 20XY.ab as a message
  14. Push the tag, verify that the CIs are still green
    • to GitLab as well
  15. Update the Corrade and Magnum tagfiles on the website using the freshly-built public docs
  16. 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
  17. Publish the release announcement, verify it looks correct
  18. Advertise the release announcement, preferrably 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)
  19. Reference Twitter, Reddit, Hacker News and mailing list in a "Discussion" note at the end of the article, reupload that change
  20. 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 ennd
    • copy the updated PKGBUILD to the AUR package repo, run makepkg --printsrcinfo > .SRCINFO there
    • commit the updated PKGBUILD and .SRCINFO, push
    • after pushing all, verify that the version is updated in the AUR web interface as well
  21. Update Debian package changelog in package/debian/changelog, copypasting the last entry, updating it and using the Git tag date+time for it (note that the date format is slightly different)
  22. Update Homebrew package versions
  23. Ask someone to update the Ubuntu PPA
  24. Ask someone to update Vcpkg packages
  25. Close the 20XY.ab GitHub milestone
  26. Add link to the release notes to the tag on GitHub
  27. Have a drink and take two days off