Skip to content

API stability

Giovanni Bajo edited this page Jul 7, 2024 · 12 revisions

The stable branch guarantees API stability "forever". The idea is that if you build your ROM against libdragon stable, we will strive to make sure that your ROM will build against newer libdragon versions as well.

General overview

The API stability guarantees covers:

  • Public functions, as exposed by libdragon headers and documented in the reference manual. Libdragon will not change the prototype of the functions in a way that make calling code not work anymore (eg: adding a parameter). It might sometimes make changes to them as long as it is backwards compatible (eg: a int parameter could be changed to float in the future, as this is deemed to be a backward compatibile change).
  • Public structures, as exposed by libdragon headers. Libdragon will not rename or delete a field of the public structures. We instead reserve the right instead add more fields, or reorder them, so some care must be taken while filling them. See below for some examples.
  • Asset conversion tools. Tools like mksprite, audioconv64, etc. are guaranteed to change only in a backward compatible way. This means that existing command line options will not be removed.

Rules to follow

To benefit from API stability in the stable branch, follow these simple rules:

  • Include libdragon.h only. libdragon.h brings in the whole libdragon API, so no other libdragon include is necessary. Do not include other header files such as display.h, rsp.h, etc., as these might get renamed, removed, or rearranged in the future.
  • Only use public APIs. Libdragon public APIs are those exposed via libdragon.h and documented in the reference manual. Sometimes, header files expose other symbols for internal purposes, that are clearly marked as such with code comments, and specifically hidden from the reference manual. Those symbols are not part of the public API and should not be used as they could go away at any time.
  • Use a Makefile including n64.mk, like examples do. Some people prefer to use other build systems but unfortunately N64 is an embedded system and building a ROM includes spawning many different external tools during build, with specific rules. n64.mk is our own "build system" that describes exactly what needs to be done, and it is updated as libdragon progresses over years. If you manage to build your ROM by copying what n64.mk does today into your own favorite build system, this will break in the future when we change n64.mk (because maybe we changed an internal tool to accept different command line arguments, added another build step, or whatnot).
  • Commit original assets, not converted ones. For instance, for sprites and textures, commit into your repository the original PNG files, not the converted .sprite files. Libdragon consider all its proprietary formats as not part of its public API, so their binary content can change at any time. If you commit a .sprite file, a future Libdragon might not be able to open and parse it correctly anymore. If you instead commit the PNG file, the API stability guarantees that mksprite will always be able to convert it.
    • Note that this applies to asset compression formats too. Libdragon can change the compression formats at any time in the future, so in case you want to use libdragon compression over your own binary assets (via mkasset), make sure to commit the original, uncompressed file, not the compressed one.
  • Use designated initializers for C structures. When initializing a structure defined by libdragon, make sure to use designated initializer to specify the value of one or multiple members of the structure. For instance:
resolution_t res = { .width = 320, .height = 240, .interlace=false };
display_init(res, ...);

// or you can do that inline if you prefer
display_init((resolution_t){.width=320, .height=240, .interlace=false}, ...);

This allows libdragon maintainers to add more fields to the structure (as long as 0 is a good, backward compatible default for them), and freely reorder fields in the definition. Using other approaches might create problems in the future. For instance:

// DO NOT DO THIS. All fields not mentioned in your code will be uninitialized causing undefined behavior.
// This will make it impossible to libdragon authors to add more fields to the structure.
resolution_t res;
res.width = 320; 
res.height = 240;
res.interlace = false;
display_init(res, ...);
// DO NOT DO THIS. This would make it impossible to libdragon authors to reorder fields in the structure, which
// is sometimes needed.
resolution_t res = {320, 240, false};
display_init(res, ...);

Clone this wiki locally