CONTRIBUTING
============

To contribute code or documentation, submit a pull request at the
`source repository website
<https://code.uplex.de/uplex-varnish/libvmod-selector>`_ or its
`mirror <https://gitlab.com/uplex/varnish/libvmod-selector>`_.

If you have a problem or discover a bug, you can post an `issue
<https://code.uplex.de/uplex-varnish/libvmod-selector/issues>`_ at
the website
(`or mirror <https://gitlab.com/uplex/varnish/libvmod-selector/-/issues>`_).
You can also write to <varnish-support@uplex.de>.

For developers
--------------

The VMOD source code is in C, and compilation has been tested with gcc
and clang. The code MUST always compile successfully with both of
them.

The build specifies C99 conformance for C sources (``-std=c99``). All
compiler warnings are turned on, and all warnings are considered
errors (``-Werror -Wall -Wextra``).  The code MUST always build
without warnings or errors under these constraints.

By default, ``CFLAGS`` is set to ``-g -O2``, so that symbols are
included in the shared library, and optimization is at level
``O2``. To change or disable these options, set ``CFLAGS`` explicitly
before calling ``configure`` (it may be set to the empty string).

For development/debugging cycles, the ``configure`` option
``--enable-debugging`` is recommended (off by default). This will turn
off optimizations and function inlining, so that a debugger will step
through the code as expected.

Experience has shown that adding ``-ggdb3`` to ``CFLAGS`` is
beneficial if you need to examine the VMOD with the gdb debugger. The
shared object for a VMOD is loaded from a directory relative to the
Vinyl home directory (by default ``/usr/local/var/$INSTANCE`` for
development builds). A debugger needs to locate the shared object from
that relative path to load its symbols, so the Vinyl home directory
should be the current working directory when the debugger is run. For
example::

  # To run gdb and examine a coredump
  $ cd /usr/local/var/myinstance
  $ gdb /usr/local/sbin/vinyld /path/to/coredump

By default, the VMOD is built with the stack protector enabled
(compile option ``-fstack-protector``), but it can be disabled with
the ``configure`` option ``--disable-stack-protector``.

Test coverage
~~~~~~~~~~~~~

.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php

The autotools generate a make target ``coverage``, which can be used
to generate test coverage reports, if you have the tools ``lcov`` and
``genhtml`` installed (see `lcov`_). HTML coverage reports are
generated in ``src/coverage``::

  $ make coverage
  # Now point your browser to src/coverage/index.html

By default, ``configure`` checks if both of ``lcov`` and ``genhtml``
can be found on the ``PATH``; if they cannot be found, then coverage
reports cannot be generated (and ``make coverage`` results in an
error). If necessary, you can invoke ``configure`` with
``--with-lcov=/path/to/lcov`` and/or
``--with-genhtml=/path/to/genhtml`` to specify their locations.

Invoking ``make coverage`` has these effects:

* ``make clean`` is invoked.

* Code is compiled with ``CFLAGS`` set to generate ``gcov`` output.
  This entails disabling debugging and optimization.

* ``make check`` is invoked.

* ``lcov`` and ``genhtml`` are used to generate the reports.

After running ``make coverage``, it may be necessary to clean up with
``make clean`` and rebuild the code before you continue development
and debugging, since the symbols for ``gcov`` may interfere with
linkage and testing.

Benchmarks
~~~~~~~~~~

Utilities for benchmarking the internal match operations are included
in the repository under ``src/tests/bench``. That directory also
includes files with test data meant to simulate various kinds of use
cases, and test inputs. See ``README.md`` in the directory for
details.

If ``configure`` is called with ``--enable-benchmarks``, then the
benchmark utilities are built as part of the regular build process
(when ``make`` is invoked). The feature is disabled by default. Even
if the configure flag was not enabled, the benchmarks are built when
``make`` is invoked in the benchmark directory.

popcnt support
~~~~~~~~~~~~~~

The QP interface ("quadbit patricia trie", supporting prefix matches)
computes the population count, or popcnt, of 16-bit bitmaps to
implement sparse arrays for branching (following an idea from
`Tony Finch <https://dotat.at/prog/qp/README.html>`_); see
``src/popcnt_compat.h``.  By default, this is implemented by table
lookup -- two lookups in a table of popcnt values for each byte.

If ``__builtin_popcount`` is supported (as is the case for both gcc
and clang) and the macro ``__POPCNT__`` is defined, then
``__builtin_popcount`` is invoked instead of the table lookup. The
macro is usually defined for an architecture-specific build, for
example with the ``-march`` C flag, and there is a ``popcnt`` machine
instruction. You can also define ``__POPCNT__`` in the flags.

If there is no ``popcnt`` instruction, ``__builtin_popcount`` is
usually implemented with a computation that may be considerably slower
than the table lookup. Benchmarks have suggested that it can have a
significant negative impact, and should probably be avoided in
general.

In fact, table lookup for popcnt appears to perform very well, even
compared to implementations with a ``popcnt`` instruction. If you are
considering a build that uses a native ``popcnt`` instruction, it is
advisable to benchmark the results to see if there is a real
advantage.
