前言
最近在基于LVGL v9版本进行项目开发,在开发过程中顺便研究了整个项目的CMake构建原理,以可以支持更好的自定义。因此本篇文章将刨析LVGL v9项目的CMake构建原理,让我们对LVGL v9的项目框架有个更好的理解。
源码分析
本篇文章基于 https://github.com/lvgl/lv_port_linux_frame_buffer.git 项目进行分析,这个项目主要用于Linux上,但构建的思路都是差不多的,只要能看懂这个项目,其他项目也一样能看懂。
接下来的分析需要具备 CMake 和 Makefile 的前置知识,学习 CMake 可以看我这篇《CMake实战教程》文章,干货满满。
根 CMakeLists.txt
源码如下:
cmake_minimum_required(VERSION 3.10)
project(lvgl)
set(CMAKE_C_STANDARD 99)#C99 # lvgl officially support C99 and above
set(CMAKE_CXX_STANDARD 17)#C17
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_subdirectory(lvgl)
target_include_directories(lvgl PUBLIC ${PROJECT_SOURCE_DIR})
add_executable(main main.c mouse_cursor_icon.c)
include(${CMAKE_CURRENT_LIST_DIR}/lvgl/tests/FindLibDRM.cmake)
include_directories(${Libdrm_INCLUDE_DIRS})
find_package(SDL2)
find_package(SDL2_image)
include_directories(${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS})
target_link_libraries(main lvgl lvgl::examples lvgl::demos lvgl::thorvg ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES} ${Libdrm_LIBRARIES} m pthread)
add_custom_target (run COMMAND ${EXECUTABLE_OUTPUT_PATH}/main DEPENDS main)
CMake构建的最低三要素是:
cmake_minimum_required
:cmake最低版本号;project
:项目名称;add_executable
:要编译的可执行文件;
从上面的源码我们可以得到三要素的信息是:CMake版本号最低是3.10,项目名称叫做lvgl,最终编译并链接后的可执行文件的产物是main文件。
基于这个基础上,就可以拓展开其他了,其他的api,都是围绕着三要素进行,特别是最后一个,要编译的可执行文件,因为最终目标就是编译一个二进制可执行文件。
这里回顾一下 C 编译成最终产物经历的阶段:源文件(.c) -> 预处理(.i) -> 编译(.s) -> 汇编(.o) -> 链接 -> 可执行文件。
其他的api,也是围绕这个流程来构建的,CMake的api提高了我们编写构建项目脚本的效率,但它的本质并没有改变。
因此我们从上面的CMake源码可以得出如下的结论:
set
设置了一些变量,用于指定编译器的版本;add_subdirectory
去指定的lvgl目录查找新的CMakeLists.txt文件并执行它的构建;target_include_directories
为目标添加头文件的查找路径,对应c编译过程的预处理;include
将指定的cmake文件加载进来并继续执行,可以理解成c的宏;find_package
去查找SDL2和SDL2_image的库文件,并链接到目标,也就是最终的可执行文件main,这一步对应c编译过程的链接。add_custom_target
创建一个名为run
的自定义目标,该目标会运行生成的可执行文件main
,并且run
目标依赖于main
目标,确保main
在运行前已经成功构建。
下面是详细的注释说明:
# 设置最低的CMake版本要求为3.10
cmake_minimum_required(VERSION 3.10)
# 定义项目名称为lvgl
project(lvgl)
# 设置C标准为C99
set(CMAKE_C_STANDARD 99) # C99是lvgl官方支持的标准
# 设置C++标准为C++17
set(CMAKE_CXX_STANDARD 17) # C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 确保编译器必须支持C++17
# 设置生成的可执行文件的输出目录为项目根目录下的bin目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 添加并处理lvgl子目录中的CMakeLists.txt文件
add_subdirectory(lvgl)
# 将项目根目录添加到lvgl目标的包含路径中
target_include_directories(lvgl PUBLIC ${PROJECT_SOURCE_DIR})
# 定义一个名为main的可执行文件,并包含源文件main.c和mouse_cursor_icon.c
add_executable(main main.c mouse_cursor_icon.c)
# 包含并执行FindLibDRM.cmake文件,用于查找并配置LibDRM库
include(${CMAKE_CURRENT_LIST_DIR}/lvgl/tests/FindLibDRM.cmake)
# 将LibDRM库的包含目录添加到项目中
include_directories(${Libdrm_INCLUDE_DIRS})
# 查找并配置SDL2库
find_package(SDL2)
# 查找并配置SDL2_image库
find_package(SDL2_image)
# 将SDL2和SDL2_image库的包含目录添加到项目中
include_directories(${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS})
# 将多个库链接到main可执行文件中
target_link_libraries(main
lvgl # lvgl库
lvgl::examples # lvgl示例模块
lvgl::demos # lvgl演示模块
lvgl::thorvg # lvgl的thorvg模块
${SDL2_LIBRARIES} # SDL2库
${SDL2_IMAGE_LIBRARIES} # SDL2_image库
${Libdrm_LIBRARIES} # LibDRM库
m # 数学库
pthread # POSIX线程库
)
# 创建一个名为run的自定义目标,该目标会运行生成的main可执行文件
# 并且run目标依赖于main目标,确保main在运行前已经成功构建
add_custom_target(run
COMMAND ${EXECUTABLE_OUTPUT_PATH}/main
DEPENDS main
)
lvgl 文件夹下的 CMakeLists.txt
从上面我们可以得知,这个lvgl文件夹下的 CMakeLists.txt 也是在为最终可执行文件 main 服务的,它的职责是负责生成 lvgl 相关的静态库(.a),并最终链接到 main.o 上生成 main 可执行文件。
cmake_minimum_required(VERSION 3.12.4)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(NOT ESP_PLATFORM)
project(lvgl LANGUAGES C CXX ASM HOMEPAGE_URL https://github.com/lvgl/lvgl)
endif()
set(LVGL_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR})
if(ESP_PLATFORM)
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/esp.cmake)
elseif(ZEPHYR_BASE)
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/zephyr.cmake)
elseif(MICROPY_DIR)
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/micropython.cmake)
else()
include(${CMAKE_CURRENT_LIST_DIR}/env_support/cmake/custom.cmake)
endif()
#[[
unfortunately CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS does not work for global data.
for global data we still need decl specs.
Check out the docs to learn more about the limitations of CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
https://cmake.org/cmake/help/latest/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.html#prop_tgt:WINDOWS_EXPORT_ALL_SYMBOLS
For all compiled sources within the library (i.e. basically all lvgl files) we need to use dllexport.
For all compiled sources from outside the library (i.e. files which include lvgl headers) we need to use dllimport.
We can do this by using CMakes INTERFACE and PRIVATE keyword.
]]
if (MSVC)
target_compile_definitions(lvgl
INTERFACE LV_ATTRIBUTE_EXTERN_DATA=__declspec\(dllimport\)
PRIVATE LV_ATTRIBUTE_EXTERN_DATA=__declspec\(dllexport\)
)
endif()
这个 CMakeLists.txt 比较简单,主要是判断平台,设置变量,并根据不同的平台执行不同的 .cmake 文件。
Linux平台是属于else()
中,也就是 custom.cmake 文件。通过判断不同平台,lvgl可以做到适应多个开发板多种操作系统多种平台,并实现解耦,这个设计思想,值得我们学习。
custom.cmake
这个CMake可以说是整个项目的构建核心,它解释了lvgl库是如何构建的,源码如下:
# 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
"Use #include \"lv_conf.h\" instead of #include \"../../lv_conf.h\"" ON)
# Option LV_CONF_PATH, which should be the path for lv_conf.h
# If set parent path LV_CONF_DIR is added to includes
if( LV_CONF_PATH )
get_filename_component(LV_CONF_DIR ${LV_CONF_PATH} DIRECTORY)
endif( LV_CONF_PATH )
# Option to build shared libraries (as opposed to static), default: OFF
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
# Set sources used for LVGL components
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c ${LVGL_ROOT_DIR}/src/*.S)
file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c)
file(GLOB_RECURSE DEMO_SOURCES ${LVGL_ROOT_DIR}/demos/*.c)
file(GLOB_RECURSE THORVG_SOURCES ${LVGL_ROOT_DIR}/src/libs/thorvg/*.cpp ${LVGL_ROOT_DIR}/src/others/vg_lite_tvg/*.cpp)
# Build LVGL library
add_library(lvgl ${SOURCES})
add_library(lvgl::lvgl ALIAS lvgl)
target_compile_definitions(
lvgl PUBLIC $<$<BOOL:${LV_LVGL_H_INCLUDE_SIMPLE}>:LV_LVGL_H_INCLUDE_SIMPLE>
$<$<BOOL:${LV_CONF_INCLUDE_SIMPLE}>:LV_CONF_INCLUDE_SIMPLE>
$<$<COMPILE_LANGUAGE:ASM>:__ASSEMBLY__>)
# Add definition of LV_CONF_PATH only if needed
if(LV_CONF_PATH)
target_compile_definitions(lvgl PUBLIC LV_CONF_PATH=${LV_CONF_PATH})
endif()
# Add definition of LV_CONF_SKIP only if needed
if(LV_CONF_SKIP)
target_compile_definitions(lvgl PUBLIC LV_CONF_SKIP=1)
endif()
# Include root and optional parent path of LV_CONF_PATH
target_include_directories(lvgl SYSTEM PUBLIC ${LVGL_ROOT_DIR} ${LV_CONF_DIR})
if(NOT LV_CONF_BUILD_DISABLE_THORVG_INTERNAL)
add_library(lvgl_thorvg ${THORVG_SOURCES})
add_library(lvgl::thorvg ALIAS lvgl_thorvg)
target_include_directories(lvgl_thorvg SYSTEM PUBLIC ${LVGL_ROOT_DIR}/src/libs/thorvg)
target_link_libraries(lvgl_thorvg PUBLIC lvgl)
endif()
# Build LVGL example library
if(NOT LV_CONF_BUILD_DISABLE_EXAMPLES)
add_library(lvgl_examples ${EXAMPLE_SOURCES})
add_library(lvgl::examples ALIAS lvgl_examples)
target_include_directories(lvgl_examples SYSTEM PUBLIC ${LVGL_ROOT_DIR}/examples)
target_link_libraries(lvgl_examples PUBLIC lvgl)
endif()
# Build LVGL demos library
if(NOT LV_CONF_BUILD_DISABLE_DEMOS)
add_library(lvgl_demos ${DEMO_SOURCES})
add_library(lvgl::demos ALIAS lvgl_demos)
target_include_directories(lvgl_demos SYSTEM PUBLIC ${LVGL_ROOT_DIR}/demos)
target_link_libraries(lvgl_demos PUBLIC lvgl)
endif()
# 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("${RUNTIME_INSTALL_DIR}" STREQUAL "")
set(RUNTIME_INSTALL_DIR "bin")
endif()
if("${INC_INSTALL_DIR}" STREQUAL "")
set(INC_INSTALL_DIR "include/lvgl")
endif()
#Install headers
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h")
# install example headers
if(NOT LV_CONF_BUILD_DISABLE_EXAMPLES)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h")
endif()
# install demo headers
if(NOT LV_CONF_BUILD_DISABLE_DEMOS)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/demos"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h")
endif()
configure_file("${LVGL_ROOT_DIR}/lvgl.pc.in" lvgl.pc @ONLY)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/lvgl.pc"
DESTINATION "${LIB_INSTALL_DIR}/pkgconfig/")
# Install library
set_target_properties(
lvgl
PROPERTIES OUTPUT_NAME lvgl
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
# Install library thorvg
if(NOT LV_CONF_BUILD_DISABLE_THORVG_INTERNAL)
set_target_properties(
lvgl_thorvg
PROPERTIES OUTPUT_NAME lvgl_thorvg
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl_thorvg
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
endif()
# Install library demos
if(NOT LV_CONF_BUILD_DISABLE_DEMOS)
set_target_properties(
lvgl_demos
PROPERTIES OUTPUT_NAME lvgl_demos
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl_demos
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
endif()
#install library examples
if(NOT LV_CONF_BUILD_DISABLE_EXAMPLES)
set_target_properties(
lvgl_examples
PROPERTIES OUTPUT_NAME lvgl_examples
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl_examples
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
endif()
上面的源码看起来好像很多,但其实刨去一些不是重要的点,实际的源码就下面这几行:
# Set sources used for LVGL components
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c ${LVGL_ROOT_DIR}/src/*.S)
# Build LVGL library
add_library(lvgl ${SOURCES})
add_library(lvgl::lvgl ALIAS lvgl)
target_compile_definitions(
lvgl PUBLIC $<$<BOOL:${LV_LVGL_H_INCLUDE_SIMPLE}>:LV_LVGL_H_INCLUDE_SIMPLE>
$<$<BOOL:${LV_CONF_INCLUDE_SIMPLE}>:LV_CONF_INCLUDE_SIMPLE>
$<$<COMPILE_LANGUAGE:ASM>:__ASSEMBLY__>)
# Include root and optional parent path of LV_CONF_PATH
target_include_directories(lvgl SYSTEM PUBLIC ${LVGL_ROOT_DIR} ${LV_CONF_DIR})
它主要做了四件事:递归查找lvgl目录下的所有的.c、.S文件;添加一个称为lvgl的静态库,它依赖的源文件就是上面查找到的那些源文件;为库目标添加预处理阶段需要查找的头文件目录;为lvgl库目标添加一些宏定义,比如LV_LVGL_H_INCLUDE_SIMPLE。
是不是整个思路立马就清晰了呢,哈哈,其实就是这么的简单。
其他的内容也都差不多,无非就是如果满足某些条件就添加demo库或example库并链接到最终的 main 可执行文件,还有提供一些安装功能,当我们输入 make install
,就会根据 install
提供的信息去进行安装,这个也很简单。
下面是对整个源代码的解释:
# 选项定义LV_LVGL_H_INCLUDE_SIMPLE,默认值为ON
option(LV_LVGL_H_INCLUDE_SIMPLE
"Use #include \"lvgl.h\" instead of #include \"../../lvgl.h\"" ON)
# 选项定义LV_CONF_INCLUDE_SIMPLE,默认值为ON
option(LV_CONF_INCLUDE_SIMPLE
"Use #include \"lv_conf.h\" instead of #include \"../../lv_conf.h\"" ON)
# 选项LV_CONF_PATH,指定lv_conf.h的路径
# 如果设置了LV_CONF_PATH,将其父路径LV_CONF_DIR添加到包含路径中
if( LV_CONF_PATH )
get_filename_component(LV_CONF_DIR ${LV_CONF_PATH} DIRECTORY)
endif( LV_CONF_PATH )
# 选项用于构建共享库(相对于静态库),默认值为OFF
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
# 设置用于LVGL组件的源文件
file(GLOB_RECURSE SOURCES ${LVGL_ROOT_DIR}/src/*.c ${LVGL_ROOT_DIR}/src/*.S)
file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c)
file(GLOB_RECURSE DEMO_SOURCES ${LVGL_ROOT_DIR}/demos/*.c)
file(GLOB_RECURSE THORVG_SOURCES ${LVGL_ROOT_DIR}/src/libs/thorvg/*.cpp ${LVGL_ROOT_DIR}/src/others/vg_lite_tvg/*.cpp)
# 构建LVGL库
add_library(lvgl ${SOURCES})
add_library(lvgl::lvgl ALIAS lvgl)
# 为lvgl目标添加编译定义
target_compile_definitions(
lvgl PUBLIC $<$<BOOL:${LV_LVGL_H_INCLUDE_SIMPLE}>:LV_LVGL_H_INCLUDE_SIMPLE>
$<$<BOOL:${LV_CONF_INCLUDE_SIMPLE}>:LV_CONF_INCLUDE_SIMPLE>
$<$<COMPILE_LANGUAGE:ASM>:__ASSEMBLY__>)
# 仅在需要时添加LV_CONF_PATH定义
if(LV_CONF_PATH)
target_compile_definitions(lvgl PUBLIC LV_CONF_PATH=${LV_CONF_PATH})
endif()
# 仅在需要时添加LV_CONF_SKIP定义
if(LV_CONF_SKIP)
target_compile_definitions(lvgl PUBLIC LV_CONF_SKIP=1)
endif()
# 包含LVGL根目录和LV_CONF_PATH的可选父路径
target_include_directories(lvgl SYSTEM PUBLIC ${LVGL_ROOT_DIR} ${LV_CONF_DIR})
# 如果未禁用内部的THORVG支持,构建lvgl_thorvg库
if(NOT LV_CONF_BUILD_DISABLE_THORVG_INTERNAL)
add_library(lvgl_thorvg ${THORVG_SOURCES})
add_library(lvgl::thorvg ALIAS lvgl_thorvg)
target_include_directories(lvgl_thorvg SYSTEM PUBLIC ${LVGL_ROOT_DIR}/src/libs/thorvg)
target_link_libraries(lvgl_thorvg PUBLIC lvgl)
endif()
# 如果未禁用示例构建,构建lvgl_examples库
if(NOT LV_CONF_BUILD_DISABLE_EXAMPLES)
add_library(lvgl_examples ${EXAMPLE_SOURCES})
add_library(lvgl::examples ALIAS lvgl_examples)
target_include_directories(lvgl_examples SYSTEM PUBLIC ${LVGL_ROOT_DIR}/examples)
target_link_libraries(lvgl_examples PUBLIC lvgl)
endif()
# 如果未禁用演示构建,构建lvgl_demos库
if(NOT LV_CONF_BUILD_DISABLE_DEMOS)
add_library(lvgl_demos ${DEMO_SOURCES})
add_library(lvgl::demos ALIAS lvgl_demos)
target_include_directories(lvgl_demos SYSTEM PUBLIC ${LVGL_ROOT_DIR}/demos)
target_link_libraries(lvgl_demos PUBLIC lvgl)
endif()
# 库和头文件可以使用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("${RUNTIME_INSTALL_DIR}" STREQUAL "")
set(RUNTIME_INSTALL_DIR "bin")
endif()
if("${INC_INSTALL_DIR}" STREQUAL "")
set(INC_INSTALL_DIR "include/lvgl")
endif()
# 安装头文件
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h")
# 安装示例头文件(如果未禁用示例构建)
if(NOT LV_CONF_BUILD_DISABLE_EXAMPLES)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h")
endif()
# 安装演示头文件(如果未禁用演示构建)
if(NOT LV_CONF_BUILD_DISABLE_DEMOS)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/demos"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/"
FILES_MATCHING
PATTERN "*.h")
endif()
# 配置并生成lvgl.pc文件,用于pkg-config
configure_file("${LVGL_ROOT_DIR}/lvgl.pc.in" lvgl.pc @ONLY)
# 安装pkg-config文件
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/lvgl.pc"
DESTINATION "${LIB_INSTALL_DIR}/pkgconfig/")
# 设置库的目标属性
set_target_properties(
lvgl
PROPERTIES OUTPUT_NAME lvgl
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
# 安装lvgl库
install(
TARGETS lvgl
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
# 安装lvgl_thorvg库(如果未禁用内部的THORVG支持)
if(NOT LV_CONF_BUILD_DISABLE_THORVG_INTERNAL)
set_target_properties(
lvgl_thorvg
PROPERTIES OUTPUT_NAME lvgl_thorvg
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl_thorvg
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
endif()
# 安装lvgl_demos库(如果未禁用演示构建)
if(NOT LV_CONF_BUILD_DISABLE_DEMOS)
set_target_properties(
lvgl_demos
PROPERTIES OUTPUT_NAME lvgl_demos
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl_demos
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
endif()
# 安装lvgl_examples库(如果未禁用示例构建)
if(NOT LV_CONF_BUILD_DISABLE_EXAMPLES)
set_target_properties(
lvgl_examples
PROPERTIES OUTPUT_NAME lvgl_examples
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PUBLIC_HEADER "${LVGL_PUBLIC_HEADERS}")
install(
TARGETS lvgl_examples
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
RUNTIME DESTINATION "${RUNTIME_INSTALL_DIR}"
PUBLIC_HEADER DESTINATION "${INC_INSTALL_DIR}")
endif()
结语
通过上面的刨析,我们了解到其实LVGL项目的CMake构建原理也不过如此。CMake的出现是为了解决跨平台构建的问题,它很大程度上提升了搭建项目框架的效率,是一个非常值得掌握的小技能之一。好了,本文到这里就结束了,感谢大家的阅读。
如果觉得本文写得还不错,请多多点赞、收藏与转发,谢谢~