zhen's blog

编译思想,编译人生

FLTK基于cmake编译以及使用(Windows、macOS以及Linux)

最近因为一些学习的原因,需要使用一款跨平台的轻量级的GUI+图像绘制 C/C++库。经过一番调研以后,最终从GTK+、FLTK中选出了FLTK,跨平台、够轻量。本文将在Windows、macOS以及Linux Debian三套操作系统环境,对FLTK进行编译,并搭建简单Demo。这其中也有少许的坑,也在此文进行记录。

前期准备

PS:后续操作系统差异带来的配置/代码差异我会特别指明

编译FLTK

编译静态库文件

首先从官方地址下载FLTK 1.3.8代码:Download - Fast Light Toolkit (FLTK)

下载完成后,将文件内容解压至某个自定义目录,例如在macOS下,我存放在"用户主目录/Projects/third-lib-projects/fltk-1.3.8"目录。

进入该目录后,我们创建一个build目录,并进入build目录,然后使用CMake进行配置

上述一些列命令操作整理如下:

1
2
3
4
5
6
7
8
9
10
11
# 进入fltk跟目录
cd "用户主目录/Projects/third-lib-projects/fltk-1.3.8"
# 创建 build 文件夹
mkdir build
# 进入 build 文件夹
cd build
# 执行 cmake 配置操作(注意,cmake后面跟空格,再跟"..",cmake中"外部构建"方式)
# 执行该命令前,请先阅读下面的cmake前置条件
cmake ..

# Windows下建议使用PowerShell,上述的命令基本没有差别。

cmake配置前置条件

Windows

macOS

Linux

在Linux下,使用cmake进行项目生成前,务必确保一些基础库的安装:

1
2
3
4
5
6
7
8
9
10
# 安装gcc/g++等核心开发构建工具和库(必备)
sudo apt-get install build-essential
# openGL库安装(可选,建议。OpenGL的Library、Utilities以及ToolKit)
sudo apt-get install libgl1-mesa-dev
sudo apt-get install libglu1-mesa-dev
sudo apt-get install freeglut3-dev
# openSSL库(可选)
sudo apt-get install libssl-dev
# x11库(必备)
sudo apt-get install libx11-dev

对于必备的X11库,安装完成后是以动态链接库(.so)的方式存放于/usr/lib/x86_64-linux-gnu/libX11.so。在上面的cmake ..命令执行后,你也会看到控制台输出的一些关键内容:

1
2
3
4
# cmake .. 执行后的输出内容
... ...
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so; ... - found
... ...

调用对应平台工具链完成FLTK编译

cmake进行项目构建完成后,在我们当前的build目录中,对于macOS/Linux类操作系统,CMake会为我们生成了对应的makefile文件,所以我们直接使用make命令调用本地的clang或则gcc进行编译。

1
2
# 在build目录下,默认就是release版
make

在Windows操作系统,请直接使用vs打开build中的解决方案FLTK.sln,打开后对项目ALL_BUILD进行Release模式编译。

编译完成后,build目录中会生成一个lib文件夹,这里面存放的就是fltk编译出来的静态链接库。

在macOS/Linux中是lib前缀,.a结尾:

1
2
3
4
# macOS/Linux(Release模式)
build/lib
├── libfltk.a
└── ... ...

在windows中是.lib结尾:

1
2
3
4
5
# Windows(Release模式文件名结尾不会有"d")
build/lib
└── Release
├── fltk.lib
└── ... ...

准备头文件

对于我的方式,在build文件夹中,我们创建一个inlude文件夹,并且将build上一层的fltk根目录中的FL文件夹复制到build/include中,形成如下结构:

1
2
3
4
5
build/include
└── FL
├── Enumerations.H
├── FL.H
└── ... ...

注意,请同时务必将build目录下FL/abi-version.h复制到include/FL/abi-version.h。原因在于FL.h -> Enumerations.h头文件会用到该头文件里面的一些定义,不添加则会报错:

