Build and Run

Install the dependencies, build the two example applications, and run them on your desktop in an SDL2 window - no target hardware needed.

Both examples shipped with the LVGL Safe preview (v0.1.0) run on your desktop in an SDL2 window, so you can evaluate the library before any target hardware is involved.

1. What you need

CMake3.16 or newer
A C99 compiler (or newer)GCC or Clang
SDL2 development filesthe simulator backend the examples draw into
The LVGL Safe packagealready unpacked as a sibling folder, e.g. lvgl_safe-0.1.0-linux-x86_64/ (holding include/ and lib/)

Installing the tools and dependencies

On Debian-based distributions (Debian / Ubuntu) using the apt package manager:

bash
sudo apt install cmake build-essential libsdl2-dev

Windows builds use the MSYS2 mingw-w64 GCC toolchain (https://www.msys2.org/). Install the packages once from an MSYS2 shell:

bash
pacman -S --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake \
                    mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2

Note: If you are using VSCode follow these instructions to set up MSYS2 mingw-w64 and come back to this guide when installing the needed packages.

Python is not needed to build the examples. It is only needed if you want to convert your own images and fonts - see Assets.

2. Build and run

The LVGL Safe repository ships an ubuntu and a windows preset, so cmake --preset <name> and cmake --build --preset <name> configure and build the same way regardless of platform.

Using the bundled CMake presets

On Debian-based distributions (Debian / Ubuntu), in the repository root:

bash
cmake --preset ubuntu
cmake --build --preset ubuntu

On Windows from a regular Windows shell (PowerShell or cmd), in the repository root:

PowerShell
cmake --preset windows
cmake --build --preset windows

That configures both examples and produces two binaries:

bash
./build/<platform>/examples/basic_example/basic_example
./build/<platform>/examples/lvgl_safe_api_tour/lvgl_safe_api_tour

The top-level CMakeLists.txt looks for lvgl_safe-x.y.z-<platform>/ subdirectories next to it and imports the library through the CMake config package each one ships (lib/cmake/lvgl_safe/). Only the subdirectory whose name matches the host platform (linux, windows) is considered, so the same command resolves to the right static library. To use a copy kept somewhere else instead, point at the directory that contains include/ and lib/. For Ubuntu:

bash
cmake --preset ubuntu -DLS_PACKAGE_PREFIX=/path/to/lvgl_safe-0.1.0-linux-x86_64

A successful configure prints the version and location it resolved:

bash
-- Found LVGL Safe 0.1.0 in /path/to/lvgl_safe
-- SDL2 target for examples: SDL2::SDL2

Linking your own application against the library is the same two lines the examples use (see examples/basic_example/CMakeLists.txt) - every font and image is a generated C file you list alongside your own sources:

cmake
add_executable(my_app main.c fonts/my_font.c images/my_image.c)
target_link_libraries(my_app PRIVATE lvgl_safe::lvgl_safe ${LS_SDL2_LIBRARY})

Compile-time configuration

Features are selected in a single header, ls_conf.h (in each platform package's include/) - for example LS_USE_INDEV, LS_USE_RENDER_TEXT or LS_USE_RENDER_IMAGE_ROTATED.

Note on ls_conf.h: the shipped ls_conf.h is authoritative, and the copies in the example folders are identical to it. Its values are already compiled into the static library and baked into the struct layouts in include/, so it must not be edited - every feature of the preview library is enabled as shipped.

3. The two examples

We suggest trying the examples in this order.

lvgl_safe_api_tour - what the library can do

A deck of eleven screens, one topic per screen, at 1024x600. Click the arrows in the footer to move through it; the deck wraps around in both directions. The UP/DOWN keys move the keyboard focus - most screens have only the footer's language button to focus, but the ls_button and event-callback screens have several.

It covers every widget type in v0.1.0 - rectangle, label, arc, button, image button, image - and all four extension points: the input event callback, custom hit testing, a per-widget render hook, and a whole-screen render hook. Nothing is hidden behind a helper function, so each screen doubles as reference code for the topic it names.

The whole deck is translated. The footer button cycles English, German and French, and every string on screen follows it, because the labels are bound to an ls_translation_t rather than to a literal. The text itself lives in examples/lvgl_safe_api_tour/translations.c - one row per string, three languages per row - so main.c holds the layout and the logic and none of the wording. The only strings it builds itself are the ones that are not language at all, like the 01 / 11 slide counter.

Start here to see the capabilities. → examples/lvgl_safe_api_tour/main.c

basic_example - how an application is put together

One display, two screens, one widget of each basic kind, and a few callbacks, at 800x480. Every element carries a dimmed tag naming its widget type, so what you see on screen maps directly onto the code.

STEP +10 and RESET drive a single application variable; the readout and the arc both follow it, and the switch shows and hides the arc. The arrow icons move between the two screens - the second screen reads the same variable, which shows that application state is not owned by a screen.

This is the file to copy from when starting your own application. It is laid out to show the general shape of every LVGL Safe program: give the display a framebuffer you own, init a screen, create widgets onto it, configure them by writing struct fields, then loop over input, render, and flush.

Two properties worth noticing as you read: every widget is a caller-owned static struct created once at start-up - nothing is allocated at runtime and nothing is ever destroyed - and every fallible call returns an ls_error_code_t that is checked at the call site.

See → examples/basic_example/main.c

For a line-by-line walkthrough of that shape, see Your first program.

4. If something goes wrong

SymptomCause
No unpacked LVGL Safe package for '<platform>' found in ...no lvgl_safe-x.y.z-<platform>/ subdirectory was found for the host platform - extract the matching package as a sibling of CMakeLists.txt (not directly into the repository root), or pass -DLS_PACKAGE_PREFIX=<path>
... does not look like an unpacked LVGL Safe packagethe path given to -DLS_PACKAGE_PREFIX is not the directory holding include/ and lib/ (lib/cmake/lvgl_safe/lvgl_safeConfig.cmake was not found there)
SDL2 not found at configure timeinstall the SDL2 development package, not just the runtime
A widget draws nothing, no errorits width/height are still 0, common.hidden is set, or it is a button in a checked state that was never given a color and opacity - those five states default to transparent
ls_render() returns 3 (LS_ERROR_CODE_INVALID_CONFIGURATION)some widget on the active screen is missing a required source: a label with no font, an image with no src, or an image button whose current state's src_* is NULL. One such widget fails the whole frame
A widget was configured but nothing changedthe fields were set before ls_<widget>_create(), which resets the struct - always configure after creating

Last updated on

On this page