跨平台 LVGL 工程的搭建

使用开源库搭建跨平台的工程

Posted by Jerry Chen on December 9, 2020

第一步:编译 libuv 库

windows 平台

方法一
  1. 安装 VS22019 或 MinGW;
  2. CMake 下载页面 下载 cmake-3.19.1-win64-x64.zip

  3. 解压后添加 cmake 工具目录到系统环境变量 PATH;

  4. 下载 libuv 源码

  5. powershell 下查看 cmake 的生成器:

    1
    
    cmake.exe --help
    

    可以看到默认是 VS16 工程方式,VS16 已安装才能成功解析 CMakeLists.txt;如果没有安装 VS16,在调用 cmake.exe 时可以指定其他的工程或生成方式;

  6. 在 libuv 源码目录下新建 build 目录,在 build 目录中打开 powershell 并执行 cmake

    如果选择 MinGW,调用 cmake 的命令是:cmake.exe -G "MinGW Makefiles" ..

    1
    2
    3
    4
    
    # 按照默认生成器
    cmake.exe ..
    # 选择 VS16 生成
    cmake.exe -G "Visual Studio 16 2019" ..
    

  7. 在当前 build 目录中进行生成

    MinGW 使用 mingw32-make.exe 生成,使用方法和 Linux 平台 make 类似;

    1
    2
    3
    4
    
    # 生成 Debug 版本
    cmake.exe --build .
    # 生成 Release 版本
    cmake.exe --build . --config Release
    

    在 build/Debug 或 build/Release 目录下会生成我们的编译目标:

方法二
  1. 安装 VS2019;

  2. 下载 libuv 源码

  3. 使用 VS2019 打开 libuv 目录下的 CMakeLists.txt;

    会在工程目录下多出 .vs 和 out 目录;

    打开工程后,会自动按 x64-Debug 默认配置生成 cmake 缓存,默认路径在 out\build\${cfg_name} 目录,然后 C++ IntelliSense 也会按照 cmake 缓存进行构建;

  4. 在解决方案资源管理器的 CMakeLists.txt 上右键 “CMake 设置”,新增一个 x64-Release 配置并保存;

    会在工程目录下多出 CMakeSettings.json 文件;

  5. 选择 x64-Reelease 配置;

  6. 接着在解决方案资源管理器的 CMakeLists.txt 上右键 “生成”

    最终在 out\build\x64-Release 目录下会生成我们的编译目标:

linux 平台

1
2
3
4
mkdir build
cd build
cmake ..
make

最终会生成 libuv.so、libuv_a.a 等文件;

arm 平台

1
2
3
4
mkdir build
cd build
cmake .. -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=arm -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc
make

最终会生成 libuv.so、libuv_a.a 等文件;

第二步:分平台使用 libuv 库

windows 平台

测试工程文件结构如下:

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include "uv.h"

int main() {
    uv_loop_t* loop = malloc(sizeof(uv_loop_t));
    uv_loop_init(loop);

    printf("Now quitting.\n");
    uv_run(loop, UV_RUN_DEFAULT);

    uv_loop_close(loop);
    free(loop);
    return 0;
}

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 设置 CMake 最低可用版本
cmake_minimum_required(VERSION 3.10)

# 设置工程名称和其他属性
project(vs_demo DESCRIPTION "vs cmake demo 工程")

