
* We still target Ubuntu 14.04, which comes with GCC 4.8 and CMake
  2.8.12.

  The code is thus written in C++11 and must be tested to compile with
  GCC 4.8, since C++11 support in this version is not perfect. In
  particular, it emits erroneous -Wmissing-field-initializers in some
  places; we intentionally don't add workarounds for this warning.

  Support for CMake 2.8.12 is only required on Unix-like systems; many
  Windows-specific CMake files use features from version 3.

* A C/CPP file should include headers in the following order:

  * The header of the current C/CPP file
  * Standard C/C++ library headers. On Unix-like systems, OS API
    (POSIX) headers may also be in this group.
  * OS API headers.
  * Other third-party headers, including src/thirdparty.
  * Our headers from src/.

  These #include groups should be separated by an empty line.

* When a CPP file implements a function from a C header, the signature
  should be copied verbatim to the CPP file. This includes the case
  when a C type from the signature is available in CPP in the std::
  namespace, e.g. size_t (<stddef.h>) vs std::size_t (<cstddef>).

* In both C and C++ code, a pointer is not expected to be null (unless
  the opposite is explicitly stated in the documentation) in case it
  implies an arbitrary sized memory region (e.g. array, C string,
  void*, etc.) rather than a pointer to a single object. Other pointer
  types are handled as follows:

  * C: A function from a public C API should expect a pointer argument
    to be null. If null is an invalid value, the routine should either
    report an error or (if there's no way to report an error) do
    nothing.

  * C++: In C++ code, raw pointers are only used to express optional
    references and thus always expected to be null. Exceptions to
    this rule should be revised to use references (or
    reference_wrapper), or at least be explicitly documented.

    In case of errors, a function returning a created an object via a
    smart pointer should either throw an exception and never return
    null (this is the preferred way), or never throw and return null
    to signal an error.

* Don't use UTF-8 string literals (u8""). Since C++20, their type is
  changed from char to char8_t, breaking the backward compatibility.

  To insert UTF-8 bytes in a string, use 3 digit octal escape
  sequences. Don't use hex sequences, as they consume as much valid
  hex characters as possible. The only exception is when they are
  separated from the rest of the string by literal concatenation:

      "\xC2\xA9" "2018" (gives ©2018)

* You can implicitly create QStrings from UTF-8 data. Qt 5 and newer
  uses fromUtf8() in this case. For Qt 4, which uses fromAscii(), we
  have setCodecForCStrings() in main.cpp.

* Tesseract versions before 4.1.0 require "C" locale during OCR,
  forcing gettext to return English. As a workaround, we cache
  translatable strings that are set while OCR is active, and group
  them in structs named DynamicStrings.

* Use underscores instead of hyphens in CMake target names.

* All global configuration macros and CMake options have DPSO_ prefix.
  A CMakeLists file should explicitly set the macro value in
  target_compile_definitions() rather than leaving it undefined; an
  undefined macro may be set to a default value in the source code,
  and that default may not match the CMake option.

* ENABLE_NLS=1 macro should be defined to enable gettext. If you use
  dpso_utils/intl.h, this can be done with DPSO_ENABLE_NLS CMake
  option (enabled by default). If you use your own gettext.h, set
  ENABLE_NLS manually.
