GLFW 3.5 应用构建指南:头文件引入、选项宏与全平台链接配置详解
【免费下载链接】glfwA multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input项目地址: https://gitcode.com/GitHub_Trending/gl/glfw
本篇指南聚焦于使用 GLFW 3.5 编写 OpenGL、OpenGL ES 与 Vulkan 应用时的编译与链接环节:如何正确引入GLFW/glfw3.h头文件、如何通过选项宏切换 API 头文件、以及如何在 Visual C++、MinGW-w64、CMake、pkg-config 和 Xcode 等不同开发环境中完成静态库或 DLL 的链接。读完本文,你将掌握一套可在 Windows、macOS 与 Linux 等平台上直接复用的构建配置方案。关于如何编译 GLFW 库本身,请参阅 docs/compile.md;关于如何编写 GLFW 应用,请从 docs/quick.md 的入门教程开始。
本文假定读者已具备基本的 C 程序编译与链接知识,能够使用所选开发环境的编译器。它并非编译或链接的通用教程。
引入 GLFW 头文件
在使用了 OpenGL 或 GLFW 的源文件中,应包含 GLFW 头文件:
#include <GLFW/glfw3.h>该头文件定义了 GLFW API 的全部常量、类型和函数原型。默认情况下,它还会引入开发环境自带的 OpenGL 头文件(GL/gl.h,macOS 上为OpenGL/gl.h),具体行为见下文 GLFW 头文件选项宏。
GLFW 头文件还会按需定义 OpenGL 头文件所需的平台相关宏(如 Windows 下的APIENTRY、WINGDIAPI、CALLBACK),从而让 OpenGL 头文件可以在不依赖任何窗口系统头文件的情况下被引入。在 include/GLFW/glfw3.h 中可以找到这些宏的定义逻辑,例如:
#if !defined(APIENTRY) #if defined(_WIN32) #define APIENTRY __stdcall #else #define APIENTRY #endif #define GLFW_APIENTRY_DEFINED #endif /* APIENTRY */只有当需要时 GLFW 才会定义这些符号;如果窗口系统头文件已被提前引入,GLFW 不会重复定义这些符号。但反过来不成立——例如windows.h无法容忍 Win32 符号被提前定义。因此请遵循以下三条规则:
- 使用 GLFW 头文件来可移植地引入 OpenGL 或 OpenGL ES 头文件;
- 除非要直接使用窗口系统 API,否则不要引入窗口系统头文件;
- 如果确实需要这些头文件,请在 GLFW 头文件之前引入它们。
与扩展加载库(glad 等)搭配使用
如果使用 glad 这类 OpenGL 扩展加载库,扩展加载器的头文件应放在 GLFW 头文件之前引入:
#include <glad/gl.h> #include <GLFW/glfw3.h>GLFW 会尝试检测是否已引入过任何 OpenGL、OpenGL ES 或扩展加载器头文件(通过识别它们各自的 include guard 宏),一旦检测到就会禁用默认 OpenGL 头文件的引入。大多数扩展加载库还会自行定义宏来禁用其下方的同类头文件。
上述两种机制都依赖扩展加载器头文件定义了某个已知宏。如果你的扩展加载库没有这样做,或者你无法确定用户会选用哪个,GLFW_INCLUDE_NONE宏可以显式阻止 GLFW 头文件引入 OpenGL 头文件,同时允许你以任意顺序引入两个头文件:
#define GLFW_INCLUDE_NONE #include <GLFW/glfw3.h> #include <glad/gl.h>GLFW 头文件选项宏
以下宏必须在包含 GLFW 头文件之前定义,用于影响其行为。
GLFW_DLL:在 Windows 上使用 GLFW DLL 版本时必须定义,用于告知编译器 GLFW 函数定义在 DLL 中。
下列宏用于控制引入哪个 OpenGL 或 OpenGL ES API 头文件,同一时间只能定义其中一个:
| 宏 | 引入的头文件 | 说明 |
|---|---|---|
| (无) | GL/gl.h(macOS 为OpenGL/gl.h) | 默认的标准 OpenGL 头文件;除非 GLFW 检测到已引入过任何已知的 OpenGL、OpenGL ES 或扩展加载器头文件 |
GLFW_INCLUDE_GLCOREARB | GL/glcorearb.h(macOS 为OpenGL/gl3.h) | 现代核心 OpenGL 头文件 |
GLFW_INCLUDE_ES1 | GLES/gl.h | OpenGL ES 1.x |
GLFW_INCLUDE_ES2 | GLES2/gl2.h | OpenGL ES 2.0 |
GLFW_INCLUDE_ES3 | GLES3/gl3.h | OpenGL ES 3.0 |
GLFW_INCLUDE_ES31 | GLES3/gl31.h | OpenGL ES 3.1 |
GLFW_INCLUDE_ES32 | GLES3/gl32.h | OpenGL ES 3.2 |
GLFW_INCLUDE_NONE | 不引入任何 API 头文件 | 与扩展加载库搭配使用 |
注意:GLFW不提供上述任何 API 头文件,它们来自你的开发环境或 OpenGL、OpenGL ES、Vulkan SDK。
以下宏控制额外API 头文件的引入,可与上述任一宏同时定义多个:
GLFW_INCLUDE_VULKAN:在已选定的 OpenGL/OpenGL ES 头文件之外,额外引入vulkan/vulkan.h。在 include/GLFW/glfw3.h 中可以看到它位于整个条件选择链的最前面:#if defined(GLFW_INCLUDE_VULKAN) #include <vulkan/vulkan.h> #endif /* Vulkan header */GLFW_INCLUDE_GLEXT:在已选定的 OpenGL/OpenGL ES 头文件之后,额外引入对应的扩展头文件(例如GLES2/gl2ext.h、GL/glext.h、macOS 上的OpenGL/gl3ext.h)。GLFW_INCLUDE_GLU:额外引入 GLU 头文件。只应配合标准 OpenGL 头文件使用,且仅用于兼容遗留代码;GLU 已被弃用,新代码不应使用。
上述宏的完整组合逻辑可以对照 include/GLFW/glfw3.h 阅读:从GLFW_INCLUDE_ES1开始逐级#elif判断,默认分支还会检查GLFW_INCLUDE_NONE以及一系列 include guard 宏(__gl_h_、__gles2_gl2_h_、__gl_glcorearb_h_等),以决定是否引入默认 OpenGL 头文件。
重要提醒:以上任何宏都不得在编译 GLFW 库本身时被定义。如果你的构建同时包含 GLFW 源码,务必确保这些宏不会作用于 GLFW 的源文件。
链接正确的库
GLFW 本质上是各种平台特定 API 的封装层,因此需要链接大量不同的系统库。使用共享库/动态库/DLL版本时,这些链接由 GLFW 库自身完成;使用静态库版本时,你的可执行文件需要自行链接这些库。
在 Windows 和 macOS 上,系统库列表是固定的,可以直接写死在构建环境中(见下文各开发环境小节)。在 Linux 及其他 Unix 类系统上,该列表因发行版而异,但可以通过下文介绍的多种方式自动获取。
使用 Visual C++ 与 GLFW 二进制
如果使用下载的二进制压缩包,请先确认压缩包与你要构建的架构(32 位或 64 位)匹配,否则会出现链接错误;同时确保二进制与你所用 Visual C++ 版本对应。
二进制压缩包中包含两个静态库版本,因为它们必须与可执行文件其余部分的运行库(base run-time library)变体一致:
glfw3.lib:用于项目选项Runtime Library为Multi-threaded DLL或Multi-threaded Debug DLL时;glfw3_mt.lib:用于项目选项Runtime Library为Multi-threaded或Multi-threaded Debug时。
将path/to/glfw3.lib或path/to/glfw3_mt.lib添加到项目的Additional Dependencies选项。如果静态库是你自己编译的,则只有一个glfw3.lib,你需要自行保证运行库变体一致。
DLL 版本名为glfw3.dll,但链接时使用glfw3dll.lib导入库,将其添加到Additional Dependencies。DLL 版本的所有依赖默认已列在其中,但使用 DLL 版本时还必须定义GLFW_DLL,可以在Preprocessor Definitions中设置,或在源码中包含 GLFW 头文件之前定义:
#define GLFW_DLL #include <GLFW/glfw3.h>使用 MinGW-w64 与 GLFW 二进制
适用于在 Windows 上使用 MinGW-w64 从命令行或 makefile 构建程序。以下路径假定使用二进制压缩包(下载的或自己编译的)。
注意 GCC 中源文件和库的排列顺序:依赖项必须列在使用它的文件之后。依赖 GLFW 的源文件必须排在 GLFW 库之前,而 GLFW 又依赖gdi32,因此gdi32必须排在 GLFW 库之后。
使用静态库libglfw3.a:
gcc -o myprog myprog.c -I path/to/glfw/include path/to/glfw/lib-mingw-w64/libglfw3.a -lgdi32使用 DLL 版本glfw3.dll,需要链接导入库libglfw3dll.a:
gcc -o myprog myprog.c -I path/to/glfw/include path/to/glfw/lib-mingw-w64/libglfw3dll.a -lgdi32生成的程序运行时需要能找到glfw3.dll,通常将两者放在同一目录即可。使用 DLL 版本时还需定义GLFW_DLL宏,可在源码中定义(必须在包含头文件之前):
#define GLFW_DLL #include <GLFW/glfw3.h>也可以在命令行定义:
gcc -o myprog myprog.c -D GLFW_DLL -I path/to/glfw/include path/to/glfw/lib-mingw-w64/libglfw3dll.a -lgdi32使用 CMake 与 GLFW 源码一起构建
在CMakeLists.txt中做少量修改,即可让 GLFW 源码树随你的应用一起构建。首先把 GLFW 源码树根目录加入项目,这会向项目添加glfw目标:
add_subdirectory(path/to/glfw)然后让你的应用链接glfw目标。它会按当前配置附加 GLFW 库及其链接期依赖、GLFW 头文件的 include 目录,并在适用时附加GLFW_DLL宏:
target_link_libraries(myapp glfw)注意glfw目标不依赖 OpenGL,因为 GLFW 在运行时才动态加载所需的 OpenGL、OpenGL ES 或 Vulkan 库。如果你的应用直接调用 OpenGL(而非使用现代的扩展加载库,参见 docs/context.md),请使用 OpenGL CMake 包:
find_package(OpenGL REQUIRED)找到后项目会获得OpenGL::GL目标(包含库路径与 include 路径),像链接其他库一样链接它:
target_link_libraries(myapp OpenGL::GL)从 src/CMakeLists.txt 可以看出,glfw目标的源文件包含平台无关的context.c、init.c、input.c、monitor.c、platform.c、vulkan.c、window.c以及各后端源文件;而 CMakeLists.txt 中的GLFW_BUILD_WIN32、GLFW_BUILD_COCOA、GLFW_BUILD_X11、GLFW_BUILD_WAYLAND选项决定了具体编译哪个平台后端。
使用 CMake 与已安装的 GLFW 二进制
如果你已经构建并安装了 GLFW,则可以用find_package定位安装时生成的包与目标文件(对应模板 CMake/glfw3Config.cmake.in 和 CMake/glfw3Config.cmake.in 生成的glfw3Config.cmake):
find_package(glfw3 3.5 REQUIRED)找到后链接glfw目标即可,它会附加 GLFW 库及其链接期依赖、头文件 include 目录,并在适用时附加GLFW_DLL宏:
target_link_libraries(myapp glfw)与源码构建方式相同,glfw目标不依赖 OpenGL;直接调用 OpenGL 的应用请额外使用 OpenGL CMake 包:
find_package(OpenGL REQUIRED) target_link_libraries(myapp OpenGL::GL)在 Unix 上使用 pkg-config 与 GLFW 二进制
适用于 macOS 或任何 Unix 类系统(Linux、FreeBSD、Cygwin)下从命令行或 makefile 构建。
GLFW 支持 pkg-config,其中Requires.private、Libs.private等内容由 src/CMakeLists.txt 在配置阶段生成。
使用静态库版本的典型编译链接命令:
cc $(pkg-config --cflags glfw3) -o myprog myprog.c $(pkg-config --static --libs glfw3)使用共享库版本时省略--static标志:
cc $(pkg-config --cflags glfw3) -o myprog myprog.c $(pkg-config --libs glfw3)也可以在不安装的情况下直接使用glfw3.pc,通过PKG_CONFIG_PATH环境变量指定其位置(构建目录位于源码树中的src子目录下):
env PKG_CONFIG_PATH=path/to/glfw/src cc $(pkg-config --cflags glfw3) -o myprog myprog.c $(pkg-config --libs glfw3)依赖中不包含 OpenGL,因为 GLFW 在运行时才加载所需的 OpenGL、OpenGL ES 或 Vulkan 库。如果应用直接调用 OpenGL(而非使用扩展加载库,参见 docs/context.md),请额外添加glpkg-config 包:
cc $(pkg-config --cflags glfw3 gl) -o myprog myprog.c $(pkg-config --libs glfw3 gl)在 macOS 上使用 Xcode
- 使用动态库版本:将其添加到项目依赖中。
- 使用静态库版本:将静态库以及Cocoa、OpenGL、IOKit、QuartzCore四个 framework 作为依赖添加到项目。它们都可以在
/System/Library/Frameworks中找到。
这些 framework 与 src/CMakeLists.txt 中glfw目标在 macOS 上的链接参数(-framework Cocoa -framework IOKit -framework CoreFoundation -framework QuartzCore)保持一致。
在 macOS 上使用命令行或 makefile
在 macOS 命令行使用已安装的 GLFW 二进制时,推荐使用 pkg-config 方式,这样新增的依赖会自动包含。若仍要手动构建,需要使用-l和-framework开关自行添加所需的 framework 和库。
使用动态库libglfw.3.dylib:
cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework QuartzCore使用静态库libglfw3.a时,把-lglfw替换为-lglfw3。命令行链接 framework 时不需要添加.framework扩展名。
注意:你的机器上可能还有
libGL.*.dylib风格的 OpenGL 库,但那是为 X Window System 准备的,不适用于macOS 原生版本的 GLFW。
深入理解:GLFW 的链接依赖从何而来
从源码结构看,GLFW 在 src/CMakeLists.txt 中按平台累积链接依赖:
- Windows (Win32):
-lgdi32(src/CMakeLists.txt),并在构建 DLL 时通过target_compile_definitions(glfw INTERFACE GLFW_DLL)(src/CMakeLists.txt)把GLFW_DLL自动传给使用者,这解释了为何通过 CMake 使用 DLL 版本时无需手动定义该宏; - macOS (Cocoa):Cocoa、IOKit、CoreFoundation、QuartzCore 四个 framework(src/CMakeLists.txt);
- Unix 类系统:
rt(实时库)、m(数学库)和dl(动态加载库)按需链接(src/CMakeLists.txt); - Wayland:依赖
wayland-client、wayland-cursor、wayland-egl、xkbcommon(src/CMakeLists.txt); - X11:依赖 XRandR、Xinerama、Xkb、Xcursor、XInput、X Shape 等扩展(src/CMakeLists.txt)。
这些依赖会同时进入 pkg-config 的Libs.private(静态链接时需要)和 CMake 的链接接口,这正是前文各种链接方式中"GLFW 库自带链接期依赖"这一说法的实现基础。
与编译 GLFW 库本身的衔接
本文覆盖的是使用GLFW 时的构建配置。若需要把 GLFW 库本身编译出来,请阅读 docs/compile.md。二者衔接的关键点包括:
- 通过 docs/compile.md 中的
cmake -S . -B build生成构建文件,并用cmake --build build或make完成编译; - 根 CMakeLists.txt 中的
BUILD_SHARED_LIBS决定构建静态库还是共享库(默认 OFF,即静态库),GLFW_INSTALL(默认 ON)决定是否生成安装目标; - 安装后,CMake 包文件(
glfw3Config.cmake)会安装在${CMAKE_INSTALL_LIBDIR}/cmake/glfw3,glfw3.pc会安装在${CMAKE_INSTALL_LIBDIR}/pkgconfig(CMakeLists.txt),分别供前文的find_package(glfw3 3.5 REQUIRED)和pkg-config glfw3使用。
把握了"库本身怎么编译"与"应用怎么链接"这两条主线,无论你的目标平台是 Windows、macOS、Linux 还是 Wayland/X11 环境,都能快速搭建出可运行、可维护的 GLFW 应用构建系统。
【免费下载链接】glfwA multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input项目地址: https://gitcode.com/GitHub_Trending/gl/glfw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考