gnunet-handbook

The GNUnet Handbook
Log | Files | Refs

style.rst (20483B)


      1 .. _dev-style-workflow:
      2 
      3 *******************
      4 Style and Workflow
      5 *******************
      6 
      7 This document contains normative rules for writing GNUnet
      8 code and naming conventions used throughout the project.
      9 
     10 Coding style
     11 ============
     12 
     13 This project follows the GNU Coding Standards.
     14 
     15 Indentation is done with two spaces per level, never with tabs.
     16 Specific (though incomplete) indentation rules are defined in an ``uncrustify``
     17 configuration file (in ``contrib/uncrustify.cfg``) and are enforced by Git hooks.
     18 
     19 C99-style struct initialisation is acceptable and generally encouraged.
     20 
     21 As in all good C code, we care about symbol space pollution and thus use
     22 :code:`static` to limit the scope where possible, even in the compilation
     23 unit that contains :code:`main`.
     24 
     25 Only one variable should be declared per line:
     26 
     27 .. code-block:: c
     28 
     29    // bad
     30    int i,j;
     31 
     32    // good
     33    int i;
     34    int j;
     35 
     36 This helps keep diffs small and forces developers to think precisely about
     37 the type of every variable.
     38 
     39 Note that :c:`char *` is different from :c:`const char*` and
     40 :c:`int` is different from :c:`unsigned int` or :c:`uint32_t`.
     41 Each variable type should be chosen with care.
     42 
     43 
     44 While ``goto`` should generally be avoided, having a ``goto`` to the
     45 end of a function to a block of clean up statements (free, close,
     46 etc.) can be acceptable.
     47 
     48 Conditions should be written with constants on the left (to avoid
     49 accidental assignment) and with the ``true`` target being either the
     50 ``error`` case or the significantly simpler continuation. For
     51 example:
     52 
     53 ::
     54 
     55       if (0 != stat ("filename,"
     56                      &sbuf))
     57       {
     58         error();
     59       }
     60       else
     61       {
     62         /* handle normal case here */
     63       }
     64 
     65 instead of
     66 
     67 ::
     68 
     69       if (stat ("filename," &sbuf) == 0) {
     70         /* handle normal case here */
     71        } else {
     72         error();
     73        }
     74 
     75 If possible, the error clause should be terminated with a ``return``
     76 (or ``goto`` to some cleanup routine) and in this case, the ``else``
     77 clause should be omitted:
     78 
     79 ::
     80 
     81       if (0 != stat ("filename",
     82                      &sbuf))
     83       {
     84         error();
     85         return;
     86       }
     87       /* handle normal case here */
     88 
     89 This serves to avoid deep nesting. The 'constants on the left' rule
     90 applies to all constants (including. ``GNUNET_SCHEDULER_NO_TASK``),
     91 NULL, and enums). With the two above rules (constants on left, errors
     92 in 'true' branch), there is only one way to write most branches
     93 correctly.
     94 
     95 Combined assignments and tests are allowed if they do not hinder code
     96 clarity. For example, one can write:
     97 
     98 ::
     99 
    100       if (NULL == (value = lookup_function()))
    101       {
    102         error();
    103         return;
    104       }
    105 
    106 Use ``break`` and ``continue`` wherever possible to avoid deep(er)
    107 nesting. Thus, we would write:
    108 
    109 ::
    110 
    111       next = head;
    112       while (NULL != (pos = next))
    113       {
    114         next = pos->next;
    115         if (! should_free (pos))
    116           continue;
    117         GNUNET_CONTAINER_DLL_remove (head,
    118                                      tail,
    119                                      pos);
    120         GNUNET_free (pos);
    121       }
    122 
    123 instead of
    124 
    125 ::
    126 
    127       next = head; while (NULL != (pos = next)) {
    128         next = pos->next;
    129         if (should_free (pos)) {
    130           /* unnecessary nesting! */
    131           GNUNET_CONTAINER_DLL_remove (head, tail, pos);
    132           GNUNET_free (pos);
    133          }
    134         }
    135 
    136 We primarily use ``for`` and ``while`` loops. A ``while`` loop is
    137 used if the method for advancing in the loop is not a straightforward
    138 increment operation. In particular, we use:
    139 
    140 ::
    141 
    142       next = head;
    143       while (NULL != (pos = next))
    144       {
    145         next = pos->next;
    146         if (! should_free (pos))
    147           continue;
    148         GNUNET_CONTAINER_DLL_remove (head,
    149                                      tail,
    150                                      pos);
    151         GNUNET_free (pos);
    152       }
    153 
    154 to free entries in a list (as the iteration changes the structure of
    155 the list due to the free; the equivalent ``for`` loop does no longer
    156 follow the simple ``for`` paradigm of ``for(INIT;TEST;INC)``).
    157 However, for loops that do follow the simple ``for`` paradigm we do
    158 use ``for``, even if it involves linked lists:
    159 
    160 ::
    161 
    162       /* simple iteration over a linked list */
    163       for (pos = head;
    164            NULL != pos;
    165            pos = pos->next)
    166       {
    167          use (pos);
    168       }
    169 
    170 The first argument to all higher-order functions in GNUnet must be
    171 declared to be of type ``void *`` and is reserved for a closure. We
    172 do not use inner functions, as trampolines would conflict with setups
    173 that use non-executable stacks. The first statement in a higher-order
    174 function, which unusually should be part of the variable
    175 declarations, should assign the ``cls`` argument to the precise
    176 expected type. For example:
    177 
    178 ::
    179 
    180       int
    181       callback (void *cls,
    182                 char *args)
    183       {
    184         struct Foo *foo = cls;
    185         int other_variables;
    186 
    187          /* rest of function */
    188       }
    189 
    190 As shown in the example above, after the return type of a function
    191 there should be a break. Each parameter should be on a new line.
    192 
    193 It is good practice to write complex ``if`` expressions instead of
    194 using deeply nested ``if`` statements. However, except for addition
    195 and multiplication, all operators should use parens. This is fine:
    196 
    197 ::
    198 
    199       if ( (1 == foo) ||
    200            ( (0 == bar) &&
    201              (x != y) ) )
    202         return x;
    203 
    204 However, this is not:
    205 
    206 ::
    207 
    208       if (1 == foo)
    209         return x;
    210       if (0 == bar && x != y)
    211         return x;
    212 
    213 Note that splitting the ``if`` statement above is debatable as the
    214 ``return x`` is a very trivial statement. However, once the logic
    215 after the branch becomes more complicated (and is still identical),
    216 the \"or\" formulation should be used for sure.
    217 
    218 There should be two empty lines between the end of the function and
    219 the comments describing the following function. There should be a
    220 single empty line after the initial variable declarations of a
    221 function. If a function has no local variables, there should be no
    222 initial empty line. If a long function consists of several complex
    223 steps, those steps might be separated by an empty line (possibly
    224 followed by a comment describing the following step). The code should
    225 not contain empty lines in arbitrary places; if in doubt, it is
    226 likely better to NOT have an empty line (this way, more code will fit
    227 on the screen).
    228 
    229 When command-line arguments become too long (and would result in some
    230 particularly ugly ``uncrustify`` wrapping), we start all arguments on
    231 a new line. As a result, there must never be a new line within an
    232 argument declaration (i.e. between ``struct`` and the struct's name)
    233 or between the type and the variable). Example:
    234 
    235 ::
    236 
    237       struct GNUNET_TRANSPORT_CommunicatorHandle *
    238       GNUNET_TRANSPORT_communicator_connect (
    239         const struct GNUNET_CONFIGURATION_Handle *cfg,
    240         const char *config_section_name,
    241         const char *addr_prefix,
    242         ...);
    243 
    244 Note that for short function names and arguments, the first argument
    245 does remain on the same line. Example:
    246 
    247 ::
    248 
    249       void
    250       fun (short i,
    251            short j);
    252 
    253 
    254 Naming conventions
    255 ==================
    256 
    257 Header files
    258 ------------
    259 .. Not sure if "include" and "header" files are synonymous.
    260 
    261 
    262 For header files, the following suffixes should be used:
    263 
    264 ============= ======================================
    265 Suffix        Usage
    266 ============= ======================================
    267 ``_lib``      Libraries without associated processes
    268 ``_service``  Libraries using service processes
    269 ``_plugin``   Plugin definition
    270 ``_protocol`` structs used in network protocol
    271 ============= ======================================
    272 
    273 There exist a few exceptions to these rules within the codebase:
    274 
    275 * ``gnunet_config.h`` is automatically generated.
    276 * ``gnunet_common.h``, which defines fundamental routines.
    277 * ``platform.h``, a collection of portability functions and macros.
    278 * ``gettext.h``, the internationalization configuration for gettext in GNUnet.
    279 
    280 
    281 Binaries
    282 --------
    283 
    284 For binary files, the following convention should be used:
    285 
    286 =============================== =========================================
    287 Name format                     Usage
    288 =============================== =========================================
    289 ``gnunet-service-xxx``          Service processes (with listen sockets)
    290 ``gnunet-daemon-xxx``           Daemon processes (without listen sockets)
    291 ``gnunet-helper-xxx[-yyy]``     SUID helper for module xxx
    292 ``gnunet-yyy``                  End-user command line tools
    293 ``libgnunet_plugin_xxx_yyy.so`` Plugin for API xxx
    294 ``libgnunetxxx.so``             Library for API xxx
    295 =============================== =========================================
    296 
    297 Logging
    298 -------
    299 
    300 The convention is to define a macro on a per-file basis to manage logging:
    301 
    302 .. code-block:: c
    303 
    304    #define LOG(kind,...)
    305    [logging_macro] (kind, "[component_name]", __VA_ARGS__)
    306 
    307 The table below indicates the substitutions which should be made
    308 for ``[component_name]`` and ``[logging_macro]``.
    309 
    310 ======================== ========================================= ===================
    311 Software category        ``[component_name]``                      ``[logging_macro]``
    312 ======================== ========================================= ===================
    313 Services and daemons     Directory name in ``GNUNET_log_setup``    ``GNUNET_log``
    314 Command line tools       Full name in ``GNUNET_log_setup``         ``GNUNET_log``
    315 Service access libraries ``[directory_name]``                      ``GNUNET_log_from``
    316 Pure libraries           Library name (without ``lib`` or ``.so``) ``GNUNET_log_from``
    317 Plugins                  ``[directory_name]-[plugin_name]``        ``GNUNET_log_from``
    318 ======================== ========================================= ===================
    319 
    320 .. todo:: Clear up terminology within the style guide (_lib, _service mapped to appropriate software categories)
    321 
    322 .. todo:: Interpret and write configuration style
    323 
    324 Symbols
    325 -------
    326 
    327 Exported symbols must be prefixed with ``GNUNET_[module_name]_`` and be
    328 defined in ``[module_name].c``. There are exceptions to this rule such as
    329 symbols defined in ``gnunet_common.h``.
    330 
    331 Private symbols, including ``struct``\ s and macros, must not be prefixed.
    332 In addition, they must not be exported in a way that linkers could use them
    333 or other libraries might see them via headers. This means that they must
    334 **never** be declared in ``src/include``, and only declared or defined in
    335 C source files or headers under ``src/[module_name]``.
    336 
    337 
    338 Tests
    339 -----
    340 
    341 In the core of GNUnet, we restrict new testcases to a small subset of
    342 languages, in order of preference:
    343 
    344 1. C
    345 
    346 2. Portable Shell Scripts
    347 
    348 3. Python (3.7 or later)
    349 
    350 We welcome efforts to remove our existing Python 2.7 scripts to replace
    351 them either with portable shell scripts or, at your choice, Python 3.7
    352 or later.
    353 
    354 If you contribute new python based testcases, we advise you to not
    355 repeat our past misfortunes and write the tests in a standard test
    356 framework like for example pytest.
    357 
    358 For writing portable shell scripts, these tools are useful:
    359 
    360 * `Shellcheck <https://github.com/koalaman/shellcheck>`__, for static
    361    analysis of shell scripts.
    362 * http://www.etalabs.net/sh_tricks.html,
    363 * ``bash``-``dash`` (``/bin/sh`` on Debian) interoperability
    364    * `checkbashisms <https://salsa.debian.org/debian/devscripts/blob/master/scripts/checkbashisms.pl>`__,
    365    * https://wiki.ubuntu.com/DashAsBinSh, and
    366    * https://mywiki.wooledge.org/Bashism
    367 
    368 Test cases and performance tests should follow the naming conventions
    369 ``test_[module-under-test]_[test_description].c`` and
    370 ``perf_[module-under-test]_[test_description].c``, respectively.
    371 
    372 In either case, if there is only a single test, ``[test_description]``
    373 may be omitted.
    374 
    375 
    376 
    377 Continuous integration
    378 ======================
    379 
    380 The continuous integration buildbot can be found at
    381 https://buildbot.gnunet.org. Repositories need to be enabled by a
    382 buildbot admin in order to participate in the builds.
    383 
    384 The buildbot can be configured to process scripts in your repository
    385 root under ``.buildbot/``:
    386 
    387 The files ``build.sh``, ``install.sh`` and ``test.sh`` are executed in
    388 order if present. If you want a specific worker to behave differently,
    389 you can provide a worker specific script, e.g. ``myworker_build.sh``. In
    390 this case, the generic step will not be executed.
    391 
    392 For the ``gnunet.git`` repository, you may use \"!tarball\" or
    393 \"!coverity\" in your commit messages. \"!tarball\" will trigger a
    394 ``make dist`` of the gnunet source and verify that it can be compiled.
    395 The artifact will then be published to
    396 https://buildbot.gnunet.org/artifacts. This is a good way to create a
    397 tarball for a release as it verifies the build on another machine.
    398 
    399 The \"!coverity\" trigger will trigger a coverity build and submit the
    400 results for analysis to coverity: https://scan.coverity.com/. Only
    401 developers with accounts for the GNUnet project on coverity.com are able
    402 to see the analysis results.
    403 
    404 
    405 Developer access and commit messages
    406 ====================================
    407 
    408 Major changes **SHOULD** be developed in a developer branch.
    409 A developer branch is a branch which matches a developer-specific
    410 prefix. As a developer with git access, you should have a git username.
    411 If you do not know it, please ask an admin. A developer branch has the
    412 format:
    413 
    414 ::
    415 
    416    dev/<username>/<branchname>
    417 
    418 Assuming the developer with username \"jdoe\" wants to create a new
    419 branch for an i18n fix, the branch name could be:
    420 
    421 ::
    422 
    423    dev/jdoe/i18n_fx
    424 
    425 You will be able to force push to and delete branches under
    426 your prefix. It is highly recommended to work in your own developer
    427 branches.
    428 Most developers only have access to developer branches anyway.
    429 Code which conforms to the commit message guidelines and
    430 coding style, is tested and builds may be merged to the master branch.
    431 Preferably, you would then\...
    432 
    433 -  (optional) \...squash your commits,
    434 
    435 -  rebase to master and then
    436 
    437 -  ask that your branch is merged into master.
    438 
    439 -  (optional) Delete the branch.
    440 
    441 In general, you may want to follow the rule \"commit often, push tidy\":
    442 You can create smaller, succinct commits with limited meaning on the
    443 commit messages. In the end and before you push or ask your branch to be
    444 merged, you can then squash the commits or rename them.
    445 You can ask the project maintainer to merge your branch through any channel,
    446 but the gnunet-developers@gnu.org mailing list is the preferred method.
    447 
    448 Commit messages are required to convey what changes were
    449 made in a self-contained fashion. Commit messages such as \"fix\" or
    450 \"cleanup\" are not acceptable. You commit message should ideally start
    451 with the subsystem name and be followed by a succinct description of the
    452 change. Where applicable a reference to a bug number in the bugtracker
    453 may also be included. Example:
    454 
    455 .. code-block:: text
    456 
    457    # <subsystem>: <description>. (#XXXX)
    458    IDENTITY: Fix wrong key construction for anonymous ECDSA identity. (Fixes #12344)
    459 
    460 We do not maintain a separate ChangeLog file anymore as the changes are
    461 documented in the git repositories.
    462 If you edit files that change user-facing behaviour (e.g. header files in src/include)
    463 you will have to add at least one line in the commit message starting with \"NEWS:\".
    464 If there is a special reason why you deem this unnecessary, you can add the line
    465 \"NEWS: -\".
    466 Any \"NEWS\" lines from commit messages will on release be put into the "NEWS" file in the tarball
    467 to inform users and packages of noteworthy changes.
    468 
    469 .. code-block:: text
    470 
    471    # NEWS
    472    NEWS: The API for foo has changed: lorem ipsum.
    473 
    474 Note that if you run \"./bootstrap\" hooks will be installed that add message hints
    475 to your commit message template when you run \"git commit\".
    476 
    477 If you need to modify a commit you can do so using:
    478 
    479 .. code-block:: console
    480 
    481    $ git commit --amend
    482 
    483 If you need to modify a number of successive commits you will have to
    484 rebase and squash. Note that most branches are protected. This means
    485 that you can only fix commits as long as they are not pushed. You can
    486 only modify pushed commits in your own developer branches.
    487 
    488 
    489 
    490 
    491 Releases
    492 ========
    493 
    494 Packaging a release can only be done by a maintainer.
    495 
    496 In this order do:
    497 
    498 0. Update your local tree
    499 
    500 1. Update the submodule ``contrib/handbook``
    501 
    502 2. Run ``./bootstrap`` to regenerate files
    503 
    504 3. *Optional*: Update bootstrap HELLO file and update GANA generated files using ``./scripts/gana_update.sh``
    505 
    506 4. Update NEWS file, debian/changelog (adding an entry for the new version), update the PO files and commit
    507 
    508 5. Tag the release (Named commit!)
    509 
    510 6. Create and test tarballs
    511 
    512 7. Build and publish Debian and Ubuntu packages using taler-deployment.git/packaging/ng/ (see README there)
    513 
    514 8. Upload tarball
    515 
    516 9. Write release announcement
    517 
    518 
    519 **(1)** Make sure the ``contrib/handbook`` submodule
    520 is up to date.
    521 In the **handbook repository**, make sure you have a folder that
    522 contains the ``prebuilt`` branch as a worktree:
    523 
    524 .. code-block:: console
    525 
    526    $ git worktree add _build prebuilt
    527 
    528 Then compile the current handbook:
    529 
    530 .. code-block:: console
    531 
    532    $ sphinx-multiversion --dump-metadata . _build
    533 
    534 Commit the changes (if any) and update the submoduce in the
    535 gnunet repository under ``doc/handbook`` and execute:
    536 
    537 .. code-block:: console
    538 
    539    $ git pull origin prebuilt
    540 
    541 If the submodule was updated, commit the new submodule.
    542 
    543 **(2)** You should now re-run bootstrap::
    544 
    545 .. code-block:: console
    546 
    547    $ ./bootstrap
    548 
    549 **(3)** If this is a major release, it makes sense to update the bootstrap peer
    550 
    551 HELLO. For this, you need access to the bootstrap peer (``GKZS``) and create
    552 the hello file. Make sure that you update the bootstrap peer first such that
    553 any changes in the identity format are actually refrected!
    554 It is recommended to have it expire within a year:
    555 
    556 .. code-block:: console
    557 
    558    $ gnunet-hello -e -E "1 year" -b -c gnunet.conf > GKZSYTE4H3N4RMYGFYEM95RV1CDRPH8QNJNTPMEB7C4QJGGR3KEG
    559 
    560 You can then update the file in ``data/hellos``.
    561 
    562 **(4)** Then, in order to pre-populate the news file with news hints
    563 from commit messages (see above), we execute
    564 
    565 .. code-block:: console
    566 
    567    $ sh contrib/scripts/update_news.sh v0.22.0
    568 
    569 ``v0.22.0`` is the placeholder for the version number you want to release.
    570 Now edit the ``NEWS`` file to include all the noteworthy changes
    571 you want to add.
    572 
    573 Then, update the po files:
    574 
    575 .. code-block:: console
    576 
    577    $ meson setup build-release && meson compile -C build-release gnunet-update-po
    578 
    579 Commit all changes in the source tree now, and push the changes.
    580 
    581 **(5)** You can now tag the release. Please **always** use named tags (important for our
    582 nightly tarball build trigger).
    583 
    584 .. code-block:: console
    585 
    586    $ git tag v0.22.0 -m "GNUnet release v0.22.0"
    587 
    588 **(6)** Then, we can re-run ``./bootstrap`` and make the tarball:
    589 
    590 .. code-block:: console
    591 
    592    $ ./bootstrap && meson setup --reconfigure build-release && meson dist -C build-release --formats gztar
    593 
    594 
    595 Meson will automatically run the tests.
    596 
    597 **(7)** To distribute the tarballs create a release triplet as defined in the GNU guidelines and
    598 upload them to the FTP (https://www.gnu.org/prep//maintain/html_node/Automated-FTP-Uploads.html).
    599 
    600 The file ``gnunet-0.22.0.tar.gz`` will be found inside ``build/meson-dist``.
    601 The file must be signed by a maintainer and the signature and tarball uploaded to
    602 https://buildbot.gnunet.org/releases/.
    603 
    604 **(8)** After the tarballs are uploaded, we need to write the announcement.
    605 For minor releases, we only write a brief statement:
    606 
    607 .. code-block:: text
    608 
    609   See also: https://www.gnunet.org/en/news/2024-06-0.21.2.html
    610 
    611   This is a bugfix release for gnunet 0.21.1. It primarily addresses some
    612   connectivity issues introduced with our new transport subsystem.
    613 
    614   Links
    615 
    616     Source: https://ftpmirror.gnu.org/gnunet/gnunet-0.21.2.tar.gz (https://ftpmirror.gnu.org/gnunet/gnunet-0.21.2.tar.gz.sig)
    617     Detailed list of changes: https://git.gnunet.org/gnunet.git/log/?h=v0.21.2
    618     NEWS: https://git.gnunet.org/gnunet.git/tree/NEWS?h=v0.21.2
    619     The list of closed issues in the bug tracker: https://bugs.gnunet.org/changelog_page.php?version_id=440
    620 
    621   The GPG key used to sign is: 3D11063C10F98D14BD24D1470B0998EF86F59B6A
    622 
    623   Note that due to mirror synchronization, not all links may be
    624   functional early after the release. For direct access try
    625   https://ftp.gnu.org/gnu/gnunet/
    626 
    627 The announcement is posted to ``gnunet-developers@gnu.org`` as well as
    628 ``help-gnunet@gnu.org``.
    629 
    630 For major releases, we use a full release announcement.
    631 You can find the template in the ``www.git``.
    632 The full release announcement is sent to
    633 ``info-gnu@gnu.org`` as well.