Tutorial part 1: “Hello world”¶
Before we look at the details of the API, let’s look at building and running programs that use the library.
Here’s a toy program that uses libgdiagnostics to emit an error message to stderr.
/* Minimal usage example. */ #include "libgdiagnostics.h" static diagnostic_manager *diag_mgr; static void init_diagnostics (void) { diag_mgr = diagnostic_manager_new (); diagnostic_manager_add_text_sink (diag_mgr, stderr, DIAGNOSTIC_COLORIZE_IF_TTY); } static void finish_diagnostics (void) { diagnostic_manager_release (diag_mgr); } static void do_stuff (void) { const char *username = "Dave"; diagnostic *d = diagnostic_begin (diag_mgr, DIAGNOSTIC_LEVEL_ERROR); diagnostic_finish (d, "I'm sorry %s, I'm afraid I can't do that", username); } int main () { init_diagnostics (); do_stuff (); finish_diagnostics (); };
Copy the above to tut01-hello-world.c.
Assuming you have libgdiagnostics installed, build the test program using:
$ gcc \
tut01-hello-world.c \
-o tut01-hello-world \
-lgdiagnostics
You should then be able to run the built program:
$ ./tut01-hello-world
progname: error: I'm sorry Dave, I'm afraid I can't do that
If stderr is connected to a terminal, you should get colorized output (using SGR control codes).

Otherwise, the output will be plain text.
Obviously a trivial example like the above could be done using fprintf
on stderr, and it’s fairly easy to colorize text at the terminal.
In the next part of the tutorial we’ll add file/location information to our error messages, and libgdiagnostics will quote the pertinent parts of the file, underlining them, which is less trivial to reimplement. libgdiagnostics gives us many other such abilities, such as fix-it hints and execution paths, which we’ll cover in the following tutorials. Also, once a program’s diagnostics are using libgdiagnostics, it is trivial to add support for outputting them in machine-readable form as SARIF.
Structure¶
The above example shows the typical structure of a program using libgdiagnostics:
initialization: create a
diagnostic_manager
instance, and create an output sink for it, and other one-time initializationemission: create various
diagnostic
instances, populating them with data, and calling “finish” once they’re ready to be emitted. Text sinks emit their diagnostics as soon as “finish” is called on them.cleanup: call
diagnostic_manager_release()
on thediagnostic_manager
to finish and free up resources. SARIF sinks write their output whendiagnostic_manager_release()
is called on the manager.
For non-trivial examples we’ll also want to create location information, which could happen during initialization, or during a parsing phase of the program using libgdiagnostics. See Tutorial part 2: physical locations for more information.
Formatted messages¶
The above example uses diagnostic_finish()
, which takes a format
string and arguments. libgdiagnostics has its own style of format
string arguments used for diagnostic_finish()
and some other
entrypoints.
Note
The format syntax is not the same as printf
; see
supported formatting options.
You can use the q
modifier on arguments
to quote them, so, for example %qs
is a quoted string, consuming a
const char *
argument:
diagnostic_finish (d, "can't find %qs", "foo");
This gives output like this:
progname: error: can't find ‘foo’
where the quoted string will appear in bold in a suitably-capable
terminal, and the quotes will be internationalized, so that e.g. with
LANG=fr_FR.UTF8
we might get:
progname: erreur: can't find « free »
Note that:
the string
error
has been localized by libgdiagnostics toerreur
,locale-specific quoting has been used (
«
and»
rather than‘
and’
),foo
hasn’t been localized - you would typically use quoted strings for referring to identifiers in the input language (such as function names in code, property names in JSON, etc),the message itself hasn’t been localized: you are responsible for passing a translated format string to
diagnostic_finish()
if you want to internationalize the output.
There are many supported formatting options.
Naming the program¶
In the above output the message was preceded with progname
. This
appears for diagnostics that don’t have any location information associated
with them. We’ll look at setting up location information in the
next tutorial, but we can override this
default name via diagnostic_manager_set_tool_name()
:
diagnostic_manager_set_tool_name (diag_mgr, "my-awesome-checker");
leading to output like this:
my-awesome-checker: error: can't find ‘foo’
There are various other functions for supplying metadata to libgdiagnostics.
Moving beyond trivial examples¶
Obviously it’s not very useful if we can’t refer to specific files and specific locations in those files in our diagnostics, so read part 2 of the tutorial for information on how to do this.