From a8f30120ce6f2f70542b2cad17ad14bcd04ac277 Mon Sep 17 00:00:00 2001 From: Vincent Hamp Date: Mon, 22 Nov 2021 10:51:51 +0100 Subject: [PATCH] fix(CMake) split CMakeLists.txt, add options, includes and dependencies (#2753) * fix(CMake) split CMakeLists.txt, add options, includes and dependencies * fix(CMake) do not use 'project' keyword with ESP_PLATFORM * fix(CMake) prefix includes with CMAKE_CURRENT_LIST_DIR * Don't depend on CMAKE_CURRENT_SOURCE_DIR * fix(CMake) rename baremetal.cmake to custom.cmake * fix(CMake) add CMake documentation --- CMakeLists.txt | 103 +++++--------------------------------- cmake/custom.cmake | 61 ++++++++++++++++++++++ cmake/esp.cmake | 33 ++++++++++++ cmake/micropython.cmake | 18 +++++++ cmake/zephyr.cmake | 14 ++++++ docs/get-started/cmake.md | 91 +++++++++++++++++++++++++++++++++ docs/get-started/index.md | 1 + 7 files changed, 231 insertions(+), 90 deletions(-) create mode 100644 cmake/custom.cmake create mode 100644 cmake/esp.cmake create mode 100644 cmake/micropython.cmake create mode 100644 cmake/zephyr.cmake create mode 100644 docs/get-started/cmake.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d473e0ed..c064ef2b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,94 +1,17 @@ -if(ESP_PLATFORM) - - file(GLOB_RECURSE SOURCES src/*.c) - - idf_build_get_property(LV_MICROPYTHON LV_MICROPYTHON) - - if (LV_MICROPYTHON) - idf_component_register(SRCS ${SOURCES} - INCLUDE_DIRS . src ../ - REQUIRES main) - else() - idf_component_register(SRCS ${SOURCES} - INCLUDE_DIRS . src ../) - endif() - - target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE") - - if (CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM) - target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR") - endif() - -elseif(ZEPHYR_BASE) - - if(CONFIG_LVGL) - - zephyr_include_directories(${ZEPHYR_BASE}/lib/gui/lvgl) - - target_include_directories(lvgl INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - - zephyr_compile_definitions(LV_CONF_KCONFIG_EXTERNAL_INCLUDE=) - - zephyr_library() - - file(GLOB_RECURSE SOURCES src/*.c) - zephyr_library_sources(${SOURCES}) - - endif(CONFIG_LVGL) - -else() - - file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) - file(GLOB_RECURSE EXAMPLE_SOURCES ${CMAKE_CURRENT_LIST_DIR}/examples/*.c) - - if(MICROPY_DIR) - # with micropython, build lvgl as interface library - # link chain is: lvgl_interface [lvgl] → usermod_lvgl_bindings [lv_bindings] → usermod [micropython] → firmware [micropython] - add_library(lvgl_interface INTERFACE) - # ${SOURCES} must NOT be given to add_library directly for some reason (won't be built) - target_sources(lvgl_interface INTERFACE ${SOURCES}) - # Micropython builds with -Werror; we need to suppress some warnings, such as: - # - # /home/test/build/lv_micropython/ports/rp2/build-PICO/lv_mp.c:29316:16: error: 'lv_style_transition_dsc_t_path_xcb_callback' defined but not used [-Werror=unused-function] - # 29316 | STATIC int32_t lv_style_transition_dsc_t_path_xcb_callback(const struct _lv_anim_t * arg0) - # | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - target_compile_options(lvgl_interface INTERFACE -Wno-unused-function) - else(MICROPY_DIR) - # without micropython, build lvgl and examples libs normally - # default linux build uses this scope - add_library(lvgl STATIC ${SOURCES}) - add_library(lvgl_examples STATIC ${EXAMPLE_SOURCES}) - - include_directories(${CMAKE_SOURCE_DIR}) - - # Lbrary and headers can be installed to system using make install - file(GLOB LVGL_PUBLIC_HEADERS - "${CMAKE_SOURCE_DIR}/lv_conf.h" - "${CMAKE_SOURCE_DIR}/lvgl.h") - - if("${LIB_INSTALL_DIR}" STREQUAL "") - set(LIB_INSTALL_DIR "lib") - endif() - if("${INC_INSTALL_DIR}" STREQUAL "") - set(INC_INSTALL_DIR "include/lvgl") - endif() - - install(DIRECTORY "${CMAKE_SOURCE_DIR}/src" - DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/" - FILES_MATCHING - PATTERN "*.h") - - set_target_properties(lvgl PROPERTIES - OUTPUT_NAME lvgl - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" - PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}") - - install(TARGETS lvgl - ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" - PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}") - - endif(MICROPY_DIR) +cmake_minimum_required(VERSION 3.12.4) +if(NOT ESP_PLATFORM) + project(lvgl HOMEPAGE_URL https://github.com/lvgl/lvgl) endif() +set(LVGL_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) +if(ESP_PLATFORM) + include(${CMAKE_CURRENT_LIST_DIR}/cmake/esp.cmake) +elseif(ZEPHYR_BASE) + include(${CMAKE_CURRENT_LIST_DIR}/cmake/zephyr.cmake) +elseif(MICROPY_DIR) + include(${CMAKE_CURRENT_LIST_DIR}/cmake/micropython.cmake) +else() + include(${CMAKE_CURRENT_LIST_DIR}/cmake/custom.cmake) +endif() diff --git a/cmake/custom.cmake b/cmake/custom.cmake new file mode 100644 index 000000000..3f1c69b0a --- /dev/null +++ b/cmake/custom.cmake @@ -0,0 +1,61 @@ +# Option to define LV_LVGL_H_INCLUDE_SIMPLE, default: ON +option(LV_LVGL_H_INCLUDE_SIMPLE + "Use #include \"lvgl.h\" instead of #include \"../../lvgl.h\"" ON) + +# Option to define LV_CONF_INCLUDE_SIMPLE, default: ON +option(LV_CONF_INCLUDE_SIMPLE + "Simple include of \"lv_conf.h\" and \"lv_drv_conf.h\"" ON) + +# Option to set LV_CONF_PATH, if set parent path LV_CONF_DIR is added to +# includes +option(LV_CONF_PATH "Path defined for lv_conf.h") +get_filename_component(LV_CONF_DIR ${LV_CONF_PATH} DIRECTORY) + +file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c) +file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c) + +add_library(lvgl STATIC ${SOURCES}) +add_library(lvgl::lvgl ALIAS lvgl) +add_library(lvgl_examples STATIC ${EXAMPLE_SOURCES}) +add_library(lvgl::examples ALIAS lvgl_examples) + +target_compile_definitions( + lvgl PUBLIC $<$:LV_LVGL_H_INCLUDE_SIMPLE> + $<$:LV_CONF_INCLUDE_SIMPLE>) + +# Include root and optional parent path of LV_CONF_PATH +target_include_directories(lvgl SYSTEM PUBLIC ${LVGL_ROOT_DIR} ${LV_CONF_DIR}) + +# Include /examples folder +target_include_directories(lvgl_examples SYSTEM + PUBLIC ${LVGL_ROOT_DIR}/examples) + +target_link_libraries(lvgl_examples PUBLIC lvgl) + +# Lbrary and headers can be installed to system using make install +file(GLOB LVGL_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_conf.h" + "${CMAKE_SOURCE_DIR}/lvgl.h") + +if("${LIB_INSTALL_DIR}" STREQUAL "") + set(LIB_INSTALL_DIR "lib") +endif() +if("${INC_INSTALL_DIR}" STREQUAL "") + set(INC_INSTALL_DIR "include/lvgl") +endif() + +install( + DIRECTORY "${CMAKE_SOURCE_DIR}/src" + DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/" + FILES_MATCHING + PATTERN "*.h") + +set_target_properties( + lvgl + PROPERTIES OUTPUT_NAME lvgl + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}") + +install( + TARGETS lvgl + ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" + PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}") diff --git a/cmake/esp.cmake b/cmake/esp.cmake new file mode 100644 index 000000000..a8671da25 --- /dev/null +++ b/cmake/esp.cmake @@ -0,0 +1,33 @@ +file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c) + +idf_build_get_property(LV_MICROPYTHON LV_MICROPYTHON) + +if(LV_MICROPYTHON) + idf_component_register( + SRCS + ${SOURCES} + INCLUDE_DIRS + ${LVGL_ROOT_DIR} + ${LVGL_ROOT_DIR}/src + ${LVGL_ROOT_DIR}/../ + REQUIRES + main) + + target_compile_definitions(${COMPONENT_LIB} + INTERFACE "-DLV_CONF_INCLUDE_SIMPLE") + + if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM) + target_compile_definitions(${COMPONENT_LIB} + INTERFACE "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR") + endif() +else() + idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_ROOT_DIR} + ${LVGL_ROOT_DIR}/src ${LVGL_ROOT_DIR}/../) + + target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE") + + if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM) + target_compile_definitions(${COMPONENT_LIB} + PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR") + endif() +endif() diff --git a/cmake/micropython.cmake b/cmake/micropython.cmake new file mode 100644 index 000000000..43ce7c4f4 --- /dev/null +++ b/cmake/micropython.cmake @@ -0,0 +1,18 @@ +file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c) +file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c) + +# With micropython, build lvgl as interface library, link chain is: +# lvgl_interface [lvgl] → usermod_lvgl_bindings [lv_bindings] → usermod +# [micropython] → firmware [micropython] +add_library(lvgl_interface INTERFACE) +# ${SOURCES} must NOT be given to add_library directly for some reason (won't be +# built) +target_sources(lvgl_interface INTERFACE ${SOURCES}) +# Micropython builds with -Werror; we need to suppress some warnings, such as: +# +# /home/test/build/lv_micropython/ports/rp2/build-PICO/lv_mp.c:29316:16: error: +# 'lv_style_transition_dsc_t_path_xcb_callback' defined but not used +# [-Werror=unused-function] 29316 | STATIC int32_t +# lv_style_transition_dsc_t_path_xcb_callback(const struct _lv_anim_t * arg0) | +# ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +target_compile_options(lvgl_interface INTERFACE -Wno-unused-function) diff --git a/cmake/zephyr.cmake b/cmake/zephyr.cmake new file mode 100644 index 000000000..f9ae517e7 --- /dev/null +++ b/cmake/zephyr.cmake @@ -0,0 +1,14 @@ +if(CONFIG_LVGL) + + zephyr_include_directories(${ZEPHYR_BASE}/lib/gui/lvgl) + + target_include_directories(lvgl INTERFACE ${LVGL_ROOT_DIR}) + + zephyr_compile_definitions(LV_CONF_KCONFIG_EXTERNAL_INCLUDE=) + + zephyr_library() + + file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c) + zephyr_library_sources(${SOURCES}) + +endif(CONFIG_LVGL) diff --git a/docs/get-started/cmake.md b/docs/get-started/cmake.md new file mode 100644 index 000000000..39d0cc66e --- /dev/null +++ b/docs/get-started/cmake.md @@ -0,0 +1,91 @@ +```eval_rst +.. include:: /header.rst +:github_url: |github_link_base|/get-started/cmake.md +``` + +# CMake +LVGL supports integrating with [CMake](https://cmake.org/). It comes with preconfigured targets for: +- [Espressif (ESP32)](https://docs.espressif.com/projects/esp-idf/en/v3.3/get-started-cmake/index.html) +- [MicroPython](https://docs.micropython.org/en/v1.15/develop/cmodules.html) +- [Zephyr](https://docs.zephyrproject.org/latest/guides/zephyr_cmake_package.html) + +On top of the preconfigured targets you can also use "plain" CMake to integrate LVGL into any custom C/C++ project. + +### Prerequisites +- CMake ( >= 3.12.4 ) +- Compatible build tool e.g. + - [Make](https://www.gnu.org/software/make/) + - [Ninja](https://ninja-build.org/) + +## Building LVGL with CMake +There are many ways to include external CMake projects into your own. A modern one also used in this example is the CMake [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module. This module conveniently allows us to download dependencies directly at configure time from e.g. [GitHub](https://github.com/). Here is an example how we might include LVGL into our own project. + +```cmake +cmake_minimum_required(VERSION 3.14) +include(FetchContent) + +project(MyProject LANGUAGES C CXX) + +# Build an executable called "MyFirmware" +add_executable(MyFirmware src/main.c) + +# Specify path to own LVGL config header +set(LV_CONF_PATH + ${CMAKE_CURRENT_SOURCE_DIR}/src/lv_conf.h + CACHE STRING "" FORCE) + +# Fetch LVGL from GitHub +FetchContent_Declare(lvgl URL https://github.com/lvgl/lvgl.git) +FetchContent_MakeAvailable(lvgl) + +# The target "MyFirmware" depends on LVGL +target_link_libraries(MyFirmware PRIVATE lvgl::lvgl) +``` + +This configuration declares a dependency between the two targets **MyFirmware** and **lvgl**. Upon building the target **MyFirmware** this dependency will be resolved and **lvgl** will be built and linked with it. Since LVGL requires a config header called [lv_conf.h](https://github.com/lvgl/lvgl/blob/master/lv_conf_template.h) to be includable by its sources we also set the option `LV_CONF_PATH` to point to our own copy of it. + +### Additional CMake options +Besides `LV_CONF_PATH` there are two additional CMake options to specify include paths. + +`LV_LVGL_H_INCLUDE_SIMPLE` which specifies whether to `#include "lvgl.h"` absolut or relative +| ON (default) | OFF | +| ------------ | -------------- | +| "lvgl.h" | "../../lvgl.h" | + +`LV_CONF_INCLUDE_SIMPLE` which specifies whether to `#include "lv_conf.h"` and `"lv_drv_conf.h"` absolut or relative +| ON (default) | OFF | +| --------------- | --------------------- | +| "lv_conf.h" | "../../lv_conf.h" | +| "lv_drv_conf.h" | "../../lv_drv_conf.h" | + +I do not recommend to disable those options unless your folder layout makes it absolutely necessary. + +## Building LVGL examples with CMake +LVGL [examples](https://docs.lvgl.io/master/examples.html) have their own CMake target. If you want to build the examples simply add them to your dependencies. + +```cmake +# The target "MyFirmware" depends on LVGL and examples +target_link_libraries(MyFirmware PRIVATE lvgl::lvgl lvgl::examples) +``` + +## Building LVGL drivers and demos with CMake +Exactly the same goes for the [drivers](https://github.com/lvgl/lv_drivers) and the [demos](https://github.com/lvgl/lv_demos). + +```cmake +# Specify path to own LVGL demos config header +set(LV_DEMO_CONF_PATH + ${CMAKE_CURRENT_SOURCE_DIR}/src/lv_demo_conf.h + CACHE STRING "" FORCE) + +FetchContent_Declare(lv_drivers + GIT_REPOSITORY https://github.com/lvgl/lv_drivers) +FetchContent_MakeAvailable(lv_drivers) +FetchContent_Declare(lv_demos + GIT_REPOSITORY https://github.com/lvgl/lv_demos.git) +FetchContent_MakeAvailable(lv_demos) + +# The target "MyFirmware" depends on LVGL, drivers and demos +target_link_libraries(MyFirmware PRIVATE lvgl::lvgl lvgl::drivers lvgl::examples) +``` + +Just like the [lv_conf.h](https://github.com/lvgl/lvgl/blob/master/lv_conf_template.h) header demos comes with its own config header called [lv_demo_conf.h](https://github.com/lvgl/lv_demos/blob/master/lv_demo_conf_template.h). Analogous to `LV_CONF_PATH` its path can be set by using the option `LV_DEMO_CONF_PATH`. \ No newline at end of file diff --git a/docs/get-started/index.md b/docs/get-started/index.md index 42cbeb3c9..ea8b57933 100644 --- a/docs/get-started/index.md +++ b/docs/get-started/index.md @@ -30,5 +30,6 @@ There are several ways to get your feet wet with LVGL. Here is one recommended o arduino micropython nuttx + cmake ```