mirror of
https://github.com/m5stack/CardputerZero-AppBuilder.git
synced 2026-05-20 11:51:57 -07:00
sdk/include/lv_conf.h mirrors the emulator's (music + keypad_encoder demos enabled) so apps using the SDK see the same LVGL feature set the host provides. sdk/cmake/CZApp.cmake gains: - demos/ header search path so apps can #include "widgets/lv_demo_widgets.h" etc. - NO_KBD_STUBS option for apps that want to resolve the host's real lv_sdl_keyboard_create at dlopen time (instead of the weak inert stub). Default weak stub stays for the 90% of apps that don't care about keyboard input. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
135 lines
5.6 KiB
CMake
135 lines
5.6 KiB
CMake
# CZApp.cmake — build a CardputerZero LVGL app as a shared library.
|
|
#
|
|
# Usage:
|
|
# list(APPEND CMAKE_MODULE_PATH "${path_to_sdk}/cmake")
|
|
# include(CZApp)
|
|
# cz_add_lvgl_app(my_app SOURCES src/foo.c src/bar.c)
|
|
#
|
|
# The resulting target:
|
|
# * is a SHARED library named "my_app" (→ libmy_app.dylib / .so / my_app.dll)
|
|
# * can reference any LVGL API — LVGL symbols are resolved at dlopen time
|
|
# against the host's (emulator or APPLaunch) LVGL instance
|
|
# * exports exactly the symbols declared in <cz_app.h>
|
|
#
|
|
# Required variables (auto-discovered from this file's location):
|
|
# CZ_SDK_DIR — root of the sdk/ tree (include/ + cmake/ below it)
|
|
# CZ_EMULATOR_DIR — the emulator checkout that supplies lvgl.h. Defaults to
|
|
# ${CZ_SDK_DIR}/../emulator (AppBuilder layout).
|
|
#
|
|
# See docs/DESKTOP_DEV.md for the rules an app must follow.
|
|
|
|
if(NOT DEFINED CZ_SDK_DIR)
|
|
get_filename_component(CZ_SDK_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
|
|
endif()
|
|
|
|
if(NOT DEFINED CZ_EMULATOR_DIR)
|
|
get_filename_component(CZ_EMULATOR_DIR "${CZ_SDK_DIR}/../emulator" ABSOLUTE)
|
|
endif()
|
|
|
|
set(CZ_LVGL_DIR "${CZ_EMULATOR_DIR}/lib/lvgl")
|
|
|
|
if(NOT EXISTS "${CZ_LVGL_DIR}/lvgl.h")
|
|
message(FATAL_ERROR
|
|
"CZApp: LVGL headers not found at ${CZ_LVGL_DIR}/lvgl.h. "
|
|
"Did you run `git submodule update --init --recursive` in the "
|
|
"CardputerZero-AppBuilder checkout?")
|
|
endif()
|
|
|
|
function(cz_add_lvgl_app TARGET)
|
|
# Options:
|
|
# NO_KBD_STUBS — skip the default weak lv_sdl_keyboard_create/handler
|
|
# shim. Apps that want real keyboard input (using the
|
|
# emulator's real SDL keyboard driver) should set this so
|
|
# that the symbols stay unresolved in the .dylib/.so and
|
|
# get bound to the host at dlopen time.
|
|
cmake_parse_arguments(CZA "NO_KBD_STUBS" "" "SOURCES" ${ARGN})
|
|
if(NOT CZA_SOURCES)
|
|
message(FATAL_ERROR "cz_add_lvgl_app(${TARGET}): no SOURCES given")
|
|
endif()
|
|
|
|
add_library(${TARGET} SHARED ${CZA_SOURCES})
|
|
|
|
set_target_properties(${TARGET} PROPERTIES
|
|
C_STANDARD 11
|
|
CXX_STANDARD 17
|
|
PREFIX "lib" # Windows: libfoo.dll for parity with Unix
|
|
POSITION_INDEPENDENT_CODE ON
|
|
)
|
|
|
|
target_include_directories(${TARGET} PRIVATE
|
|
"${CZ_SDK_DIR}/include" # cz_app.h + lv_conf.h
|
|
"${CZ_LVGL_DIR}" # lvgl.h
|
|
"${CZ_LVGL_DIR}/demos" # demos/widgets/lv_demo_widgets.h etc.
|
|
)
|
|
|
|
# Pinned LVGL config — must byte-match the host's.
|
|
target_compile_definitions(${TARGET} PRIVATE LV_CONF_INCLUDE_SIMPLE=1)
|
|
|
|
# Link-time behaviour: LVGL symbols stay unresolved in the app library; the
|
|
# host resolves them at dlopen/LoadLibrary time.
|
|
if(APPLE)
|
|
target_link_options(${TARGET} PRIVATE -undefined dynamic_lookup)
|
|
elseif(WIN32)
|
|
# Windows needs an import library for LVGL; see docs/DESKTOP_DEV.md §4.
|
|
# Until that lands, flag builds so they fail loud instead of producing
|
|
# a silently broken .dll.
|
|
message(WARNING
|
|
"cz_add_lvgl_app: Windows import-lib support is not implemented "
|
|
"yet (see DESKTOP_DEV.md §4). Build will likely fail at link.")
|
|
else()
|
|
target_link_options(${TARGET}
|
|
PRIVATE "LINKER:--unresolved-symbols=ignore-all")
|
|
endif()
|
|
|
|
# Compatibility shim: the current emulator dlsym's "ui_init" and calls it.
|
|
# Until the emulator switches to app_main/app_event (separate task), emit
|
|
# a one-line ui_init thunk that forwards to app_main(lv_screen_active()).
|
|
set(_thunk "${CMAKE_CURRENT_BINARY_DIR}/cz_${TARGET}_ui_init_thunk.c")
|
|
file(WRITE "${_thunk}"
|
|
"/* Auto-generated by CZApp.cmake — do not edit. */\n"
|
|
"#include <cz_app.h>\n"
|
|
"void ui_init(void) { app_main(lv_screen_active()); }\n"
|
|
)
|
|
target_sources(${TARGET} PRIVATE "${_thunk}")
|
|
|
|
# Also emit a default weak app_event so apps that only care about UI can
|
|
# skip providing one. Strong definitions in the app override this.
|
|
set(_weak "${CMAKE_CURRENT_BINARY_DIR}/cz_${TARGET}_app_event_default.c")
|
|
file(WRITE "${_weak}"
|
|
"/* Auto-generated by CZApp.cmake — default no-op app_event. */\n"
|
|
"#include <cz_app.h>\n"
|
|
"__attribute__((weak)) void app_event(int type, void *data) { (void)type; (void)data; }\n"
|
|
)
|
|
target_sources(${TARGET} PRIVATE "${_weak}")
|
|
|
|
if(CZA_NO_KBD_STUBS)
|
|
return()
|
|
endif()
|
|
|
|
# Default weak keyboard stubs. The emulator always dlsyms
|
|
# lv_sdl_keyboard_create / lv_sdl_keyboard_handler; when the app provides
|
|
# neither, the emulator falls back to a bare keypad indev with no read_cb
|
|
# and LVGL floods the log with "indev_read_cb is not registered". These
|
|
# stubs give the emulator a real (but inert) indev so the log stays clean.
|
|
# Apps that want real keyboard input pass NO_KBD_STUBS and let the
|
|
# emulator's real lv_sdl_keyboard_* resolve via dlopen.
|
|
set(_kbd "${CMAKE_CURRENT_BINARY_DIR}/cz_${TARGET}_kbd_default.c")
|
|
file(WRITE "${_kbd}"
|
|
"/* Auto-generated by CZApp.cmake — default no-op SDL keyboard stubs. */\n"
|
|
"#include <cz_app.h>\n"
|
|
"static void _cz_default_kbd_read(lv_indev_t *indev, lv_indev_data_t *data) {\n"
|
|
" (void)indev;\n"
|
|
" data->state = LV_INDEV_STATE_RELEASED;\n"
|
|
" data->key = 0;\n"
|
|
"}\n"
|
|
"__attribute__((weak)) lv_indev_t *lv_sdl_keyboard_create(void) {\n"
|
|
" lv_indev_t *kb = lv_indev_create();\n"
|
|
" lv_indev_set_type(kb, LV_INDEV_TYPE_KEYPAD);\n"
|
|
" lv_indev_set_read_cb(kb, _cz_default_kbd_read);\n"
|
|
" return kb;\n"
|
|
"}\n"
|
|
"__attribute__((weak)) void lv_sdl_keyboard_handler(void *ev) { (void)ev; }\n"
|
|
)
|
|
target_sources(${TARGET} PRIVATE "${_kbd}")
|
|
endfunction()
|