1
2
3
fatal error: 'FL/abi-version.h' file not found
#include <FL/abi-version.h>
^~~~~~~~~~~~~~~~~~

库、头文件准备总结

至此,我们准备好了:

  1. build/lib下的fltk相关静态库(.a/.lib );

  2. 在build/include里面的头文件。

为了方便我们后续的使用,创建一个文件夹fltk-dist-1.3.8,并将lib、include复制到dist中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fltk-dist-1.3.8/
include
└── FL
├── Enumerations.H
├── FL.H
└── ... ...
lib
└── macOS-release
├── libfltk.a
└── ... ...
└── linux-release
├── libfltk.a
└── ... ...
└── Windows-release
├── fltk.lib
└── ... ...

基础项目搭建

创建一个名为fltk-demo目录

  1. 将上一步中的fltk-dist-1.3.8文件夹整体复制到fltk-demo目录中
  2. 项目根目录创建src文件夹,并在其中创建main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>

int main (int argc, char *argv[]) {
Fl_Window *window;
Fl_Box *box;
window = new Fl_Window(300, 180);
window->label("HelloWorld!");
box = new Fl_Box(20, 40, 260, 100, "Hello World!");
box->box(FL_UP_BOX);
box->labelsize(36);
box->labelfont(FL_BOLD + FL_ITALIC);
(FL_SHADOW_LABEL);
window->end();
window->show(argc, argv);
return Fl::run();
}
  1. 创建一个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
CMAKE_MINIMUM_REQUIRED(VERSION 3.23)
PROJECT(fltk_demo)

SET(CMAKE_CXX_STANDARD 11)

# 可执行程序名称,下面统一使用
SET(my_app_name fltk_demo)

# 指定头文件查找目录
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/fltk-dist-1.3.8/include")

# 将src下面的所有头文件路径保存至 all_head_files 数组变量中
# 将src下面的所有源文件路径保存至 all_source_files 数组变量中
FILE(GLOB_RECURSE all_source_files "src/*.cpp" "src/*.c")
FILE(GLOB_RECURSE all_head_files "src/*.hpp" "src*.h")

# 指定库文件查找路径,根据操作系统区分:
IF (CMAKE_SYSTEM_NAME MATCHES "Windows")
# Windows 操作系统,需要查找 Windows-release
MESSAGE(STATUS "current platform: Windows")
LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/fltk-dist-1.3.8/lib/Windows-release")
ADD_EXECUTABLE(
${my_app_name}
WIN32 # Windows 非命令行程序
${all_head_files}
${all_source_files}
)
TARGET_LINK_LIBRARIES(
${my_app_name}
PRIVATE
fltk # 链接的静态库名称,这里只需要写fltk,在运行时自动查找.a/.lib
)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
# macOS 操作系统,查找 macOS-release
MESSAGE(STATUS "current platform: macOS")
LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/fltk-dist-1.3.8/lib/macOS-release")
ADD_EXECUTABLE(
${my_app_name}
${all_head_files}
${all_source_files}
)
TARGET_LINK_LIBRARIES(
${my_app_name}
PRIVATE
fltk # 链接的静态库名称,这里只需要写fltk,在运行时自动查找.a/.lib
# macOS 该选项必填
"-framework Cocoa"
)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Linux")
# Linux 操作系统,查找 Linux-release
MESSAGE(STATUS "current platform: Linux ")

LINK_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/fltk-dist-1.3.8/lib/Linux-release")
ADD_EXECUTABLE(
${my_app_name}
${all_head_files}
${all_source_files}
)
TARGET_LINK_LIBRARIES(
${my_app_name}
PRIVATE
fltk # 链接的静态库名称,这里只需要写fltk,在运行时自动查找.a/.lib
X11 # Linux环境需要指定X11以及dl两个库才能正常显示
dl
)
ELSE ()
# 其他操作系统
MESSAGE(STATUS "other platform: ${CMAKE_SYSTEM_NAME}")
ENDIF ()

