Reputation: 351
I have a project were I use CMake with a structure like this:
CMakeLists.txt
├── build
├── include
│ ├── AudioDevice.h
│ ├── Game.h
│ ├── game_objects
│ │ ├── Ball.h
│ │ ├── Brick.h
│ │ ├── GameObject.h
│ │ ├── IndestructibleBrick.h
│ │ ├── MoveableGameObject.h
│ │ ├── Physics.h
│ │ ├── Platform.h
│ │ └── Wall.h
│ ├── GameParameter.h
│ ├── InputHandler.h
│ ├── Level.h
│ ├── Renderer.h
│ └── SDL_RAII.h
├── src
│ ├── AudioDevice.cpp
│ ├── Game.cpp
│ ├── game_objects
│ │ ├── Ball.cpp
│ │ ├── Brick.cpp
│ │ ├── GameObject.cpp
│ │ ├── MoveableGameObject.cpp
│ │ ├── Physics.cpp
│ │ └── Platform.cpp
│ ├── GameParameter.cpp
│ ├── InputHandler.cpp
│ ├── Level.cpp
│ ├── main.cpp
│ ├── Renderer.cpp
│ └── SDL_RAII.cpp
├── test
│ ├── game_objects
│ │ ├── Ball_test.cpp
│ │ ├── Brick_test.cpp
│ │ ├── GameObject_test.cpp
│ │ ├── MoveableGameObject_test.cpp
│ │ ├── Physics_test.cpp
│ │ └── Platform_test.cpp
│ └── Level_test.cpp
Now I want to improve how the Project is organized with CMake. Currently I only have one CMakeLists.txt
in the root directory. Good practice should be to have it in each folder.
My CMakeLists.txt
in the root directory currently looks like this:
cmake_minimum_required(VERSION 3.7)
add_definitions(-std=c++17)
set(CXX_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS, "${CXX_FLAGS}")
set(CMAKE_CXX_CLANG_TIDY clang-tidy -checks=-*,readability-*)
project(bricks)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(LIBRARY_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/lib")
#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
find_package(SDL2 REQUIRED)
find_package(SDL2_mixer REQUIRED)
include_directories(
${SDL2_INCLUDE_DIRS}
${SDL2_mixer_INCLUDE_DIRS}
include
include/game_objects
include/types
include/utility
)
add_subdirectory(thirdparty/googletest)
add_executable(bricks
src/game_objects/Ball.cpp
src/game_objects/Brick.cpp
src/game_objects/GameObject.cpp
src/game_objects/MoveableGameObject.cpp
src/game_objects/Physics.cpp
src/game_objects/Platform.cpp
src/AudioDevice.cpp
src/Game.cpp
src/GameParameter.cpp
src/InputHandler.cpp
src/Level.cpp
src/main.cpp
src/Renderer.cpp
src/SDL_RAII.cpp
)
target_link_libraries(
bricks
SDL2::Main
SDL2::Mixer
)
add_executable(test
test/game_objects/Ball_test.cpp
src/game_objects/Ball.cpp
test/game_objects/Brick_test.cpp
src/game_objects/Brick.cpp
test/game_objects/GameObject_test.cpp
src/game_objects/GameObject.cpp
test/game_objects/MoveableGameObject_test.cpp
src/game_objects/MoveableGameObject.cpp
test/game_objects/Physics_test.cpp
src/game_objects/Physics.cpp
test/game_objects/Platform_test.cpp
src/game_objects/Platform.cpp
# needs to be added so linker works with level
src/GameParameter.cpp
test/Level_test.cpp
src/Level.cpp
)
target_link_libraries(test
gtest_main
)
Now I thought as a first step, it would be good to put the stuff from the folder src
in its own CMakeLists.txt
.
So my root file became this:
cmake_minimum_required(VERSION 3.7)
add_definitions(-std=c++17)
set(CXX_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS, "${CXX_FLAGS}")
set(CMAKE_CXX_CLANG_TIDY clang-tidy -checks=-*,readability-* -fix)
project(bricks)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(LIBRARY_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/lib")
#set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
find_package(SDL2 REQUIRED)
find_package(SDL2_mixer REQUIRED)
add_subdirectory(src)
add_subdirectory(thirdparty/googletest)
add_executable(test
test/game_objects/Ball_test.cpp
src/game_objects/Ball.cpp
test/game_objects/Brick_test.cpp
src/game_objects/Brick.cpp
test/game_objects/GameObject_test.cpp
src/game_objects/GameObject.cpp
test/game_objects/MoveableGameObject_test.cpp
src/game_objects/MoveableGameObject.cpp
test/game_objects/Physics_test.cpp
src/game_objects/Physics.cpp
test/game_objects/Platform_test.cpp
src/game_objects/Platform.cpp
src/GameParameter.cpp
test/Level_test.cpp
src/Level.cpp
)
target_link_libraries(test
gtest_main
)
And I created this file in src
:
include_directories(
${SDL2_INCLUDE_DIRS}
${SDL2_mixer_INCLUDE_DIRS}
../include
../include/game_objects
../include/types
../include/utility
)
add_executable(bricks
game_objects/Ball.cpp
game_objects/Brick.cpp
game_objects/GameObject.cpp
game_objects/MoveableGameObject.cpp
game_objects/Physics.cpp
game_objects/Platform.cpp
AudioDevice.cpp
Game.cpp
GameParameter.cpp
InputHandler.cpp
Level.cpp
main.cpp
Renderer.cpp
SDL_RAII.cpp
)
target_link_libraries(
bricks
SDL2::Main
SDL2::Mixer
)
Now when I run CMake it does not work. I get complains in Ball.cpp
and the other files that it can't find the header files. I thought I added them with include_directories
.
I really cannot find out whats going on here. I already googled myself for the issue but cannot find the solution.
I would appreciate very much if someone could give me a hint how to restructure this well.
Upvotes: 1
Views: 3441
Reputation: 18243
The include_directories()
command applies the listed include directories to targets in the current CMake file, and those in child directories. So, the include_directories()
command won't apply the include directories to your test
target in the top-level CMake file. Therefore, the sources listed for your test
executable will have no knowledge of the include directories you listed. A simple fix for this is to simply move the the include_directories()
call to your top-level CMake file:
...
include_directories(
${SDL2_INCLUDE_DIRS}
${SDL2_mixer_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/include/game_objects
${CMAKE_SOURCE_DIR}/include/types
${CMAKE_SOURCE_DIR}/include/utility
)
add_subdirectory(src)
add_subdirectory(thirdparty/googletest)
add_executable(test
test/game_objects/Ball_test.cpp
src/game_objects/Ball.cpp
test/game_objects/Brick_test.cpp
src/game_objects/Brick.cpp
test/game_objects/GameObject_test.cpp
src/game_objects/GameObject.cpp
test/game_objects/MoveableGameObject_test.cpp
src/game_objects/MoveableGameObject.cpp
test/game_objects/Physics_test.cpp
src/game_objects/Physics.cpp
test/game_objects/Platform_test.cpp
src/game_objects/Platform.cpp
src/GameParameter.cpp
test/Level_test.cpp
src/Level.cpp
)
target_link_libraries(test
gtest_main
)
You should also use the variable CMAKE_SOURCE_DIR
to grab the full path to the top-level CMake file, to avoid using relative paths.
FWIW, I'm not aware of any guidance that claims you should have a CMakeLists.txt
file in each sub-directory of your project. The way you structure your CMakeLists.txt files in your project hierarchy is obviously dependent on how your files are laid out in your file system, how lengthy you want each CMakeLists.txt file to be, and other design decisions. For large projects, I've seen that it is common to have one CMakeLists.txt file per target.
Upvotes: 2