CMakeLists C++ Beginner

CMakeLists C++ Beginner

本文关键字:Beginner C++ CMakeLists      更新时间:2023-10-16

我已经开始玩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. 为什么我可以使用 GLM 库而不将其包含在 CMakeList 中? 2. 为什么我需要包括glfw和glew,而不是glm? 3. 为什么我需要使用 ${GLEW_LIBRARIES} 而不是像 glew 这样的名称?(我尝试了不同的名字,但没有任何效果。

顺便说一句。我使用的是 macOS。

首先要记住的是,C++还没有像新语言那样真正的模块系统。 它只有一个搜索头文件的目录列表,一个搜索库的目录列表,以及一个在链接时搜索符号的库列表。target_link_libraries指令只是添加添加到这三个列表的编译器标志。

现在,进入这个特定场景。 大多数魔术都发生在find_package指令中。 该指令实际上最终只是运行 cmake 脚本。 有时它们与 cmake 一起打包,有时它们与您找到的软件包一起安装。 最后,这些脚本基本上可以做任何他们想做的事情。 它们都有相同的目标,为您提供一种添加适当的编译器标志以使用该包的方法,但是它们有几种常见的方法。

较旧的方法是设置变量,您可以使用这些变量告诉编译器要搜索标头和库的目录以及要链接到哪些库。 这就是GLEW似乎采取的方法。 它将变量设置为GLEW_LIBRARIESGLEW_INCLUDE_DIRS,然后您必须使用link_librariesinclude_directories来告诉编译器要做什么。 这是旧版本的 cmake(2.8 IIRC 之前(中唯一可用的方法,所以虽然它不好用,但它仍然是有多少库的find_package脚本工作。

较新的方法是创建导入的目标。 这些目标设置了适当的属性,以便链接到导入的目标的任何目标都继承相应的包含目录和库标志。 这就是GLFW采取的方法。 它创建一个名为glfw的导入目标,该目标设置了INTERFACE_INCLUDE_DIRECTORIESINTERFACE_LINK_LIBRARIES属性。 当您将其传递给target_link_libraries时,您的untitled2目标将继承这些包含目录和库。

最后,GLM 是一个仅标头库。 没有要链接到的库文件,因此只要将适当的目录添加到编译器标头搜索路径中,您就可以包含和使用 GLM。


由于您使用 homebrew 来安装库,因此它们的所有标头都可能位于同一个基本目录下;很可能是"/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(untitled2 ${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)