# 头文件路径
message("include dir: " ${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR})
message("include dir: " ${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/include)

# 生成可执行文件
add_executable(main main.c)

# 添加库,可直接添加库的完整路径
target_link_libraries(main ${PROJECT_SOURCE_DIR}/lib/uv.lib)

# 构建成功后复制依赖的 dll
add_custom_command(TARGET main POST_BUILD 
	COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/lib/uv.dll ${CMAKE_BINARY_DIR}
)

VS2019 打开 cmake 工程,成功生成后即可断点调试:

linux 平台

测试工程文件结构如下:

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include "uv.h"

int main() {
    uv_loop_t* loop = malloc(sizeof(uv_loop_t));
    uv_loop_init(loop);

    printf("Now quitting.\n");
    uv_run(loop, UV_RUN_DEFAULT);

    uv_loop_close(loop);
    free(loop);
    return 0;
}

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 设置 CMake 最低可用版本
cmake_minimum_required(VERSION 3.10)

# 设置工程名称和其他属性
project(demo DESCRIPTION "demo 工程")

# 头文件路径
message("include dir: " ${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR})
message("include dir: " ${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/include)

# 生成可执行文件
add_executable(main main.c)

# 添加库,可直接添加库的完整路径
target_link_libraries(main ${PROJECT_SOURCE_DIR}/lib/libuv.so.1.0.0)

# 构建成功后复制依赖的 dll
add_custom_command(TARGET main POST_BUILD 
	COMMAND cp ${PROJECT_SOURCE_DIR}/lib/libuv.so.1.0.0 ${CMAKE_BINARY_DIR}
)

运行测试程序的结果:

arm 平台

除了需要指定交叉编译器,其他和 linux 平台使用方法相同;

1
2
SET(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

第三步:跨平台使用 libuv+lvgl

工程文件

工程文件结构如下:

SDL2/lib 目录下有 SDL2.lib SDL2main.lib SDL2.dll libSDL2.so 等文件;

uv/lib 目录下有 uv.lib uv.dll libuv.so 等文件;

CMakeLists.txt 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 设置 CMake 最低可用版本
cmake_minimum_required(VERSION 3.10)

# 设置工程名称和其他属性
project(lvgl_test DESCRIPTION "lvgl test 工程")

# 函数:递归添加子目录到全局头文件,root_dir 需要是完整路径
function(include_sub_directories_recursively root_dir)
    # 当前路径是一个目录吗,是的话就加入到包含目录
    if (IS_DIRECTORY ${root_dir})
        message("include dir: " ${root_dir})
        include_directories(${root_dir})
    endif()

    # 获得当前目录下的所有文件,让如ALL_SUB列表中
    file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*)
    foreach(sub ${ALL_SUB})
        if (IS_DIRECTORY ${root_dir}/${sub})
            # 对子目录递归调用,包含
            include_sub_directories_recursively(${root_dir}/${sub})
        endif()
    endforeach()
endfunction()

# 设置变量 C 标准为 99
set(CMAKE_C_STANDARD 99)
# 设置变量 C++ 标准为 11
set(CMAKE_CXX_STANDARD 11)

# 全局包含目录,这里包含程序目录
message("include dir: " ${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR})
message("include dir: " ${PROJECT_SOURCE_DIR}/SDL2/include)
include_directories(${PROJECT_SOURCE_DIR}/SDL2/include)
message("include dir: " ${PROJECT_SOURCE_DIR}/uv/include)
include_directories(${PROJECT_SOURCE_DIR}/uv/include)
include_sub_directories_recursively(${PROJECT_SOURCE_DIR}/lvgl)
include_sub_directories_recursively(${PROJECT_SOURCE_DIR}/lv_drivers)
include_sub_directories_recursively(${PROJECT_SOURCE_DIR}/lv_examples)

# 查找满足规则的文件名放到 SOURCES 变量
file(GLOB_RECURSE LVGL_SOURCES lvgl/src/*.c)
file(GLOB LV_DRV_SOURCES
	lv_drivers/*.c
	lv_drivers/indev/*.c
	lv_drivers/gtkdrv/*.c
	lv_drivers/display/*.c
)
file(GLOB_RECURSE LV_EXP_SOURCES lv_examples/src/*.c)

# 生成可执行文件
add_executable(main main.c ${LVGL_SOURCES} ${LV_DRV_SOURCES} ${LV_EXP_SOURCES})

if (WIN32)
    # 添加库,可直接添加库的完整路径
    target_link_libraries(main
        ${PROJECT_SOURCE_DIR}/SDL2/lib/win/x64/SDL2.lib
        ${PROJECT_SOURCE_DIR}/SDL2/lib/win/x64/SDL2main.lib
        ${PROJECT_SOURCE_DIR}/uv/lib/win/x64/uv.lib
    )

    #构建成功后复制依赖的 dll
    add_custom_command(TARGET main POST_BUILD 
	    COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/SDL2/lib/win/x64/SDL2.dll ${CMAKE_BINARY_DIR}
	    COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/uv/lib/win/x64/uv.dll ${CMAKE_BINARY_DIR}
    )
else ()
    # 添加库,可直接添加库的完整路径
    target_link_libraries(main
        ${PROJECT_SOURCE_DIR}/SDL2/lib/linux/x64/libSDL2.so
        ${PROJECT_SOURCE_DIR}/uv/lib/linux/x64/libuv.so
    )

    #构建成功后复制依赖的 so
    add_custom_command(TARGET main POST_BUILD 
	    COMMAND cp ${PROJECT_SOURCE_DIR}/SDL2/lib/linux/x64/libSDL2.so ${CMAKE_BINARY_DIR}
	    COMMAND cp ${PROJECT_SOURCE_DIR}/uv/lib/linux/x64/libuv.so ${CMAKE_BINARY_DIR}/libuv.so.1
    )
endif ()

main.c 有一点小修改,使用 libuv 替代 Windows API:

1
2
3
4
- #define <Windows.h>
+ #define "uv.h"
- Sleep(10);		/*Just to let the system breathe */
+ uv_sleep(10);		/*Just to let the system breathe */

编译运行结果

Windows 平台编译后运行结果:

Linux 平台编译后运行结果:

系统中有 cmake、make、gcc、g++ 才能编译成功;

依赖 SDL2 才能运行成功:sudo apt-get install libsdl2-2.0-0