具有多个目录的大型项目的 CMakeLists?
Posted
技术标签:
【中文标题】具有多个目录的大型项目的 CMakeLists?【英文标题】:CMakeLists for large project with multiple directories? 【发布时间】:2018-10-24 12:34:04 【问题描述】:我正在编写一个运行良好的游戏引擎。但是我遇到了一个问题,我的 CMakeLists.txt 太乱了,而且我对 CMake 了解不够。我的项目使用多个(CMake)库,这些库是使用 add_subdirectory 然后 target_link_libraries 添加的。我的项目由引擎(可执行文件)、编辑器(库)和一些测试/示例组成。这是我的文件结构:
C:.
| CMakeLists.txt
| tree.txt
|
+---Editor
| | README.md
| |
| \---src
| main.cpp
|
+---Engine
| | README.md
| |
| +---src
| | | main.cpp
| | |
| | +---API
| | | Core.h
| | |
| | +---App
| | | Application.cpp
| | |
| | +---ExtApp
| | | | AppInterface.cpp
| | | |
| | | +---Engine
| | | | ExtAppLoader.cpp
| | | |
| | | \---Game
| | | InfoExport.cpp
| | |
| | +---Framework
| | | Asset.cpp
| | |
| | +---Managing
| | | AssetLoader.cpp
| | |
| | +---Rendering
| | | | Renderer.cpp
| | | |
| | | \---Renderables
| | | Canvas2DRenderable.cpp
| | |
| | \---Types
| | Vector3f.cpp
| |
| \---TestResources
| \---Shaders
| Canvas2DTexturedTriangle.f
| Canvas2DTexturedTriangle.v
| Canvas2DUntexturedTriangle.f
| Canvas2DUntexturedTriangle.v
| ImTest.f
| ImTest.v
|
+---Libraries
| +---glfw
| | CMakeLists.txt
| |
| \---glm
| CMakeLists.txt
|
\---Tests
\---TestGame
\---src
main.cpp
如您所见,我一开始有一个 CMakeLists,它会加载所有项目。然后我有图书馆,其中也有一个 CMakeLists。每个目录只有一个文件来使树变小,但一个目录中有多个文件。另外,这是我当前的、凌乱的、几乎没用的 CMakeLists 文件:
cmake_minimum_required(VERSION 3.6)
#project(3DEngine)
add_subdirectory(Libraries/glfw) #Add glfw to the project
# Make sure we're running C++17 so all features(like std::filesystem) are present.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
option(BUILD_ENGINE_FOR_EDITOR "Build the engine as DLL/SO for the editor and add editor specific things. Otherwise build engine as game exec" OFF)
option(BUILD_ENGINE_FOR_DLL_APPS "Have the Engine load the game(and plugins) from dll's." ON)
project (Engine)#project engine
include_directories(Libraries/whereami/src)
include_directories(Engine/src/)
include_directories(Libraries/glfw/include)
include_directories(Libraries/glm)
include_directories(Libraries/glad/include)
include_directories(Libraries/stb)
file(GLOB EngineRootSOURCES "Engine/src/*.cpp" "Engine/src/*.h")
file(GLOB EngineRenderingSOURCES "Engine/src/Rendering/*.cpp" "Engine/src/Rendering/*.h")
file(GLOB EngineAppSOURCES "Engine/src/App/*.cpp" "Engine/src/App/*.h")
file(GLOB EngineRenderingRenderablesSOURCES "Engine/src/Rendering/Renderables/*.cpp" "Engine/src/Rendering/Renderables/*.h")
file(GLOB EngineManagingSOURCES "Engine/src/Managing/*.cpp" "Engine/src/Managing/*.h")
file(GLOB EngineTypesSOURCES "Engine/src/Types/*.cpp" "Engine/src/Types/*.h")
file(GLOB EngineGameEssentialsSOURCES "Engine/src/GameEssentials/*.cpp" "Engine/src/GameEssentials/*.h")
file(GLOB EngineLibsSOURCES "Libraries/whereami/src/whereami.c" "Libraries/glad/src/glad.c")
file(GLOB EngineFrameworkSOURCES "Engine/src/Framework/*.h" "Engine/src/Framework/*.cpp")
file(GLOB APISOURCES "Engine/src/API/*.cpp" "Engine/src/API/*.h")
file(GLOB EngineExtAppSOURCES "Engine/src/ExtApp/*.cpp" "Engine/src/ExtApp/*.h"
"Engine/src/ExtApp/Interface/*.cpp" "Engine/src/ExtApp/Interface/*.h")
file(GLOB EngineExtAppGameSOURCES "Engine/src/ExtApp/Game/*.cpp" "Engine/src/ExtApp/Game/*.h")
source_group("ExtApp" FILES $EngineExtAppGameSOURCES)
file(GLOB EngineExtAppEngineSOURCES "Engine/src/ExtApp/Engine/*.cpp" "Engine/src/ExtApp/Engine/*.h")
source_group("ExtApp" FILES $EngineExtAppEngineSOURCES)
if(BUILD_ENGINE_FOR_EDITOR)
file(GLOB EngineEditorSOURCES "Engine/src/ExtApp/*.cpp" "Engine/src/ExtApp/*.h"
"Engine/src/ExtApp/Interface/*.cpp" "Engine/src/ExtApp/Interface/*.h")
if(BUILD_ENGINE_FOR_DLL_APPS)
add_library(Engine SHARED $EngineRootSOURCES $EngineRenderingSOURCES $EngineTypesSOURCES $EngineRenderingRenderablesSOURCES $EngineManagingSOURCES $EngineGameEssentialsSOURCES $EngineLibsSOURCES $EngineEditorSOURCES $EngineExtAppSOURCES $EngineAppSOURCES $APISOURCES $EngineExtAppEngineSOURCES $EngineFrameworkSOURCES)
source_group("ExtApp" FILES $EngineExtAppSOURCES)
elseif(NOT BUILD_ENGINE_FOR_DLL_APPS)
add_library(Engine SHARED $EngineRootSOURCES $EngineRenderingSOURCES $EngineTypesSOURCES $EngineRenderingRenderablesSOURCES $EngineManagingSOURCES $EngineGameEssentialsSOURCES $EngineLibsSOURCES $EngineEditorSOURCES $EngineExtAppSOURCES $EngineAppSOURCES $APISOURCES $EngineExtAppEngineSOURCES $EngineFrameworkSOURCES)
endif()
target_link_libraries(Engine glfw)
source_group("Rendering" FILES $EngineRenderingSOURCES)
source_group("Rendering/Renderables" FILES $EngineRenderingRenderablesSOURCES)
source_group("Managing" FILES $EngineManagingSOURCES)
source_group("App" FILES $EngineAppSOURCES)
source_group("Types" FILES $EngineTypesSOURCES)
source_group("GameEssentials" FILES $EngineGameEssentialsSOURCES)
source_group("Libs" FILES $EngineLibsSOURCES)
source_group("ExtApp" FILES $EngineEditorSOURCES)
source_group("API" FILES $APISOURCES)
source_group("Framework" FILES $EngineFrameworkSOURCES)
elseif(NOT BUILD_ENGINE_FOR_EDITOR)
if(BUILD_ENGINE_FOR_DLL_APPS)
file(GLOB EngineExtAppSOURCES "Engine/src/ExtApp/*.cpp" "Engine/src/ExtApp/*.h"
"Engine/src/ExtApp/Interface/*.cpp" "Engine/src/ExtApp/Interface/*.h")
add_executable(Engine $EngineRootSOURCES $EngineRenderingSOURCES $EngineTypesSOURCES $EngineRenderingRenderablesSOURCES $EngineManagingSOURCES $EngineGameEssentialsSOURCES $EngineLibsSOURCES $EngineExtAppSOURCES $EngineAppSOURCES $APISOURCES $EngineExtAppEngineSOURCES $EngineFrameworkSOURCES)
source_group("ExtApp" FILES $EngineExtAppSOURCES)
elseif(NOT BUILD_ENGINE_FOR_DLL_APPS)
add_executable(Engine $EngineRootSOURCES $EngineRenderingSOURCES $EngineTypesSOURCES $EngineRenderingRenderablesSOURCES $EngineManagingSOURCES $EngineGameEssentialsSOURCES $EngineLibsSOURCES $EngineExtAppSOURCES $EngineAppSOURCES $APISOURCES $EngineExtAppEngineSOURCES $EngineFrameworkSOURCES)
endif()
target_link_libraries(Engine glfw)
source_group("Rendering" FILES $EngineRenderingSOURCES)
source_group("Rendering/Renderables" FILES $EngineRenderingRenderablesSOURCES)
source_group("Managing" FILES $EngineManagingSOURCES)
source_group("App" FILES $EngineAppSOURCES)
source_group("Types" FILES $EngineTypesSOURCES)
source_group("GameEssentials" FILES $EngineGameEssentialsSOURCES)
source_group("Libs" FILES $EngineLibsSOURCES)
source_group("API" FILES $APISOURCES)
source_group("Framework" FILES $EngineFrameworkSOURCES)
endif()
#add_library(Engine SHARED $EngineSOURCES)
## END project engine
project (Module_OpenGL_Renderer_Input)#project module_renderer_opengl3
include_directories(Libraries/glfw/include)
include_directories(Libraries/glm)
include_directories(Libraries/glad/include)
include_directories(Libraries/stb)
file(GLOB Module_OpenGL_Renderer_InputSOURCES "Modules/Module_OpenGL_Renderer_Input/src/*.cpp" "Modules/Module_OpenGL_Renderer_Input/src/*.h" "Libraries/glad/src/glad.c")
add_library(Module_OpenGL_Renderer_Input SHARED $Module_OpenGL_Renderer_InputSOURCES)
target_link_libraries(glfw)
##END project module_renderer_opengl3
project (Test1)#project test | This project is used to test the engine functionality.
include_directories(Libraries/imgui)
file(GLOB Test1SOURCES "Tests/Test1/src/*.cpp" "Tests/Test1/src/*.h" "Libraries/imgui/imgui*.cpp" $APISOURCES)
add_executable(Test1 $Test1SOURCES)
target_link_libraries(Test1 $CMAKE_DL_LIBS)
project (TestGame)#project test | This project is used to test the engine functionality.
include_directories(Libraries/imgui)
file(GLOB TestGameSOURCES "Tests/TestGame/src/*.cpp" "Tests/TestGame/src/*.h" "Libraries/imgui/imgui*.cpp" $EngineRenderingSOURCES $EngineTypesSOURCES $EngineRenderingRenderablesSOURCES $EngineManagingSOURCES $EngineGameEssentialsSOURCES $EngineLibsSOURCES $EngineAppSOURCES $APISOURCES $EngineExtAppSOURCES $EngineExtAppGameSOURCES $EngineFrameworkSOURCES)
add_library(TestGame SHARED $TestGameSOURCES)
target_link_libraries(TestGame glfw)
project (Editor)#project editor | This is used to make projects and build projects(using the engine)
include_directories(Libraries/imgui)
file(GLOB EditorSOURCES "Editor/src/*.cpp" "Editor/src/*.h" "Libraries/imgui/imgui*.cpp" $APISOURCES)
add_executable(Editor $EditorSOURCES)
我包含很多完全没用或不再需要的东西。 所以这是我的问题:
-
是否每个目录都需要一个 CMakeLists 文件,就像我在很多项目中看到的那样?
我需要提供包含源文件的每个目录,还是让它自动搜索目录中的源文件和头文件?
我还看到很多其他 CMake 项目分别提供每个源/头文件,为什么?每次添加文件的工作量不是很大吗?
谁有我可以用作指导的大型 CMake 项目示例?
还有什么可以改进的吗?
谢谢!
【问题讨论】:
在“大型项目”中使用 CMake 没有通用方法。但是大多数此类项目使用多个CMakeLists.txt
(在不同的目录中)。你在一个问题帖子中问了太多问题,这在 Stack Overflow 上是不受欢迎的。您可以先将CMakeLists.txt
拆分为多个目录,然后询问您将面临的具体问题。
@Tsyvarev 但是我该怎么做,它会是什么样子?很抱歉在一篇文章中问了太多问题,我想如果我把它分成单独的问题,它会被视为垃圾邮件。
CMakeLists.txt
位于子目录中通常只处理该子目录中的文件。 Editor/CMakeLists.txt
可以编译 Editor/src/main.cpp
源代码。根据第一个问题,您已经看到许多在每个目录中都使用CMakeLists.txt
的项目。为什么不简单地遵循这样的项目之一?
@Tsyvarev 感谢您的回复。好吧,我知道的唯一使用 CMake 的大型库/项目是 GLFW 和 Bullet,我想不出任何其他的。你可能知道一些吗?
【参考方案1】:
是否每个目录都需要一个 CMakeLists 文件
不,没必要。
为每个子模块和库拥有一个 CMakeLists.txt 可能是个好主意 - 并在项目本身的根目录中拥有一个。
我是否需要提供包含源文件的每个目录,或者我可以让它自动搜索目录中的源文件和头文件?
首先,查看问题 3 的答案。
其次,我不明白您为什么要搜索头文件。只需指定包含目录。
最后,如果你想使用 glob,可以将所有源文件放在一个目录下,并使用一个 glob。
我还看到很多其他 CMake 项目分别提供每个源...文件,为什么?
这是文档所说的:
注意
我们不建议使用 GLOB 从源代码树中收集源文件列表。如果添加或删除源时没有 CMakeLists.txt 文件更改,则生成的构建系统无法知道何时要求 CMake 重新生成。 CONFIGURE_DEPENDS 标志可能无法在所有生成器上可靠地工作,或者如果将来添加不能支持它的新生成器,使用它的项目将被卡住。即使 CONFIGURE_DEPENDS 工作可靠,每次重建时执行检查仍然需要成本。
...每个头文件分开,为什么?
我从来没有见过这个。
还有什么可以改进的吗?
使用target_include_directories
代替include_directories
。一般来说,始终使用target_X
指令。
【讨论】:
感谢您的回答!让我回复你说的话: 子模块的例子是什么?什么是子模块?我也想添加头文件,因为我有时使用 Visual Studio,它显示的文件与其他 IDE 不同。每当我添加文件时,我总是重新配置和重新生成我的项目,我认为这应该没问题。但是,在 CMakeLists 文件中添加每个文件不是很多工作,还是人们以某种方式自动化?我现在将使用 target_include_directories 表单。 @TimLeijten 模块是一个独立的单元。子模块是一个模块,它是另一个模块的一部分。可执行文件是模块的示例,库是子模块的示例。我提到它是为了以防你有一个你不会描述为库的子模块。 @TimLeijten 在我看来,每次添加/删除源文件时更改 CMakeLists.txt 文件并不是很多工作,但我同意这很烦人它冗余地复制了文件系统上的信息。但这就是 CMake 的设计,尽管它可能存在缺陷。一些 IDE 会自动编辑 CMakeLists.txt。 嗯,问题是我的项目并没有真正使用模块作为它的基础,物理之类的东西是它自己的模块,但渲染、基类、场景管理、资源管理等都在相同的项目/模块。这是否意味着我为此使用了一个 CMakeLists?您是否知道任何自动修改 CMakeLists 的 IDE?或插件。(用于 VS 或 CLion)以上是关于具有多个目录的大型项目的 CMakeLists?的主要内容,如果未能解决你的问题,请参考以下文章