On an MCU, LVGL has no dependencies. Point your compiler at the sources and you are done. Move up to an MPU and that changes quickly:
a Linux build can pull in Wayland, libdrm, EGL, OpenGL ES, xkbcommon, libinput, FreeType, and more. Worse, the exact set depends on
what you turned on in lv_conf.h. Writing that list into your own build by hand is tedious, easy to get wrong, and out of date the
moment someone flips a config option.
So LVGL v9.6 writes it down for you. Install LVGL and it ships an lvgl.pc and an lvglConfig.cmake that already name every library
it was compiled against. Building an app against it becomes a one-liner:
gcc main.c -o main $(pkg-config --cflags --static --libs lvgl)bashEither way there is no dependency list of your own to maintain, and if you rebuild LVGL with a different feature set, the same lines keep working.
Part one covered how LVGL parses lv_conf.h to find and fetch its dependencies
automatically. This is the second payoff of that work: because LVGL already knows exactly what it needs, it can pass that knowledge on
to everyone building against it.
Two Ways to Link Against an Installed Library#
Say you've built and installed LVGL as a static library, with SDL2 and FreeType turned on. To compile a small app against it, your compiler needs three things: LVGL's headers, the LVGL library itself, and every other library LVGL depends on. On Linux there are two common ways to point it at all three, and LVGL now supports both.
The first is pkg-config. A library installs a short .pc file that describes itself, and you ask pkg-config for the flags:
pkg-config --cflags --libs lvgl
# -I/usr/local/include -L/usr/local/lib -llvglbashPaste that in your application's build command and it links.
The second is CMake's find_package. The library installs a lvglConfig.cmake file, and your project picks it up:
find_package(lvgl REQUIRED)
target_link_libraries(app PRIVATE lvgl::lvgl)cmakeBoth carry the same responsibility: they have to name every library LVGL depends on. This matters most when you link LVGL statically,
because then the final link has to resolve every symbol at once, including the ones coming from SDL2, FreeType, and the C math library.
A .pc file keeps those in its Requires.private and Libs.private fields, and CMake covers them with find_dependency calls.
Generating the Config Files#
Because that list changes with the configuration, neither file can be shipped as a fixed text, both have to be generated. That turns out to be the easy part: LVGL already works out its dependencies in order to build itself, so it only has to write down what it used as it goes.
Part one's dependency handling already walks through every optional library one at a time and decides how to satisfy it.
The generation step rides along with that. As each dependency is resolved, LVGL records how a downstream project would find the same library:
its CMake package name for find_package and its pkg-config module name for Requires.
When configuration finishes, those records go straight into the generated lvgl.pc and lvglConfig.cmake.
The result always matches what you actually built: compile LVGL with SDL2 and FreeType, and the generated lvgl.pc lists sdl2 and freetype2.
Using It in Your Project#
None of that is visible from the outside. You install LVGL once and then link against it however you normally would.
Start by building and installing. Here we pick the feature set with a Kconfig defconfig and install it in the standard system libraries directories:
cmake -B build -GNinja \
-DLV_BUILD_USE_KCONFIG=ON \
-DLV_BUILD_DEFCONFIG_PATH=configs/defconfigs/linux.defconfig
cmake --build build
cmake --install buildbashThat puts lvgl.pc and lvglConfig.cmake in the standard locations pkg-config and CMake already search, next to the headers and the library.
The application itself is just an ordinary LVGL program, the same one we've used in the first part of the series.
#include <lvgl/lvgl.h>
int main(void)
{
lv_init();
lv_display_t * disp = lv_sdl_window_create(800, 600);
if(!disp) {
return 1;
}
lv_sdl_mouse_create();
lv_obj_t * button = lv_button_create(lv_screen_active());
lv_obj_t * label = lv_label_create(button);
lv_label_set_text_static(label, "Click Me!");
lv_obj_center(button);
while(1) {
lv_timer_handler();
lv_sleep_ms(5);
}
return 0;
}cBuild it whichever way suits your project:
# --static pulls in Requires.private and Libs.private too
gcc main.c -o main $(pkg-config --cflags --static --libs lvgl)bashEither way, you never repeat LVGL's dependency list in your own build. The SDL2 and FreeType you compiled into LVGL are pulled in for you.
Wrap Up#
There wasn't much to invent here. Most of the job was keeping information LVGL already had instead of throwing it away once the build
finished. What you get out of it is one less list to maintain: whatever LVGL was built with, pkg-config and find_package will hand
it to your compiler.
In the last part we hand these generated files to a package manager. We'll add an LVGL repository to a fresh Ubuntu install and get the same program running with apt and nothing else.
- Getting Started with LVGL v9.6 with 50 Lines of Code
- 2Installing LVGL, Dependencies IncludedYou are here
- 3apt install lvgl
- 4LVGL with Ubuntu on the RZ/G2L


