CMakeLists.txt 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. cmake_minimum_required(VERSION 3.21)
  2. project(StandardOfIron VERSION 1.0.0 LANGUAGES CXX)
  3. set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
  4. # ---- Clang-Tidy integration ----
  5. find_program(CLANG_TIDY_EXE NAMES clang-tidy)
  6. option(ENABLE_CLANG_TIDY "Enable clang-tidy analysis" OFF)
  7. if (ENABLE_CLANG_TIDY AND CLANG_TIDY_EXE)
  8. message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
  9. # Prefer using .clang-tidy config, but define fallback checks for safety
  10. set(CLANG_TIDY_ARGS "-header-filter=^(?!.*third_party/).*/Standard-of-Iron/.*")
  11. set(CLANG_TIDY_FILTER "${CMAKE_SOURCE_DIR}/tools/clang_tidy_filter.sh")
  12. if(NOT EXISTS "${CMAKE_SOURCE_DIR}/.clang-tidy")
  13. list(APPEND CLANG_TIDY_ARGS
  14. "-checks=bugprone-*,performance-*,readability-*,modernize-*,cppcoreguidelines-*,clang-analyzer-*")
  15. endif()
  16. set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_FILTER} ${CLANG_TIDY_EXE} ${CLANG_TIDY_ARGS})
  17. elseif (ENABLE_CLANG_TIDY)
  18. message(WARNING "clang-tidy requested but not found! Static analysis skipped.")
  19. else()
  20. message(STATUS "clang-tidy disabled (ENABLE_CLANG_TIDY=OFF)")
  21. endif()
  22. # Prefer Qt6 if both Qt5/Qt6 are installed
  23. set(QT_DEFAULT_MAJOR_VERSION 6)
  24. set(CMAKE_CXX_STANDARD 20)
  25. set(CMAKE_CXX_STANDARD_REQUIRED ON)
  26. set(CMAKE_CXX_EXTENSIONS OFF)
  27. # ---- Windows-specific definitions ----
  28. if(WIN32)
  29. add_compile_definitions(NOMINMAX) # Prevent min/max macros from windows.h
  30. endif()
  31. # ---- Compiler Optimization Flags ----
  32. if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  33. if(MSVC)
  34. # MSVC Debug flags
  35. set(CMAKE_CXX_FLAGS_DEBUG "/Od /Zi /DDEBUG")
  36. set(CMAKE_C_FLAGS_DEBUG "/Od /Zi /DDEBUG")
  37. else()
  38. # GCC/Clang Debug flags
  39. set(CMAKE_CXX_FLAGS_DEBUG "-g3 -O0 -DDEBUG")
  40. set(CMAKE_C_FLAGS_DEBUG "-g3 -O0 -DDEBUG")
  41. # Additional GDB-friendly flags
  42. add_compile_options(-ggdb3) # Maximum debug info for GDB
  43. add_compile_options(-fno-omit-frame-pointer) # Keep frame pointers for better backtraces
  44. add_compile_options(-fno-inline) # Don't inline functions for easier debugging
  45. # Disable optimizations that make debugging harder
  46. add_compile_options(-fno-optimize-sibling-calls)
  47. endif()
  48. message(STATUS "Building in DEBUG mode with GDB support")
  49. else()
  50. # Release/RelWithDebInfo: optimize for performance
  51. if(MSVC)
  52. # MSVC Release flags
  53. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2")
  54. else()
  55. # GCC/Clang Release flags
  56. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ffast-math")
  57. endif()
  58. set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # Enable LTO
  59. message(STATUS "Building in RELEASE mode with optimizations")
  60. endif()
  61. # ---- Qt ----
  62. # Try Qt6 first, fall back to Qt5 if not available
  63. find_package(Qt6 QUIET COMPONENTS Core Widgets OpenGL Quick Qml QuickControls2 Sql Multimedia)
  64. if(Qt6_FOUND)
  65. message(STATUS "Using Qt6")
  66. set(QT_VERSION_MAJOR 6)
  67. find_package(OpenGL REQUIRED)
  68. else()
  69. message(STATUS "Qt6 not found, trying Qt5")
  70. find_package(Qt5 REQUIRED COMPONENTS Core Widgets OpenGL Quick Qml QuickControls2 Sql Multimedia)
  71. message(STATUS "Using Qt5")
  72. set(QT_VERSION_MAJOR 5)
  73. find_package(OpenGL REQUIRED)
  74. endif()
  75. if(COMMAND qt_standard_project_setup)
  76. qt_standard_project_setup()
  77. elseif(COMMAND qt6_standard_project_setup)
  78. qt6_standard_project_setup()
  79. endif()
  80. include_directories(${CMAKE_CURRENT_SOURCE_DIR})
  81. set(CMAKE_AUTOMOC ON)
  82. # ---- Google Test Setup ----
  83. include(FetchContent)
  84. FetchContent_Declare(
  85. googletest
  86. GIT_REPOSITORY https://github.com/google/googletest.git
  87. GIT_TAG v1.14.0
  88. )
  89. # For Windows: Prevent overriding the parent project's compiler/linker settings
  90. set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
  91. FetchContent_MakeAvailable(googletest)
  92. # Enable testing
  93. enable_testing()
  94. # engine core moved under game; no separate engine subdir target
  95. add_subdirectory(render)
  96. add_subdirectory(game)
  97. add_subdirectory(ui)
  98. add_subdirectory(tools)
  99. add_subdirectory(tests)
  100. # ---- Translation support ----
  101. # Define default language (can be overridden with -DDEFAULT_LANG=de)
  102. if(NOT DEFINED DEFAULT_LANG)
  103. set(DEFAULT_LANG "en")
  104. endif()
  105. add_compile_definitions(DEFAULT_LANG="${DEFAULT_LANG}")
  106. # ---- Executable ----
  107. if(QT_VERSION_MAJOR EQUAL 6)
  108. qt6_add_executable(standard_of_iron
  109. main.cpp
  110. app/core/game_engine.cpp
  111. app/core/language_manager.cpp
  112. app/core/minimap_manager.cpp
  113. app/core/ambient_state_manager.cpp
  114. app/core/audio_resource_loader.cpp
  115. app/core/renderer_bootstrap.cpp
  116. app/core/level_orchestrator.cpp
  117. app/core/input_command_handler.cpp
  118. app/core/camera_controller.cpp
  119. app/core/game_state_restorer.cpp
  120. app/models/audio_system_proxy.cpp
  121. app/models/graphics_settings_proxy.cpp
  122. app/models/cursor_manager.cpp
  123. app/models/hover_tracker.cpp
  124. app/models/selected_units_model.cpp
  125. app/models/minimap_image_provider.cpp
  126. app/controllers/command_controller.cpp
  127. app/controllers/action_vfx.cpp
  128. app/utils/json_vec_utils.cpp
  129. ui/gl_view.cpp
  130. ui/theme.cpp
  131. )
  132. else()
  133. add_executable(standard_of_iron
  134. main.cpp
  135. app/core/game_engine.cpp
  136. app/core/language_manager.cpp
  137. app/core/minimap_manager.cpp
  138. app/core/ambient_state_manager.cpp
  139. app/core/audio_resource_loader.cpp
  140. app/core/renderer_bootstrap.cpp
  141. app/core/level_orchestrator.cpp
  142. app/core/input_command_handler.cpp
  143. app/core/camera_controller.cpp
  144. app/core/game_state_restorer.cpp
  145. app/models/audio_system_proxy.cpp
  146. app/models/graphics_settings_proxy.cpp
  147. app/models/cursor_manager.cpp
  148. app/models/hover_tracker.cpp
  149. app/models/selected_units_model.cpp
  150. app/models/minimap_image_provider.cpp
  151. app/controllers/command_controller.cpp
  152. app/controllers/action_vfx.cpp
  153. app/utils/json_vec_utils.cpp
  154. ui/gl_view.cpp
  155. ui/theme.cpp
  156. )
  157. endif()
  158. # ---- QML module ----
  159. if(QT_VERSION_MAJOR EQUAL 6)
  160. qt6_add_qml_module(standard_of_iron
  161. URI StandardOfIron
  162. VERSION 1.0
  163. QML_FILES
  164. ui/qml/Main.qml
  165. ui/qml/MainMenu.qml
  166. ui/qml/MapSelect.qml
  167. ui/qml/MapListPanel.qml
  168. ui/qml/PlayerListItem.qml
  169. ui/qml/PlayerConfigPanel.qml
  170. ui/qml/CampaignMenu.qml
  171. ui/qml/StyleGuide.qml
  172. ui/qml/StyledButton.qml
  173. ui/qml/HUD.qml
  174. ui/qml/HUDTop.qml
  175. ui/qml/HUDBottom.qml
  176. ui/qml/ProductionPanel.qml
  177. ui/qml/SaveGamePanel.qml
  178. ui/qml/LoadGamePanel.qml
  179. ui/qml/SettingsPanel.qml
  180. ui/qml/HUDVictory.qml
  181. ui/qml/BattleSummary.qml
  182. ui/qml/GameView.qml
  183. ui/qml/CursorManager.qml
  184. RESOURCES
  185. assets/shaders/archer.frag
  186. assets/shaders/archer.vert
  187. assets/shaders/archer_roman_republic.frag
  188. assets/shaders/archer_roman_republic.vert
  189. assets/shaders/archer_carthage.frag
  190. assets/shaders/archer_carthage.vert
  191. assets/shaders/basic.frag
  192. assets/shaders/basic.vert
  193. assets/shaders/bridge.frag
  194. assets/shaders/bridge.vert
  195. assets/shaders/cylinder_instanced.frag
  196. assets/shaders/cylinder_instanced.vert
  197. assets/shaders/firecamp.frag
  198. assets/shaders/firecamp.vert
  199. assets/shaders/fog_instanced.frag
  200. assets/shaders/fog_instanced.vert
  201. assets/shaders/grass_instanced.frag
  202. assets/shaders/grass_instanced.vert
  203. assets/shaders/grid.frag
  204. assets/shaders/ground_plane.frag
  205. assets/shaders/ground_plane.vert
  206. assets/shaders/swordsman.frag
  207. assets/shaders/swordsman.vert
  208. assets/shaders/swordsman_roman_republic.frag
  209. assets/shaders/swordsman_roman_republic.vert
  210. assets/shaders/swordsman_carthage.frag
  211. assets/shaders/swordsman_carthage.vert
  212. assets/shaders/horse_swordsman.frag
  213. assets/shaders/horse_swordsman.vert
  214. assets/shaders/horse_swordsman_roman_republic.frag
  215. assets/shaders/horse_swordsman_roman_republic.vert
  216. assets/shaders/horse_swordsman_carthage.frag
  217. assets/shaders/horse_swordsman_carthage.vert
  218. assets/shaders/horse_archer_roman_republic.frag
  219. assets/shaders/horse_archer_roman_republic.vert
  220. assets/shaders/horse_archer_carthage.frag
  221. assets/shaders/horse_archer_carthage.vert
  222. assets/shaders/horse_spearman_roman_republic.frag
  223. assets/shaders/horse_spearman_roman_republic.vert
  224. assets/shaders/horse_spearman_carthage.frag
  225. assets/shaders/horse_spearman_carthage.vert
  226. assets/shaders/healer.frag
  227. assets/shaders/healer.vert
  228. assets/shaders/healer_roman_republic.frag
  229. assets/shaders/healer_roman_republic.vert
  230. assets/shaders/healer_carthage.frag
  231. assets/shaders/healer_carthage.vert
  232. assets/shaders/pine_instanced.frag
  233. assets/shaders/pine_instanced.vert
  234. assets/shaders/plant_instanced.frag
  235. assets/shaders/plant_instanced.vert
  236. assets/shaders/river.frag
  237. assets/shaders/river.vert
  238. assets/shaders/riverbank.frag
  239. assets/shaders/riverbank.vert
  240. assets/shaders/spearman.frag
  241. assets/shaders/spearman.vert
  242. assets/shaders/spearman_roman_republic.frag
  243. assets/shaders/spearman_roman_republic.vert
  244. assets/shaders/spearman_carthage.frag
  245. assets/shaders/spearman_carthage.vert
  246. assets/shaders/stone_instanced.frag
  247. assets/shaders/stone_instanced.vert
  248. assets/shaders/terrain_chunk.frag
  249. assets/shaders/terrain_chunk.vert
  250. assets/maps/map_forest.json
  251. assets/maps/map_rivers.json
  252. assets/maps/map_mountain.json
  253. assets/visuals/unit_visuals.json
  254. assets/visuals/emblems/rome.png
  255. assets/visuals/emblems/cartaghe.png
  256. assets/visuals/icons/archer_rome.png
  257. assets/visuals/icons/archer_cartaghe.png
  258. assets/visuals/icons/swordsman_rome.png
  259. assets/visuals/icons/swordsman_cartaghe.png
  260. assets/visuals/icons/spearman_rome.png
  261. assets/visuals/icons/spearman_cartaghe.png
  262. assets/visuals/icons/horse_swordsman_rome.png
  263. assets/visuals/icons/horse_swordsman_cartaghe.png
  264. assets/visuals/icons/horse_archer_rome.png
  265. assets/visuals/icons/horse_archer_cartaghe.png
  266. assets/visuals/icons/horse_spearman_rome.png
  267. assets/visuals/icons/horse_spearman_cartaghe.png
  268. assets/visuals/icons/healer_rome.png
  269. assets/visuals/icons/healer_cartaghe.png
  270. assets/visuals/icons/catapult_rome.png
  271. assets/visuals/icons/catapult_cartaghe.png
  272. assets/visuals/icons/ballista_rome.png
  273. assets/visuals/icons/ballista_cartaghe.png
  274. translations/app_en.qm
  275. translations/app_de.qm
  276. translations/app_pt_br.qm
  277. DEPENDENCIES
  278. Qt6::QuickControls2
  279. )
  280. else()
  281. qt5_add_resources(qml_resources qml_resources.qrc)
  282. qt5_add_resources(assets_resources assets.qrc)
  283. qt5_add_resources(translations_resources translations.qrc)
  284. target_sources(standard_of_iron PRIVATE ${qml_resources} ${assets_resources} ${translations_resources})
  285. endif()
  286. target_link_libraries(standard_of_iron
  287. PRIVATE
  288. Qt${QT_VERSION_MAJOR}::Core
  289. Qt${QT_VERSION_MAJOR}::Widgets
  290. Qt${QT_VERSION_MAJOR}::OpenGL
  291. Qt${QT_VERSION_MAJOR}::Quick
  292. Qt${QT_VERSION_MAJOR}::Qml
  293. Qt${QT_VERSION_MAJOR}::Sql
  294. Qt${QT_VERSION_MAJOR}::Multimedia
  295. ${OPENGL_LIBRARIES}
  296. engine_core
  297. render_gl
  298. game_systems
  299. audio_system
  300. )
  301. # Windows-specific OpenGL linking
  302. if(WIN32)
  303. target_link_libraries(standard_of_iron PRIVATE opengl32)
  304. # Ensure we have access to wglGetProcAddress and related functions
  305. target_compile_definitions(standard_of_iron PRIVATE NOMINMAX)
  306. endif()
  307. if(QT_VERSION_MAJOR EQUAL 6)
  308. target_link_libraries(standard_of_iron PRIVATE Qt6::QuickControls2)
  309. else()
  310. target_link_libraries(standard_of_iron PRIVATE Qt5::QuickControls2)
  311. endif()
  312. set_target_properties(standard_of_iron PROPERTIES
  313. RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
  314. )
  315. if (WIN32)
  316. set_target_properties(standard_of_iron PROPERTIES WIN32_EXECUTABLE TRUE)
  317. endif()
  318. install(TARGETS standard_of_iron RUNTIME DESTINATION .)
  319. install(DIRECTORY assets/ DESTINATION assets)
  320. # Copy assets next to the binary for dev runs
  321. file(COPY assets/ DESTINATION ${CMAKE_BINARY_DIR}/bin/assets/)
  322. # ---- clang-format helpers (optional but convenient) ----
  323. # Provides:
  324. # - clang-format : formats all C/C++ sources using .clang-format
  325. # - clang-format-check : CI-style check (no changes), fails on violations
  326. find_program(CLANG_FORMAT_EXE NAMES clang-format)
  327. if (CLANG_FORMAT_EXE)
  328. message(STATUS "Found clang-format: ${CLANG_FORMAT_EXE}")
  329. file(GLOB_RECURSE ALL_CXX CONFIGURE_DEPENDS
  330. "${CMAKE_SOURCE_DIR}/*.c" "${CMAKE_SOURCE_DIR}/*.cpp"
  331. "${CMAKE_SOURCE_DIR}/*.h" "${CMAKE_SOURCE_DIR}/*.hpp")
  332. # Exclude the current build tree (generated sources, moc_*.cpp, etc.)
  333. list(FILTER ALL_CXX EXCLUDE REGEX "${CMAKE_BINARY_DIR}/.*")
  334. if (ALL_CXX)
  335. add_custom_target(clang-format
  336. COMMAND "${CLANG_FORMAT_EXE}" -i --style=file ${ALL_CXX}
  337. WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
  338. COMMENT "Running clang-format with .clang-format (strict)")
  339. add_custom_target(clang-format-check
  340. COMMAND "${CLANG_FORMAT_EXE}" --dry-run -Werror --style=file ${ALL_CXX}
  341. WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
  342. COMMENT "Checking clang-format compliance")
  343. else()
  344. add_custom_target(clang-format
  345. COMMAND "${CMAKE_COMMAND}" -E echo "No C/C++ files found to format.")
  346. add_custom_target(clang-format-check
  347. COMMAND "${CMAKE_COMMAND}" -E echo "No C/C++ files found to check.")
  348. endif()
  349. endif()