Blob Blame History Raw
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="tooling" xml:lang="el">

  <info>
    <link type="guide" xref="index#general-guidelines"/>

    <credit type="author copyright">
      <name>Philip Withnall</name>
      <email its:translate="no">philip.withnall@collabora.co.uk</email>
      <years>2015</years>
    </credit>

    <include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>

    <desc>Using the right tool for various tasks</desc>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Ελληνική μεταφραστική ομάδα GNOME</mal:name>
      <mal:email>team@gnome.gr</mal:email>
      <mal:years>2016</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Θάνος Τρυφωνίδης</mal:name>
      <mal:email>tomtryf@gnome.org</mal:email>
      <mal:years>2016</mal:years>
    </mal:credit>
  </info>

  <title>Tooling</title>

  <p>
    Development tools are much more than just a text editor and a compiler.
    Correct use of the right tools can drastically ease debugging and tracking
    down of complex problems with memory allocation and system calls, amongst
    other things. Some of the most commonly used tools are described below;
    other tools exist for more specialized use cases, and should be used when
    appropriate.
  </p>

  <p>
    An overarching principle to use when developing is to always have as many
    debugging options enabled as possible, rather than keeping them disabled
    until near release time. By constantly testing code with all available
    debug tooling, bugs can be caught early on, before they become ingrained in
    code and thus harder to remove.
  </p>

  <p>
    Practically, this means having all compiler and other tool warnings enabled
    and set to fail the build process with an error if they are emitted.
  </p>

  <synopsis>
    <title>Σύνοψη</title>

    <list>
      <item><p>
        Compile frequently with a second compiler.
        (<link xref="#gcc-and-clang"/>)
      </p></item>
      <item><p>
        Enable a large selection of compiler warnings and make them fatal.
        (<link xref="#gcc-and-clang"/>)
      </p></item>
      <item><p>
        Use GDB to debug and step through code. (<link xref="#gdb"/>)
      </p></item>
      <item><p>
        Use Valgrind to analyze memory usage, memory errors, cache and CPU
        performance and threading errors. (<link xref="#valgrind"/>)
      </p></item>
      <item><p>
        Use gcov and lcov to analyze unit test coverage.
        (<link xref="#gcov-and-lcov"/>)
      </p></item>
      <item><p>
        Use compiler sanitizers to analyze memory, thread and undefined behavior
        problems. (<link xref="#sanitizers"/>)
      </p></item>
      <item><p>
        Submit to Coverity as a cronjob and eliminate static analysis errors as
        they appear. (<link xref="#coverity"/>)
      </p></item>
      <item><p>
        Use Clang static analyzer and Tartan regularly to eliminate statically
        analysable errors locally. (<link xref="#clang-static-analyzer"/>)
      </p></item>
    </list>
  </synopsis>

  <section id="gcc-and-clang">
    <title>GCC και Clang</title>

    <p>
      <link href="https://gcc.gnu.org/onlinedocs/gcc/">GCC</link> is the
      standard C compiler for Linux. An alternative exists in the form of
      <link href="http://clang.llvm.org/docs/UsersManual.html">Clang</link>,
      with comparable functionality. Choose one (probably GCC) to use as a main
      compiler, but occasionally use the other to compile the code, as the two
      detect slightly different sets of errors and warnings in code. Clang also
      comes with a static analyzer tool which can be used to detect errors in
      code without compiling or running it; see
      <link xref="#clang-static-analyzer"/>.
    </p>

    <p>
      Both compilers should be used with as many warning flags enabled as
      possible. Although compiler warnings do occasionally provide false
      positives, most warnings legitimately point to problems in the code, and
      hence should be fixed rather than ignored. A development policy of
      enabling all warning flags and also specifying the <code>-Werror</code>
      flag (which makes all warnings fatal to compilation) promotes fixing
      warnings as soon as they are introduced. This helps code quality. The
      alternative of ignoring warnings leads to long debugging sessions to track
      down bugs caused by issues which would have been flagged up by the
      warnings. Similarly, ignoring warnings until the end of the development
      cycle, then spending a block of time enabling and fixing them all wastes
      time.
    </p>

    <p>
      Both GCC and Clang support a wide range of compiler flags, only some of
      which are related to modern, multi-purpose code (for example, others are
      outdated or architecture-specific). Finding a reasonable set of flags to
      enable can be tricky, and hence the
      <link href="http://www.gnu.org/software/autoconf-archive/ax_compiler_flags.html">
      <code>AX_COMPILER_FLAGS</code></link> macro exists.
    </p>

    <p>
      <code>AX_COMPILER_FLAGS</code> enables a consistent set of compiler
      warnings, and also tests that the compiler supports each flag before
      enabling it. This accounts for differences in the set of flags supported
      by GCC and Clang. To use it, add <code>AX_COMPILER_FLAGS</code> to
      <file>configure.ac</file>. If you are using in-tree copies of
      autoconf-archive macros, copy
      <link href="http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_compiler_flags.m4">
      <file>ax_compiler_flags.m4</file></link> to the <file>m4/</file> directory
      of your project. Note that it depends on the following autoconf-archive
      macros which are GPL-licenced so potentially cannot be copied in-tree.
      They may have to remain in autoconf-archive, with that as a build time
      dependency of the project:
    </p>
    <list>
      <item><p><code>ax_append_compile_flags.m4</code></p></item>
      <item><p><code>ax_append_flag.m4</code></p></item>
      <item><p><code>ax_check_compile_flag.m4</code></p></item>
      <item><p><code>ax_require_defined.m4</code></p></item>
    </list>

    <p>
      <code>AX_COMPILER_FLAGS</code> supports disabling <code>-Werror</code> for
      release builds, so that releases may always be built against newer
      compilers which have introduced more warnings. Set its third parameter to
      ‘yes’ for release builds (and only release builds) to enable this
      functionality. Development and CI builds should always have
      <code>-Werror</code> enabled.
    </p>

    <p>
      Release builds can be detected using the
      <link href="http://www.gnu.org/software/autoconf-archive/ax_is_release.html"><code>AX_IS_RELEASE</code></link>
      macro, the result of which can be passed directly to
      <code>AX_COMPILER_FLAGS</code>:
    </p>
    <code style="valid">AX_IS_RELEASE([git])
