c++ - 使用 CMake 在 MacOS 应用程序中链接 GLFW 的正确方法是什么?
问题描述
我是 CMake 新手,无法让我的简单 MacOS 应用程序(此时只是学习 OpenGL 教程)链接到 GLFW 所需的 MacOS 框架。我所有的代码都在main.cpp
里面,我正在使用生成的高兴源文件。我的源代码树如下所示:
.
├── CMakeLists.txt
├── glad
│ └── glad.h
├── glad.c
├── KHR
│ └── khrplatform.h
└── main.cpp
这是我的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(simple_repro)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
add_executable(app1 main.cpp glad.c)
target_include_directories(app1 PRIVATE
${CMAKE_SOURCE_DIR}
${GLFW_INCLUDE_DIRS}
)
target_link_libraries(app1 ${GLFW_STATIC_LDFLAGS})
当我构建时,我得到这个错误:
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 -L/usr/local/lib -lglfw3 -framework -lCocoa -framework -lIOKit -framework -lCoreFoundation -lCocoa -lIOKit -lCoreFoundation
ld: framework not found -lCocoa
clang: error: linker command failed with exit code 1 (use -v to see invocation)
从表面上看,原因很明显:在链接器命令中,框架部分${GLFW_STATIC_LDFLAGS}
被破坏了。框架的名称是前置的-l
,它们是重复的。供参考,pkg_search_module
调用后,GLFW_STATIC_LDFLAGS
是:
-L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation
请注意,我无法控制它的格式;它由pkg_search_module
.
我认为如果框架部分扩展为:
-framework Cocoa -framework IOKit -framework CoreFoundation
我会做生意的。但相反,它的出现是
-framework -lCocoa -framework -lIOKit -framework -lCoreFoundation -lCocoa -lIOKit -lCoreFoundation
所以我的问题的核心是:我需要做什么才能从 的输出中生成正确的链接器命令pkg_search_module
?我用谷歌搜索了我能想到的所有东西,并尝试了很多东西,但无济于事。我探索的一些亮点:
- 根据这个答案,我更改了
pkg_search_module
调用以指定 IMPORTED_TARGET,然后链接到该目标:
pkg_search_module(GLFW REQUIRED IMPORTED_TARGET glfw3)
...
target_link_libraries(app1 PUBLIC PkgConfig::GLFW)
这导致在链接器命令中基本上没有对 MacOS 框架的引用以及(正如我所料)一堆核心平台未定义的符号:
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 /usr/local/lib/libglfw3.a
Undefined symbols for architecture x86_64:
"_CFArrayAppendValue", referenced from:
__glfwInitJoysticksNS in libglfw3.a(cocoa_joystick.m.o)
_matchCallback in libglfw3.a(cocoa_joystick.m.o)
"_CFArrayCreateMutable", referenced from:
... and many pages more
- 我尝试通过显式设置链接标志
set_property(TARGET app1 PROPERTY LINK_FLAGS ${GLFW_STATIC_LDFLAGS})
这只是将整个分号分隔的列表解释GLFW_STATIC_LDFLAGS
为单个字符串并给出链接器警告:
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names -L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 /usr/local/lib/libglfw3.a
ld: warning: directory not found for option '-L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation'
- 我知道我可以通过
find_library()
对 Cocoa、IOKit 和 CoreFoundation 进行显式调用然后链接到找到的库来完成这项工作,但我不想将 GLFW 需要这些框架的知识硬编码到我的 CMakeLists.txt 中,因为这是特定于平台的.
非常感谢您在确定什么咒语将从pkg_search_module
输出中生成正确的链接器命令的任何帮助。
编辑:为了回应 Tsyvarev 下面的评论,我将 CMakeLists.txt 更改为:
cmake_minimum_required(VERSION 3.5)
project(simple_repro)
set(CMAKE_CXX_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLFW REQUIRED glfw3)
add_executable(app1 main.cpp glad.c)
target_include_directories(app1 PRIVATE
${CMAKE_SOURCE_DIR}
${GLFW_INCLUDE_DIRS}
)
target_link_libraries(app1 ${GLFW_LIBRARIES})
message(STATUS "GLFW_LIBRARIES is ${GLFW_LIBRARIES}")
target_compile_options(app1 PUBLIC ${GLFW_CFLAGS_OTHER})
这会输出-- GLFW_LIBRARIES is glfw3
并生成此链接器命令,该命令不包含 glfw3 的完整路径,也不包含所需的系统框架:
/usr/local/Cellar/cmake/3.21.2/bin/cmake -E cmake_link_script CMakeFiles/app1.dir/link.txt --verbose=1
/Library/Developer/CommandLineTools/usr/bin/c++ -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/app1.dir/main.cpp.o CMakeFiles/app1.dir/glad.c.o -o app1 -lglfw3
这是pkg_search_module
调用后的 GLFW_* 变量的完整列表,以防万一:
-- GLFW_CFLAGS=-I/usr/local/include
-- GLFW_CFLAGS_I=
-- GLFW_CFLAGS_OTHER=
-- GLFW_FOUND=1
-- GLFW_INCLUDEDIR=/usr/local/include
-- GLFW_INCLUDE_DIRS=/usr/local/include
-- GLFW_LDFLAGS=-L/usr/local/lib;-lglfw3
-- GLFW_LDFLAGS_OTHER=
-- GLFW_LIBDIR=/usr/local/lib
-- GLFW_LIBRARIES=glfw3
-- GLFW_LIBRARY_DIRS=/usr/local/lib
-- GLFW_LIBS=
-- GLFW_LIBS_L=
-- GLFW_LIBS_OTHER=
-- GLFW_LIBS_PATHS=
-- GLFW_LINK_LIBRARIES=/usr/local/lib/libglfw3.a
-- GLFW_MODULE_NAME=glfw3
-- GLFW_PREFIX=/usr/local
-- GLFW_STATIC_CFLAGS=-I/usr/local/include
-- GLFW_STATIC_CFLAGS_I=
-- GLFW_STATIC_CFLAGS_OTHER=
-- GLFW_STATIC_INCLUDE_DIRS=/usr/local/include
-- GLFW_STATIC_LDFLAGS=-L/usr/local/lib;-lglfw3;-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation
-- GLFW_STATIC_LDFLAGS_OTHER=-framework;Cocoa;-framework;IOKit;-framework;CoreFoundation
-- GLFW_STATIC_LIBDIR=
-- GLFW_STATIC_LIBRARIES=glfw3
-- GLFW_STATIC_LIBRARY_DIRS=/usr/local/lib
-- GLFW_STATIC_LIBS=
-- GLFW_STATIC_LIBS_L=
-- GLFW_STATIC_LIBS_OTHER=
-- GLFW_STATIC_LIBS_PATHS=
-- GLFW_VERSION=3.3.4
-- GLFW_glfw3_INCLUDEDIR=
-- GLFW_glfw3_LIBDIR=
-- GLFW_glfw3_PREFIX=
-- GLFW_glfw3_VERSION=
-- __pkg_config_arguments_GLFW=REQUIRED;glfw3
-- __pkg_config_checked_GLFW=1
-- pkgcfg_lib_GLFW_glfw3=/usr/local/lib/libglfw3.a
解决方案
最后,我放弃了 pkg-config 并最终让它与 find_package 一起工作。这是我最终得到的 CMakeLists.txt,基于GLFW 指南。
cmake_minimum_required(VERSION 3.5)
project(simple_repro)
set(CMAKE_CXX_STANDARD 17)
find_package(glfw3 3.3 REQUIRED)
add_executable(app1 main.cpp glad.c)
target_include_directories(app1 PRIVATE
${CMAKE_SOURCE_DIR}
)
target_link_libraries(app1 glfw)
find_package(OpenGL REQUIRED)
target_link_libraries(app1 OpenGL::GL)
推荐阅读
- html - 选择输入类型不起作用。怀疑初始化,但我已多次检查代码
- javascript - 为什么每次更改地址栏中的 URL 时都会重建我的当前客户端服务?
- node.js - 在@media 中的@import 中不能使用Stylus Path 别名
- reactjs - 在 reactjs 中将 { 和 } 显示为函数
- google-sheets - 允许访问单元格公式中的外部工作表的权限
- javascript - 如何检查结束时间和开始时间是否与javascript相等
- php - PHP - 将嵌套数组打印为无序列表
- flutter - Flutter / Dart 全局变量列表用最近添加的列表覆盖所有列表项
- opencv - 是否有任何算法可以让我识别照片是否是从显示器上显示的图像中拍摄的?
- arrays - 组合 0 到 (k-1) 的连通路径来构建 k 的路径