我已经开始使用C ++玩一点游戏,为了实现这一目标,我决定编写一个简单的游戏引擎。
为此,我使用CLion作为我的IDE,它运行良好,但是添加库只是一场噩梦。首先,我使用brew安装了glew,glfw或glm等所有必需的库,一切正常。然后,我花了将近2个小时来将其用于我的项目。
我最大的奥秘是它起作用的原因,我使用过Java,Python或golang的构建系统,而一切对我来说总是很清楚。但是,我不知道为什么它会以它的方式工作,我很想知道!
这是我的CMakeLists文件。
cmake_minimum_required(VERSION 3.10)
project(untitled2)
find_package(GLEW REQUIRED)
find_package(GLFW3 REQUIRED)
set(CMAKE_CXX_STANDARD 17)
add_executable(untitled2 main.cpp)
target_link_libraries(untitled2 ${GLEW_LIBRARIES})
target_link_libraries(untitled2 glfw)
现在我有几个问题: 1.为什么不用CMakeLists就能使用GLM库? 2.为什么我需要包括glfw和glew但不包括glm? 3.为什么我需要使用$ {GLEW_LIBRARIES}而不使用glew这样的名称? (我尝试使用其他名称,但没有用。)
顺便说一句。我正在使用macOS。
答案 0 :(得分:0)
首先要记住的是,C ++还没有像更新语言一样具有真正的模块系统。它仅具有用于搜索头文件的目录列表,用于搜索库的目录列表以及用于链接时搜索符号的库的列表。 target_link_libraries
指令仅添加了添加到这三个列表的编译器标志。
现在,转到此特定方案。大多数魔术都发生在find_package
指令中。该指令实际上最终只是运行cmake脚本。有时将它们与cmake打包在一起,有时将它们与找到的软件包一起安装。最后,这些脚本基本上可以执行任何所需的操作。它们都有相同的目的,为您提供一种添加适当的编译器标志以使用该程序包的方法,但是它们有两种常见的实现方法。
较旧的方法是设置变量,您可以使用这些变量来告诉编译器要在哪个目录中搜索标头和库以及要链接到的库。这就是GLEW似乎采取的方法。它设置变量GLEW_LIBRARIES
和GLEW_INCLUDE_DIRS
,然后您必须使用link_libraries
和include_directories
来告诉编译器要做什么。这是旧版本的cmake(2.8版之前的IIRC)中唯一可用的方法,因此虽然使用起来不太好,但仍然可以使用多少个库的find_package
脚本。
更新的方法是创建导入的目标。这些目标设置了适当的属性,以便链接到导入目标的任何目标都继承适当的包含目录和库标志。这就是GLFW采取的方法。它创建一个名为glfw
的导入目标,该目标具有INTERFACE_INCLUDE_DIRECTORIES
和INTERFACE_LINK_LIBRARIES
属性集。当您将其传递给target_link_libraries
时,您的untitled2
目标将继承那些包含目录和库。
最后,GLM是仅标头的库。没有可链接的库文件,因此只要将适当的目录添加到编译器头搜索路径中,您就可以包括和使用GLM。
由于您使用自制软件安装库,因此它们的所有标头都可能位于同一基本目录下;最有可能是“ / usr / local / include”。同样,它们的所有库文件都可能位于同一目录下。可能是“ / usr / local / lib”。这意味着只要告诉编译器在“ / usr / local / include”中搜索标头,并在“ / usr / local / lib”中搜索库,便可以找到其任何标头和库。
因此,最后要回答这个问题:之所以起作用,是因为glfw
目标告诉cmake它应该设置编译器标志,以将“ / usr / local / include”添加到其包含目录列表中。由于该目录与搜索GLM和GLEW所需的目录相同,因此编译器能够找到所有库的标头。编译器还能够找到需要链接的库文件,因为cmake告诉编译器通过列表GLEW_LIBRARIES
和从glfw
目标继承的属性来显式查找它们。 GLM没有任何要链接的库文件,因此没有任何可讲述的内容。
尽管如此,您实际上不应该依赖所有内容。您应该能够将这样的所有事情告诉编译器(请注意,我还没有实际测试过):
cmake_minimum_required(VERSION 3.10)
project(untitled2)
set(CMAKE_CXX_STANDARD 17)
add_executable(untitled2 main.cpp)
# This will fill the variables GLEW_INCLUDE_DIRES and GLEW_LIBRARIES
# that you can use to add the appropriate compiler flags
find_package(GLEW REQUIRED)
# This will create an imported target named glfw that you can link to
# to inherit the appropriate include directories and libraries
find_package(GLFW3 REQUIRED)
# This also creates an imported target named glm that you can "link to"
# to inherit the appropriate include directories
find_package(glm REQUIRED)
# GLEW uses an old-style find_package script, so you have to
# explicitly tell cmake about GLEW's include directories
target_include_directories(untitled2 PUBLIC ${GLEW_INCLUDE_DIRS})
# And the library files to link to
target_link_libraries(untitled ${GLEW_LIBRARIES})
# cmake will automatically add the appropriate include directories
# and library files that the imported glfw target tells it about
target_link_libraries(untitled2 glfw)
# You use the target_link_libraries directive with the glm imported target
# even though you're not actually linking to any libraries. It's just how
# you tell cmake you want your untitled2 target to inherit the appropriate
# include directories from the imported glm target
target_link_libraries(untitled2 glm)