AX_COMPILER_FLAGS([WARN_CFLAGS],[WARN_LDFLAGS],[$ax_is_release])</code>

    <p>
      The choice of release stability policy (the first argument to
      <code>AX_IS_RELEASE</code>) should be made per project, taking the
      project’s <link xref="versioning">versioning stability</link> into
      account.
    </p>
  </section>

  <section id="gdb">
    <title>GDB</title>

    <p>
      GDB is the standard debugger for C on Linux. Its most common uses are for
      debugging crashes, and for stepping through code as it executes. A full
      tutorial for using GDB is given
      <link href="https://sourceware.org/gdb/current/onlinedocs/gdb/">
      here</link>.
    </p>

    <p>
      To run GDB on a program from within the source tree, use:
      <cmd>libtool exec gdb --args <var>./program-name</var> <var>--some --arguments --here</var></cmd>
    </p>

    <p>
      This is necessary due to libtool wrapping each compiled binary in the
      source tree in a shell script which sets up some libtool variables. It is
      not necessary for debugging installed executables.
    </p>

    <p>
      GDB has many advanced features which can be combined to essentially create
      small debugging scripts, triggered by different breakpoints in code.
      Sometimes this is a useful approach (for example, for
      <link href="https://tecnocode.co.uk/2010/07/12/reference-count-debugging-with-gdb/">
      reference count debugging</link>), but sometimes simply using
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-debug">
      <code>g_debug()</code></link> to output a debug message is simpler.
    </p>
  </section>

  <section id="valgrind">
    <title>Valgrind</title>

    <p>
      Valgrind is a suite of tools for instrumenting and profiling programs. Its
      most famous tool is <link xref="#memcheck">memcheck</link>, but it has
      several other powerful and useful tools too. They are covered separately
      in the sections below.
    </p>

    <p>
      A useful way of running Valgrind is to run a program’s unit test suite
      under Valgrind, setting Valgrind to return a status code indicating the
      number of errors it encountered. When run as part of
      <cmd>make check</cmd>, this will cause the checks to succeed if Valgrind
      finds no problems, and fail otherwise. However, running
      <cmd>make check</cmd> under Valgrind is not trivial to do on the command
      line. A macro,
      <link href="http://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html">
      <code>AX_VALGRIND_CHECK</code></link> can be used which adds a new
      <cmd>make check-valgrind</cmd> target to automate this. To use it:
    </p>
    <steps>
      <item><p>
        Copy
        <link href="http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_valgrind_check.m4">
        <file>ax_valgrind_check.m4</file></link> to the <file>m4/</file>
        directory of your project.
      </p></item>
      <item><p>Προσθέστε το <code>AX_VALGRIND_CHECK</code> στο <file>configure.ac</file>.</p></item>
      <item><p>
        Add <code>@VALGRIND_CHECK_RULES@</code> to the <file>Makefile.am</file>
        in each directory which contains unit tests.
      </p></item>
    </steps>

    <p>
      When <cmd>make check-valgrind</cmd> is run, it will save its results in
      <file>test-suite-*.log</file>, one log file per tool. Note that you will
      need to run it from the directory containing the unit tests.
    </p>
    <p>
      Valgrind has a way to suppress false positives, by using
      <link href="http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress">
      suppression files</link>. These list patterns which may match error stack
      traces. If a stack trace from an error matches part of a suppression
      entry, it is not reported. For various reasons, GLib currently causes a
      number of false positives in <link xref="#memcheck">memcheck</link> and
      <link xref="#helgrind-and-drd">helgrind and drd</link> which must be
      suppressed by default for Valgrind to be useful. For this reason, every
      project should use a standard GLib suppression file as well as a project
      specific one.
    </p>

    <p>
      Suppression files are supported by the <code>AX_VALGRIND_CHECK</code>
      macro:
    </p>
    <code>@VALGRIND_CHECK_RULES@