对于CMake的配置,我们针对不同的操作系统,我们从dist中指定的操作系统的目录查找静态库文件。此外,还有一些需要注意的:

Windows

Windows操作系统中,请在ADD_EXECUTABLE的应用名称后面添加WIN32,否则部分Windows操作系统窗口显示的时候,还会有一个命令行界面显示出来。

macOS

macOS操作系统中,请在TARGET_LINK_LIBRARIES最后添加参数:"-framework Cocoa",否则fltk链接过程会有如下报错:

1
2
3
4
5
6
7
8
9
[1/1] Linking CXX executable fltk_demo
FAILED: fltk_demo
: &&
... ...
Undefined symbols for architecture x86_64:
... ...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

Linux

对于Linux操作系统,由于桌面窗体程序是基于X11进行的,所以实际运行的过程中是依赖X11库的。所以,我们还需要将X11的动态库也链接到咱们程序。我们的Demo中的CMakeLists.txt针对Linux系统,如果不进行特殊处理,会出现如下类似的错误:

undefined reference to `XGetDefault’等类似问题

1
2
3
4
5
6
7
8
9
10
11
[ 50%] Building CXX object CMakeFiles/fltk_demo.dir/src/main.cpp.o
[100%] Linking CXX executable fltk_demo
/usr/bin/ld: /home/w4ngzhen/Desktop/fltk-demo/fltk-dist-1.3.8/lib/Linux-release/libfltk.a(Fl_get_system_colors.o): in function `getsyscolor(char const*, char const*, char const*, char const*, void (*)(unsigned char, unsigned char, unsigned char))':
Fl_get_system_colors.cxx:(.text._ZL11getsyscolorPKcS0_S0_S0_PFvhhhE+0x24): undefined reference to `XGetDefault'
/usr/bin/ld: Fl_get_system_colors.cxx:(.text._ZL11getsyscolorPKcS0_S0_S0_PFvhhhE+0x47): undefined reference to `XParseColor'
... ...
Fl_Double_Window.cxx:(.text._ZN16Fl_Double_Window4hideEv+0x21): undefined reference to `XFreePixmap'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/fltk_demo.dir/build.make:97: fltk_demo] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/fltk_demo.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

所以,我们需要进行配置,在链接阶段,链接X11动态链接库。

此外,除了X11库以外,我们还需要一个dl库。不配置则会有如下类似错误:

undefined reference to symbol ‘dlsym@@GLIBC_2.2.5’

1
2
3
4
5
6
7
8
[ 50%] Building CXX object CMakeFiles/fltk_demo.dir/src/main.cpp.o
[100%] Linking CXX executable fltk_demo
/usr/bin/ld: /home/w4ngzhen/Desktop/fltk-demo/fltk-dist-1.3.8/lib/Linux-release/libfltk.a(Fl_Window_shape.o): undefined reference to symbol 'dlsym@@GLIBC_2.2.5'
/usr/bin/ld: /lib/x86_64-linux-gnu/libdl.so.2: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/fltk_demo.dir/build.make:97: fltk_demo] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/fltk_demo.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

综合来说,基于Linux环境下的CMakeLists.txt基础配置,和其他平台的差异体现在要增加额外的两个库:

1
2
3
4
5
6
7
    TARGET_LINK_LIBRARIES(
${my_app_name}
PRIVATE
fltk # 链接的静态库名称,这里只需要写fltk,在运行时自动查找.a/.lib
+ X11 # Linux环境需要指定X11以及dl两个库才能正常显示
+ dl
)

效果演示

下图是本人分别在Windows、macOS以及Linux环境下的运行效果:

010-fltk-demo-in-all

附录

本文项目代码已经提交至Github

w4ngzhen/fltk-demo (github.com)