Debugging within the FreeType sources ===================================== I. Configuration macros ----------------------- There are several ways to enable debugging features in a FreeType 2 builds. This is controlled through the definition of special macros located in the file `ftoption.h'. The macros are: FT_DEBUG_LEVEL_ERROR #define this macro if you want to compile the `FT_ERROR' macro calls to print error messages during program execution. This does not stop the program. Very useful to spot invalid fonts during development and to code workarounds for them. FT_DEBUG_LEVEL_TRACE #define this macro if you want to compile both macros `FT_ERROR' and `FT_TRACE'. This also includes the variants `FT_TRACE0', `FT_TRACE1', `FT_TRACE2', ..., `FT_TRACE7'. The trace macros are used to send debugging messages when an appropriate `debug level' is configured at runtime through the `FT2_DEBUG' environment variable (more on this later). FT_DEBUG_MEMORY If this macro is #defined, the FreeType engine is linked with a small but effective debugging memory manager that tracks all allocations and frees that are performed within the font engine. When the `FT2_DEBUG_MEMORY' environment variable is defined at runtime, a call to `FT_Done_FreeType' dumps memory statistics, including the list of leaked memory blocks and optionally with the source locations where these were allocated. It is always a very good idea to define this in development builds. This works with _any_ program linked to FreeType, but requires a big deal of memory (the debugging memory manager never frees the blocks to the heap in order to detect double frees). When `FT2_DEBUG_MEMORY' isn't defined at runtime, the debugging memory manager is ignored, and performance is unaffected. FT_DEBUG_LOGGING #define this macro for enhanced logging support; it automatically sets `FT_DEBUG_LEVEL_TRACE' and `FT_DEBUG_LEVEL_ERROR'. If defined, `FT_TRACE' and `FT_ERROR' can send tracing and debugging messages to a file. The location of the log file has to be set with the `FT_LOGGING_FILE' environment variable (more on this later). The main enhancements are the possibility of logging the time and the name of the `FT_COMPONENT' macro together with the affected `FT_TRACE' or `FT_ERROR' calls. See below how to activate this in the `FT2_DEBUG' environment variable. II. Debugging macros -------------------- Several macros can be used within the FreeType sources to help debugging its code: 1. FT_ERROR(( ... )) This macro is used to send debug messages that indicate relatively serious errors (like broken font files) without stopping the execution of the running program. Its code is compiled only when either `FT_DEBUG_LEVEL_ERROR' or `FT_DEBUG_LEVEL_TRACE' are defined in `ftoption.h'. Note that you have to use a printf-like signature, but with double parentheses, like in FT_ERROR(( "your %s is not %s\n", "foo", "bar" )); 2. FT_ASSERT( condition ) This macro is used to check strong assertions at runtime. If its condition isn't TRUE, the program aborts with a panic message. Its code is compiled when either `FT_DEBUG_LEVEL_ERROR' or `FT_DEBUG_LEVEL_TRACE' are defined. You don't need double parentheses here. Example: FT_ASSERT( ptr != NULL ); 3. FT_TRACE( level, (message...) ) The `FT_TRACE' macro is used to send general-purpose debugging messages during program execution. This macro uses an *implicit* macro named `FT_COMPONENT', which names the current FreeType component being run. The developer should always define `FT_COMPONENT' as appropriate, for example as in #undef FT_COMPONENT #define FT_COMPONENT io The value of the `FT_COMPONENT' macro is one of the component names defined in the internal file `internal/fttrace.h'. If you modify the FreeType source code and insert a new `FT_COMPONENT' macro, you must register it in `fttrace.h'. If you insert or remove many trace macros, you can test for undefined or unused trace macros with the script `src/tools/chktrcmp.py'. Each such component is assigned a `debug level', ranging from value 0 to 7, through the use of the `FT2_DEBUG' environment variable (described below) when a program linked with FreeType starts. When `FT_TRACE' is called, its level is compared to the one of the corresponding component. Messages with trace levels *higher* than the corresponding component level are filtered out and never printed. This means that trace messages with level 0 are always printed, those with level 2 are only printed when the component level is *at least* 2, etc. The second parameter to `FT_TRACE' must contain parentheses and corresponds to a printf-like call, as in FT_TRACE( 2, ( "your %s is not %s\n", "foo", "bar" ) ) The shortcut macros `FT_TRACE0', `FT_TRACE1', `FT_TRACE2', ..., `FT_TRACE7' can be used with constant level indices, and are much cleaner to use, as in FT_TRACE2(( "your %s is not %s\n", "foo", "bar" )); III. Environment variables -------------------------- The following environment variables control debugging output and behaviour of FreeType at runtime. FT2_DEBUG This variable is only used when FreeType is built with `FT_DEBUG_LEVEL_TRACE' defined. It contains a list of component level definitions, following this format: component1:level1 component2:level2 component3:level3 ... where `componentX' is the name of a tracing component, as defined in `fttrace.h'. `levelX' is the corresponding level to use at runtime. `any' is a special component name that is interpreted as `any/all components'. For example, the following definitions set FT2_DEBUG=any:2 memory:5 io:4 (on Windows) export FT2_DEBUG="any:2 memory:5 io:4" (on Linux with bash) both stipulate that all components should have level 2, except for the memory and io components, which are set to the trace levels 5 and 4, respectively. If `FT_DEBUG_LOGGING' is defined, two more options are available. * -v: Print also the name of FreeType's component from which the current log is produced, together with the tracing level. * -t: Print also the time. Here are some examples how the output might look like. FT2_DEBUG="any:7 memory:5 -vt" => [20:32:02:44969 ttload:2] table directory loaded FT2_DEBUG="any:7 memory:5 -t" => [20:32:02:44969] table directory loaded FT2_DEBUG="any:7 memory:5 -v" => [ttload:2] table directory loaded FT_LOGGING_FILE This variable is only used if FreeType is built with the `FT_DEBUG_LOGGING' macro defined. It contains the path to the file where the user wants to put his log file. If it is not set, FreeType uses stderr. Examples: On UNIX-like systems with bash: export FT_LOGGING_FILE="/tmp/freetype2.log" On Windows: set FT_LOGGING_FILE=C:\Users\AppData\Local\Temp\freetype2.log FT2_DEBUG_MEMORY This environment variable, when defined, tells FreeType to use a debugging memory manager that tracks leaking memory blocks as well as other common errors like double frees. It is also capable of reporting _where_ the leaking blocks were allocated, which considerably saves time when debugging new additions to the library. This code is only compiled when FreeType is built with the `FT_DEBUG_MEMORY' macro #defined in `ftoption.h' though, it is ignored in other builds. FT2_ALLOC_TOTAL_MAX This variable is ignored if `FT2_DEBUG_MEMORY' is not defined. It allows you to specify a maximum heap size for all memory allocations performed by FreeType. This is very useful to test the robustness of the font engine and programs that use it in tight memory conditions. If it is undefined, or if its value is not strictly positive, no allocation bounds are checked at runtime. FT2_ALLOC_COUNT_MAX This variable is ignored if `FT2_DEBUG_MEMORY' is not defined. It allows you to specify a maximum number of memory allocations performed by FreeType before returning the error `FT_Err_Out_Of_Memory'. This is useful for debugging and testing the engine's robustness. If it is undefined, or if its value is not strictly positive, no allocation bounds are checked at runtime. FT2_KEEP_ALIVE This variable is ignored if `FT2_DEBUG_MEMORY' is not defined. `Keep alive' means that freed blocks aren't released to the heap. This is useful to detect double-frees or weird heap corruption, reporting the source code location of the original allocation and deallocation in case of a problem. It uses large amounts of memory, however. If it is undefined, or if its value is not strictly positive, freed blocks are released at runtime. IV. Additional Capabilities with `FT_DEBUG_LOGGING' --------------------------------------------------- If `FT_DEBUG_LOGGING' is defined, four APIs are available to provide additional debugging support. Use #include to access them. FT_Trace_Set_Level( const char* level ) By default, FreeType uses the tracing levels set in the `FT2_DEBUG' environment variable. Use this function to override the value with `level'. Use value `NULL' to disable tracing. FT_Trace_Set_Default_Level( void ) Reset the tracing levels to the default value, i.e., the value of the `FT2_DEBUG' environment variable or no tracing if not set. FT_Set_Log_Handler( ft_custom_log_handler handler ) Use `handler' as a custom handler for formatting tracing and error messages. The `ft_custom_log_handler' typedef has the following prototype. void (*ft_custom_log_handler)( const char* ft_component, const char* fmt, va_list args ); `ft_component' is the current component like `ttload', `fmt' is the first argument of `FT_TRACE' or `FT_ERROR', and `args' holds the remaining arguments. FT_Set_Default_Log_Handler( void ) Reset the log handler to the default version. ------------------------------------------------------------------------ Copyright (C) 2002-2023 by David Turner, Robert Wilhelm, and Werner Lemberg. This file is part of the FreeType project, and may only be used, modified, and distributed under the terms of the FreeType project license, LICENSE.TXT. By continuing to use, modify, or distribute this file you indicate that you have read the license and understand and accept it fully. --- end of DEBUG ---