gnunet-handbook

The GNUnet Handbook
Log | Files | Refs

style.rst (20325B)


      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 and PO files and commit
    507 
    508 5. Tag the release (Named commit!)
    509 
    510 6. Create and test tarballs
    511 
    512 7. Upload tarball
    513 
    514 8. Write release announcement
    515 
    516 
    517 **(1)** Make sure the ``contrib/handbook`` submodule
    518 is up to date.
    519 In the **handbook repository**, make sure you have a folder that
    520 contains the ``prebuilt`` branch as a worktree:
    521 
    522 .. code-block:: console
    523 
    524    $ git worktree add _build prebuilt
    525 
    526 Then compile the current handbook:
    527 
    528 .. code-block:: console
    529 
    530    $ sphinx-multiversion --dump-metadata . _build
    531 
    532 Commit the changes (if any) and update the submoduce in the
    533 gnunet repository under ``doc/handbook`` and execute:
    534 
    535 .. code-block:: console
    536 
    537    $ git pull origin prebuilt
    538 
    539 If the submodule was updated, commit the new submodule.
    540 
    541 **(2)** You should now re-run bootstrap::
    542 
    543 .. code-block:: console
    544 
    545    $ ./bootstrap
    546 
    547 **(3)** If this is a major release, it makes sense to update the bootstrap peer
    548 
    549 HELLO. For this, you need access to the bootstrap peer (``GKZS``) and create
    550 the hello file. Make sure that you update the bootstrap peer first such that
    551 any changes in the identity format are actually refrected!
    552 It is recommended to have it expire within a year:
    553 
    554 .. code-block:: console
    555 
    556    $ gnunet-hello -e -E "1 year" -b -c gnunet.conf > GKZSYTE4H3N4RMYGFYEM95RV1CDRPH8QNJNTPMEB7C4QJGGR3KEG
    557 
    558 You can then update the file in ``data/hellos``.
    559 
    560 **(4)** Then, in order to pre-populate the news file with news hints
    561 from commit messages (see above), we execute
    562 
    563 .. code-block:: console
    564 
    565    $ sh contrib/scripts/update_news.sh v0.22.0
    566 
    567 ``v0.22.0`` is the placeholder for the version number you want to release.
    568 Now edit the ``NEWS`` file to include all the noteworthy changes
    569 you want to add.
    570 
    571 Then, update the po files:
    572 
    573 .. code-block:: console
    574 
    575    $ meson setup build-release && meson compile -C build-release gnunet-update-po
    576 
    577 Commit all changes in the source tree now, and push the changes.
    578 
    579 **(5)** You can now tag the release. Please **always** use named tags (important for our
    580 nightly tarball build trigger).
    581 
    582 .. code-block:: console
    583 
    584    $ git tag v0.22.0 -m "GNUnet release v0.22.0"
    585 
    586 **(6)** Then, we can re-run ``./bootstrap`` and make the tarball:
    587 
    588 .. code-block:: console
    589 
    590    $ ./bootstrap && meson setup --reconfigure build-release && meson dist -C build-release --formats gztar
    591 
    592 
    593 Meson will automatically run the tests.
    594 
    595 **(7)** To distribute the tarballs create a release triplet as defined in the GNU guidelines and
    596 upload them to the FTP (https://www.gnu.org/prep//maintain/html_node/Automated-FTP-Uploads.html).
    597 
    598 The file ``gnunet-0.22.0.tar.gz`` will be found inside ``build/meson-dist``.
    599 The file must be signed by a maintainer and the signature and tarball uploaded to
    600 https://buildbot.gnunet.org/releases/.
    601 
    602 **(8)** After the tarballs are uploaded, we need to write the announcement.
    603 For minor releases, we only write a brief statement:
    604 
    605 .. code-block:: text
    606 
    607   See also: https://www.gnunet.org/en/news/2024-06-0.21.2.html
    608 
    609   This is a bugfix release for gnunet 0.21.1. It primarily addresses some
    610   connectivity issues introduced with our new transport subsystem.
    611   
    612   Links
    613   
    614     Source: https://ftpmirror.gnu.org/gnunet/gnunet-0.21.2.tar.gz (https://ftpmirror.gnu.org/gnunet/gnunet-0.21.2.tar.gz.sig)
    615     Detailed list of changes: https://git.gnunet.org/gnunet.git/log/?h=v0.21.2
    616     NEWS: https://git.gnunet.org/gnunet.git/tree/NEWS?h=v0.21.2
    617     The list of closed issues in the bug tracker: https://bugs.gnunet.org/changelog_page.php?version_id=440
    618   
    619   The GPG key used to sign is: 3D11063C10F98D14BD24D1470B0998EF86F59B6A
    620   
    621   Note that due to mirror synchronization, not all links may be
    622   functional early after the release. For direct access try
    623   https://ftp.gnu.org/gnu/gnunet/ 
    624 
    625 The announcement is posted to ``gnunet-developers@gnu.org`` as well as
    626 ``help-gnunet@gnu.org``.
    627 
    628 For major releases, we use a full release announcement.
    629 You can find the template in the ``www.git``.
    630 The full release announcement is sent to
    631 ``info-gnu@gnu.org`` as well.