使用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'
  • 我知道我可以通过在Cocoa, IOKit和CoreFoundation上做显式find_library()调用来完成这项工作,然后链接到找到的库,但我不想硬编码到我的CMakeLists.txt中GLFW需要这些框架的知识,因为这是平台特定的。

提前感谢您帮助我弄清楚什么咒语可以从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

框架现在存在于动态缓存中,由库路径上的dlopen()检测到。你让它工作,所以我建议一个有条件的if(APPLE)节来处理苹果框架。

在macOS Big Sur 11.0.1中新增,系统附带一个内置的动态所有系统提供的库的链接器缓存。作为这种变化的一部分,文件系统中不再存在动态库的副本。试图检查是否存在动态库的代码对于位于路径处的文件或枚举目录将失败。相反,通过尝试dlopen()路径来检查库是否存在将正确检查缓存中的库。(62986286)

https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-release-notes

最后,我放弃了pkg-config,并最终让它与find_package一起工作。这是基于GLFW指南,我最终得到的CMakeLists.txt。

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)

相关内容

最新更新