VALGRIND_SUPPRESSIONS_FILES = my-project.supp glib.supp
EXTRA_DIST = $(VALGRIND_SUPPRESSIONS_FILES)</code>

    <section id="memcheck">
      <title>memcheck</title>

      <p>
        memcheck is a memory usage and allocation analyzer. It detects problems
        with memory accesses and modifications of the heap (allocations and
        frees). It is a highly robust and mature tool, and its output can be
        entirely trusted. If it says there is ‘definitely’ a memory leak, there
        is definitely a memory leak which should be fixed. If it says there is
        ‘potentially’ a memory leak, there may be a leak to be fixed, or it may
        be memory allocated at initialization time and used throughout the life
        of the program without needing to be freed.
      </p>

      <p>
        To run memcheck manually on an installed program, use:
      </p>
      <p><cmd>valgrind --tool=memcheck --leak-check=full <var>my-program-name</var></cmd></p>

      <p>
        Or, if running your program from the source directory, use the following
        to avoid running leak checking on the libtool helper scripts:
      </p>
      <p><cmd>libtool exec valgrind --tool=memcheck --leak-check=full <var>./my-program-name</var></cmd></p>

      <p>
        Valgrind lists each memory problem it detects, along with a short
        backtrace (if you’ve compiled your program with debug symbols), allowing
        the cause of the memory error to be pinpointed and fixed.
      </p>

      <p>
        A full tutorial on using memcheck is
        <link href="http://valgrind.org/docs/manual/mc-manual.html">here</link>.
      </p>
    </section>

    <section id="cachegrind-and-kcachegrind">
      <title>cachegrind και KCacheGrind</title>

      <p>
        cachegrind is a cache performance profiler which can also measure
        instruction execution, and hence is very useful for profiling general
        performance of a program.
        <link href="http://kcachegrind.sourceforge.net/html/Home.html">
        KCacheGrind</link> is a useful UI for it which allows visualization and
        exploration of the profiling data, and the two tools should rarely be
        used separately.
      </p>

      <p>
        cachegrind works by simulating the processor’s memory hierarchy, so
        there are situations where it is
        <link href="http://valgrind.org/docs/manual/cg-manual.html#cg-manual.annopts.accuracy">
        not perfectly accurate</link>. However, its results are always
        representative enough to be very useful in debugging performance
        hotspots.
      </p>

      <p>
        A full tutorial on using cachegrind is
        <link href="http://valgrind.org/docs/manual/cg-manual.html">here</link>.
      </p>
    </section>

    <section id="helgrind-and-drd">
      <title>helgrind και drd</title>

      <p>
        helgrind and drd are threading error detectors, checking for race
        conditions in memory accesses, and abuses of the
        <link href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html">
        POSIX pthreads API</link>. They are similar tools, but are implemented
        using different techniques, so both should be used.
      </p>

      <p>
        The kinds of errors detected by helgrind and drd are: data accessed from
        multiple threads without consistent locking, changes in lock acquisition
        order, freeing a mutex while it is locked, locking a locked mutex,
        unlocking an unlocked mutex, and several other errors. Each error, when
        detected, is printed to the console in a little report, with a separate
        report giving the allocation or spawning details of the mutexes or
        threads involved so that their definitions can be found.
      </p>

      <p>
        helgrind and drd can produce more false positives than memcheck or
        cachegrind, so their output should be studied a little more carefully.
        However, threading problems are notoriously elusive even to experienced
        programmers, so helgrind and drd errors should not be dismissed lightly.
      </p>

      <p>
        Full tutorials on using helgrind and drd are
        <link href="http://valgrind.org/docs/manual/hg-manual.html">here</link>
        and <link href="http://valgrind.org/docs/manual/drd-manual.html">
        here</link>.
      </p>
    </section>

    <section id="sgcheck">
      <title>sgcheck</title>

      <p>
        sgcheck is an array bounds checker, which detects accesses to arrays
        which have overstepped the length of the array. However, it is a very
        young tool, still marked as experimental, and hence may produce more
        false positives than other tools.
      </p>

      <p>
        As it is experimental, sgcheck must be run by passing
        <cmd>--tool=exp-sgcheck</cmd> to Valgrind, rather than
        <cmd>--tool=sgcheck</cmd>.
      </p>

      <p>
        A full tutorial on using sgcheck is
        <link href="http://valgrind.org/docs/manual/sg-manual.html">here</link>.
      </p>
    </section>
  </section>

  <section id="gcov-and-lcov">
    <title>gcov και lcov</title>

    <p>
      <link href="https://gcc.gnu.org/onlinedocs/gcc/Gcov.html">gcov</link> is
      a profiling tool built into GCC, which instruments code by adding extra
      instructions at compile time. When the program is run, this code
      generates <file>.gcda</file> and <file>.gcno</file> profiling output
      files. These files can be analyzed by the <cmd>lcov</cmd> tool, which
      generates visual reports of code coverage at runtime, highlighting lines
      of code in the project which are run more than others.
    </p>

    <p>
      A critical use for this code coverage data collection is when running
      the unit tests: if the amount of code covered (for example, which
      particular lines were run) by the unit tests is known, it can  be used to
      guide further expansion of the unit tests. By regularly checking the code
      coverage attained by the unit tests, and expanding them towards 100%,
      you can be sure that the entire project is being tested. Often it is the
      case that a unit test exercises most of the code, but not a particular
      control flow path, which then harbours residual bugs.
    </p>

    <p>
      lcov supports
      <link href="http://en.wikipedia.org/wiki/Code_coverage#Basic_coverage_criteria">
      branch coverage measurement</link>, so is not suitable for demonstrating
      coverage of safety critical code. It is perfectly suitable for
      non-safety critical code.
    </p>

    <p>
      As code coverage has to be enabled at both compile time and run time, a
      macro is provided to make things simpler. The
      <link href="http://www.gnu.org/software/autoconf-archive/ax_code_coverage.html">
      <code>AX_CODE_COVERAGE</code></link> macro adds a
      <cmd>make check-code-coverage</cmd> target to the build system, which
      runs the unit tests with code coverage enabled, and generates a report
      using <cmd>lcov</cmd>.
    </p>

    <p>
      To add <code>AX_CODE_COVERAGE</code> support to a project:
    </p>
    <steps>
      <item><p>
        Copy
        <link href="http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_code_coverage.m4">
        <file>ax_code_coverage.m4</file></link> to the <file>m4/</file>
        directory of your project.
      </p></item>
      <item><p>Προσθέστε <code>AX_CODE_COVERAGE</code> στο <file>configure.ac</file>.</p></item>
      <item><p>
        Add <code>@CODE_COVERAGE_RULES</code> to the top-level
        <file>Makefile.am</file>.
      </p></item>
      <item><p>
        Add <code>$(CODE_COVERAGE_CFLAGS)</code> to the automake
        <code><var>*</var>_CFLAGS</code> variable for each target you want
        coverage for, for example for all libraries but no unit test code. Do
        the same for <code>$(CODE_COVERAGE_LDFLAGS)</code> and
        <code><var>*</var>_LDFLAGS</code>.
      </p></item>
    </steps>

    <p>
      Documentation on using gcov and lcov is
      <link href="http://ltp.sourceforge.net/coverage/lcov.php">here</link>.
    </p>
  </section>

  <section id="sanitizers">
    <title>Address, Thread and Undefined Behavior Sanitizers</title>

    <p>
      GCC and Clang both support several sanitizers: sets of extra code and
      checks which can be optionally compiled in to an application and used to
      flag various incorrect behaviors at runtime. They are powerful tools, but
      have to be enabled specially, recompiling your application to enable and
      disable them. They cannot be enabled at the same time as each other, or
      used at the same time as <link xref="#valgrind">Valgrind</link>. They are
      still young, so have little integration with other tooling.
    </p>

    <p>
      All sanitizers are available for both GCC and Clang, accepting the same
      set of compiler options.
    </p>

    <section id="address-sanitizer">
      <title>Address Sanitizer</title>

      <p>
        The <link href="https://code.google.com/p/address-sanitizer/">address
        sanitizer</link> (‘asan’) detects use-after-free and buffer overflow
        bugs in C and C++ programs. A full tutorial on using asan is
        <link href="http://clang.llvm.org/docs/AddressSanitizer.html#usage">available
        for Clang</link> — the same instructions should work for GCC.
      </p>
    </section>

    <section id="thread-sanitizer">
      <title>Thread Sanitizer</title>

      <p>
        The <link href="https://code.google.com/p/thread-sanitizer/">thread
        sanitizer</link> (‘tsan’) detects data races on memory locations, plus
        a variety of invalid uses of POSIX threading APIs. A full tutorial on
        using tsan is
        <link href="http://clang.llvm.org/docs/ThreadSanitizer.html#usage">available
        for Clang</link> — the same instructions should work for GCC.
      </p>
    </section>

    <section id="undefined-behavior-sanitizer">
      <title>Undefined Behavior Sanitizer</title>

      <p>
        The undefined behavior sanitizer (‘ubsan’) is a collection of smaller
        instrumentations which detect various potentially undefined behaviors in
        C programs. A set of instructions for enabling ubsan is
        <link href="http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation">available
        for Clang</link> — the same instructions should work for GCC.
      </p>
    </section>
  </section>

  <section id="coverity">
    <title>Coverity</title>

    <p>
      <link href="http://scan.coverity.com/">Coverity</link> is one of the most
      popular and biggest commercial static analyzer tools available. However,
      it is available to use free for Open Source projects, and any project is
      encouraged to <link href="https://scan.coverity.com/users/sign_up">sign
      up</link>.
      <link href="https://scan.coverity.com/faq#how-get-project-included-in-scan">
      Analysis is performed</link> by running some analysis tools locally, then
      uploading the source code and results as a tarball to Coverity’s site. The
      results are then visible online to members of the project, as annotations
      on the project’s source code (similarly to how lcov presents its results).
    </p>

    <p>
      As Coverity cannot be run entirely locally, it cannot be integrated
      properly into the build system. However, scripts do exist to automatically
      scan a project and upload the tarball to Coverity regularly. The
      recommended approach is to run these scripts regularly on a server
      (typically as a cronjob), using a clean checkout of the project’s git
      repository. Coverity automatically e-mails project members about new
      static analysis problems it finds, so the same approach as for
      <link xref="#gcc-and-clang">compiler warnings</link> can be taken:
      eliminate all the static analysis warnings, then eliminate new ones as
      they are detected.
    </p>

    <p>
      Coverity is good, but it is not perfect, and it does produce a number of
      false positives. These should be marked as ignored in the online
      interface.
    </p>
  </section>

  <section id="clang-static-analyzer">
    <title>Clang Static Analyzer</title>

    <p>
      One tool which can be used to perform static analysis locally is the
      <link href="http://clang-analyzer.llvm.org/">Clang static analyzer</link>,
      which is a tool co-developed with the <link xref="#gcc-and-clang">Clang
      compiler</link>. It detects a variety of problems in C code which
      compilers cannot, and which would otherwise only be detectable at run time
      (using unit tests).
    </p>

    <p>
      Clang produces some false positives, and there is no easy way to ignore
      them. The recommended thing to do is to
      <link href="http://clang-analyzer.llvm.org/faq.html#suppress_issue">file
      a bug report against the static analyzer</link>, so that the false
      positive can be fixed in future.
    </p>

    <p>
      A full tutorial on using Clang is
      <link href="http://clang-analyzer.llvm.org/scan-build.html">here</link>.
    </p>

    <section id="tartan">
      <title>Tartan</title>

      <p>
        However, for all the power of the Clang static analyzer, it cannot
        detect problems with specific libraries, such as GLib. This is a problem
        if a project uses GLib exclusively, and rarely uses POSIX APIs (which
        Clang does understand). There is a plugin available for the Clang static
        analyzer, called
        <link href="http://people.collabora.com/~pwith/tartan/">Tartan</link>,
        which extends Clang to support checks against some of the common GLib
        APIs.
      </p>

      <p>
        Tartan is still young software, and will produce false positives and may
        crash when run on some code. However, it can find legitimate bugs quite
        quickly, and is worth running over a code base frequently to detect new
        errors in the use of GLib in the code. Please
        <link href="http://people.collabora.com/~pwith/tartan/#troubleshooting">
        report any problems with Tartan</link>.
      </p>

      <p>
        A full tutorial on enabling Tartan for use with the Clang static
        analyzer is
        <link href="http://people.collabora.com/~pwith/tartan/#usage-standalone">
        here</link>. If set up correctly, the output from Tartan will be mixed
        together with the normal static analyzer output.
      </p>
    </section>
  </section>
</page>