|
| 1 | +cmake_minimum_required(VERSION 3.16) |
| 2 | + |
| 3 | + |
| 4 | +# Set root directory, if needed |
| 5 | +if (NOT GFXF_ROOT_DIR) |
| 6 | + set(GFXF_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) |
| 7 | +endif() |
| 8 | + |
| 9 | + |
| 10 | +# Set the name of the project |
| 11 | +set(target_name GFXFramework) |
| 12 | +project(${target_name} C CXX) |
| 13 | + |
| 14 | + |
| 15 | +# Use C99 and C++11 |
| 16 | +set(CMAKE_C_STANDARD 99) |
| 17 | +set(CMAKE_C_STANDARD_REQUIRED ON) |
| 18 | + |
| 19 | +set(CMAKE_CXX_STANDARD 11) |
| 20 | +set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 21 | + |
| 22 | + |
| 23 | +# Include helper scripts |
| 24 | +include(${GFXF_ROOT_DIR}/infra/utils.cmake) |
| 25 | +custom_set_build_type() |
| 26 | + |
| 27 | + |
| 28 | +# Fix to hide a bug in CMake. Hopefully able to be removed in the future. |
| 29 | +set(CMAKE_POLICY_DEFAULT_CMP0012 NEW) |
| 30 | + |
| 31 | + |
| 32 | +# Find required packages |
| 33 | +find_package(OpenGL REQUIRED) |
| 34 | +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") |
| 35 | + find_package(GLEW REQUIRED) |
| 36 | + find_package(PkgConfig REQUIRED) |
| 37 | + pkg_search_module(GLFW REQUIRED glfw3) |
| 38 | + find_package(assimp REQUIRED) |
| 39 | + find_package(spdlog REQUIRED) |
| 40 | + find_package(Freetype REQUIRED) |
| 41 | +endif() |
| 42 | + |
| 43 | + |
| 44 | +# Set options |
| 45 | +option(WITH_LAB_M1 "With module 1 labs" ON) |
| 46 | +option(WITH_LAB_M2 "With module 2 labs" OFF) |
| 47 | +option(WITH_LAB_EXTRA "With extra labs" OFF) |
| 48 | +option(USE_DEV_COMPONENTS "Use dev components" OFF) |
| 49 | + |
| 50 | + |
| 51 | +# Set RPATH to avoid using LD_LIBRARY_PATH |
| 52 | +set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) |
| 53 | +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") |
| 54 | + set(CMAKE_INSTALL_RPATH "@executable_path") |
| 55 | +else() |
| 56 | + set(CMAKE_INSTALL_RPATH "$ORIGIN") |
| 57 | +endif() |
| 58 | + |
| 59 | + |
| 60 | +# Set the suffixes for directories, depending on how we want to include |
| 61 | +# sources and headers for different courses. If the suffix variables remain |
| 62 | +# empty, the GLOB_RECURSE will look for files in the directory called `lab_` |
| 63 | +# which does not actually exist, but will not fail. |
| 64 | +if (WITH_LAB_M1) |
| 65 | + set(SUFFIX_LAB_M1 "m1") |
| 66 | +endif() |
| 67 | +if (WITH_LAB_M2) |
| 68 | + set(SUFFIX_LAB_M2 "m2") |
| 69 | +endif() |
| 70 | +if (WITH_LAB_EXTRA) |
| 71 | + set(SUFFIX_LAB_EXTRA "extra") |
| 72 | +endif() |
| 73 | + |
| 74 | + |
| 75 | +# Gather the source files |
| 76 | +file(GLOB_RECURSE GFXF_SOURCES |
| 77 | + ${CMAKE_CURRENT_LIST_DIR}/src/components/*.c* |
| 78 | + ${CMAKE_CURRENT_LIST_DIR}/src/core/*.c* |
| 79 | + ${CMAKE_CURRENT_LIST_DIR}/src/utils/*.c* |
| 80 | + # |
| 81 | + ${CMAKE_CURRENT_LIST_DIR}/src/main.cpp |
| 82 | + # |
| 83 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_M1}/*.c* |
| 84 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_M2}/*.c* |
| 85 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_EXTRA}/*.c* |
| 86 | +) |
| 87 | + |
| 88 | + |
| 89 | +# Gather the header files |
| 90 | +file(GLOB_RECURSE GFXF_HEADERS_PRIVATE |
| 91 | + ${CMAKE_CURRENT_LIST_DIR}/src/components/*.h* |
| 92 | + ${CMAKE_CURRENT_LIST_DIR}/src/core/*.h* |
| 93 | + ${CMAKE_CURRENT_LIST_DIR}/src/utils/*.h* |
| 94 | + # |
| 95 | + ${CMAKE_CURRENT_LIST_DIR}/res/*.glsl |
| 96 | + # |
| 97 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_M1}/*.h* |
| 98 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_M2}/*.h* |
| 99 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_EXTRA}/*.h* |
| 100 | + # |
| 101 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_M1}/*.glsl |
| 102 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_M2}/*.glsl |
| 103 | + ${CMAKE_CURRENT_LIST_DIR}/src/lab_${SUFFIX_LAB_EXTRA}/*.glsl |
| 104 | +) |
| 105 | + |
| 106 | + |
| 107 | +# Gather the include directories |
| 108 | +set(GFXF_INCLUDE_DIRS_PRIVATE |
| 109 | + ${GFXF_ROOT_DIR}/deps/api |
| 110 | + ${CMAKE_CURRENT_LIST_DIR}/src |
| 111 | +) |
| 112 | + |
| 113 | + |
| 114 | +# Add the executable |
| 115 | +custom_add_executable(${target_name} |
| 116 | + ${GFXF_SOURCES} |
| 117 | + ${GFXF_SOURCES_HIDDEN} |
| 118 | + ${GFXF_HEADERS_PRIVATE} |
| 119 | +) |
| 120 | + |
| 121 | + |
| 122 | +# Detect architecture |
| 123 | +if (CMAKE_SIZEOF_VOID_P EQUAL 8) |
| 124 | + if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch") |
| 125 | + set(__cmake_arch arm64) |
| 126 | + else() |
| 127 | + set(__cmake_arch x86_64) |
| 128 | + endif() |
| 129 | +elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) |
| 130 | + if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch") |
| 131 | + set(__cmake_arch armv7) |
| 132 | + else() |
| 133 | + set(__cmake_arch i686) |
| 134 | + endif() |
| 135 | +endif() |
| 136 | + |
| 137 | + |
| 138 | +# Set library suffic |
| 139 | +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") |
| 140 | + set(__cmake_shared_suffix dll) |
| 141 | + set(__cmake_import_suffix lib) |
| 142 | +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") |
| 143 | + set(__cmake_shared_suffix so) |
| 144 | + set(__cmake_import_suffix so) |
| 145 | +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") |
| 146 | + set(__cmake_shared_suffix dylib) |
| 147 | + set(__cmake_import_suffix dylib) |
| 148 | +endif() |
| 149 | + |
| 150 | + |
| 151 | +# Link third-party libraries |
| 152 | +target_link_libraries(${target_name} PRIVATE |
| 153 | + ${OPENGL_LIBRARIES} |
| 154 | +) |
| 155 | + |
| 156 | +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") |
| 157 | + target_link_libraries(${target_name} PRIVATE |
| 158 | + ${GFXF_ROOT_DIR}/deps/prebuilt/GL/${__cmake_arch}/glew32.lib |
| 159 | + ${GFXF_ROOT_DIR}/deps/prebuilt/GLFW/${__cmake_arch}/glfw3dll.lib |
| 160 | + ${GFXF_ROOT_DIR}/deps/prebuilt/assimp/${__cmake_arch}/assimp.lib |
| 161 | + ${GFXF_ROOT_DIR}/deps/prebuilt/spdlog/${__cmake_arch}/spdlog.lib |
| 162 | + ${GFXF_ROOT_DIR}/deps/prebuilt/freetype/${__cmake_arch}/freetype.lib |
| 163 | + ) |
| 164 | +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") |
| 165 | + target_link_libraries(${target_name} PRIVATE |
| 166 | + GLEW |
| 167 | + glfw |
| 168 | + assimp |
| 169 | + spdlog |
| 170 | + freetype |
| 171 | + ) |
| 172 | +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") |
| 173 | + # Fix linking on 10.14+. See https://stackoverflow.com/questions/54068035 |
| 174 | + target_link_directories(${target_name} PRIVATE |
| 175 | + /usr/local/lib |
| 176 | + ) |
| 177 | + |
| 178 | + if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch") |
| 179 | + target_link_directories(${target_name} PRIVATE |
| 180 | + /opt/homebrew/lib |
| 181 | + ) |
| 182 | + endif () |
| 183 | + |
| 184 | + target_link_libraries(${target_name} PRIVATE |
| 185 | + GLEW |
| 186 | + glfw |
| 187 | + assimp |
| 188 | + spdlog |
| 189 | + freetype |
| 190 | + ) |
| 191 | +endif() |
| 192 | + |
| 193 | +if (USE_DEV_COMPONENTS) |
| 194 | + if (NOT TARGET GFXComponents) |
| 195 | + add_subdirectory(src/components_hidden) |
| 196 | + target_link_libraries(${target_name} PRIVATE GFXComponents) |
| 197 | + endif() |
| 198 | +else() |
| 199 | + target_link_libraries(${target_name} PRIVATE |
| 200 | + ${GFXF_ROOT_DIR}/deps/prebuilt/GFXComponents/${__cmake_arch}/GFXComponents.${__cmake_import_suffix} |
| 201 | + ) |
| 202 | +endif() |
| 203 | + |
| 204 | + |
| 205 | +# Set target properties |
| 206 | +target_include_directories(${target_name} PRIVATE ${GFXF_INCLUDE_DIRS_PRIVATE}) |
| 207 | + |
| 208 | + |
| 209 | +# For Visual Studio, set the working directory and the startup project |
| 210 | +if (MSVC) |
| 211 | + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY VS_STARTUP_PROJECT ${target_name}) |
| 212 | + set_property(TARGET ${target_name} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") |
| 213 | +endif() |
| 214 | + |
| 215 | + |
| 216 | +# Set source file properties |
| 217 | +set_source_files_properties(${GFXF_HEADERS_PRIVATE} PROPERTIES HEADER_FILE_ONLY TRUE) |
| 218 | + |
| 219 | + |
| 220 | +# Group files under logical folders (mainly for IDEs) |
| 221 | +source_group(TREE ${CMAKE_CURRENT_LIST_DIR} FILES |
| 222 | + ${GFXF_SOURCES} |
| 223 | + ${GFXF_SOURCES_HIDDEN} |
| 224 | + ${GFXF_HEADERS_PRIVATE} |
| 225 | +) |
| 226 | + |
| 227 | + |
| 228 | +# Add definitions (specific to this project) |
| 229 | +# Recommended reading: so@a/24470998/5922876, so@a/11437693/5922876 |
| 230 | +set(GFXF_CXX_DEFS LIBGFXC_EXPORTS GLM_FORCE_SILENT_WARNINGS _CRT_SECURE_NO_WARNINGS SOLVED $<$<CONFIG:Debug>:DEBUG>) |
| 231 | +if (WITH_LAB_M1) |
| 232 | + set(GFXF_CXX_DEFS ${GFXF_CXX_DEFS} WITH_LAB_M1) |
| 233 | +endif() |
| 234 | +if (WITH_LAB_M2) |
| 235 | + set(GFXF_CXX_DEFS ${GFXF_CXX_DEFS} WITH_LAB_M2) |
| 236 | +endif() |
| 237 | +if (WITH_LAB_EXTRA) |
| 238 | + set(GFXF_CXX_DEFS ${GFXF_CXX_DEFS} WITH_LAB_EXTRA) |
| 239 | +endif() |
| 240 | +target_compile_definitions(${target_name} PRIVATE ${GFXF_CXX_DEFS}) |
| 241 | + |
| 242 | + |
| 243 | +# Add compile options (specific to this project) |
| 244 | +# Recommended reading: so@a/23995391/5922876 |
| 245 | +if (MSVC) |
| 246 | + set(GFXF_CXX_FLAGS /W4 /WX-) |
| 247 | + # TODO(developer): Maybe address these warnings, see discussion below. |
| 248 | + set(GFXF_CXX_FLAGS ${GFXF_CXX_FLAGS} /wd4100 /wd4458 /wd4189) |
| 249 | +else() |
| 250 | + set(GFXF_CXX_FLAGS -Wall -Wextra -pedantic -Wno-error) |
| 251 | + # TODO(developer): Addressing these warnings might make the source code |
| 252 | + # more convoluted, since they are generated by missing code that needs |
| 253 | + # to be implemented. Some of the warnings are caused by dependencies. |
| 254 | + if (CMAKE_C_COMPILER_ID MATCHES "GNU") |
| 255 | + set(GFXF_CXX_FLAGS ${GFXF_CXX_FLAGS} -Wno-unused-parameter -Wno-unused-variable |
| 256 | + -Wno-unused-but-set-variable |
| 257 | + -Wno-missing-field-initializers -Wno-sign-compare) |
| 258 | + elseif (CMAKE_C_COMPILER_ID MATCHES "Clang") |
| 259 | + set(GFXF_CXX_FLAGS ${GFXF_CXX_FLAGS} -Wno-unused-parameter -Wno-unused-variable |
| 260 | + -Wno-missing-field-initializers -Wno-sign-compare |
| 261 | + # Apple clang |
| 262 | + -Wno-unknown-warning-option |
| 263 | + # Windows clang |
| 264 | + -Wno-microsoft-enum-value -Wno-language-extension-token) |
| 265 | + endif() |
| 266 | +endif() |
| 267 | +target_compile_options(${target_name} PRIVATE ${GFXF_CXX_FLAGS}) |
| 268 | + |
| 269 | + |
| 270 | +# Post-build events. First, we get the directory where the target was |
| 271 | +# just built. We will then copy several files and create several symlinks |
| 272 | +# into the target's parent directory. |
| 273 | +get_target_property(__target_dir ${target_name} RUNTIME_OUTPUT_DIRECTORY) |
| 274 | + |
| 275 | +# On Windows, we copy required binary files next to the target. |
| 276 | +if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") |
| 277 | + add_custom_command(TARGET ${target_name} POST_BUILD |
| 278 | + COMMAND ${CMAKE_COMMAND} -E copy_if_different |
| 279 | + "${GFXF_ROOT_DIR}/deps/prebuilt/GL/${__cmake_arch}/glew32.dll" |
| 280 | + "${GFXF_ROOT_DIR}/deps/prebuilt/GLFW/${__cmake_arch}/glfw3.dll" |
| 281 | + "${GFXF_ROOT_DIR}/deps/prebuilt/assimp/${__cmake_arch}/assimp.dll" |
| 282 | + "${GFXF_ROOT_DIR}/deps/prebuilt/spdlog/${__cmake_arch}/spdlog.dll" |
| 283 | + "${GFXF_ROOT_DIR}/deps/prebuilt/freetype/${__cmake_arch}/freetype.dll" |
| 284 | + |
| 285 | + # Destination directory |
| 286 | + "${__target_dir}" |
| 287 | + ) |
| 288 | +endif() |
| 289 | + |
| 290 | +# This bit is necessary to allow building via Clang on Windows |
| 291 | +if (NOT MSVC) |
| 292 | + set(__error_sink || rem) |
| 293 | +endif() |
| 294 | + |
| 295 | +# We create symbolic links of several directories next to the target. |
| 296 | +# Note for developers: a much more elegant solution would be to use |
| 297 | +# `cmake -E rm` and `cmake -E create_symlink` and avoid using OS-specific |
| 298 | +# commands. Unfortunately, `create_symlink` will fail if the user is not |
| 299 | +# an administrator of the device, as it uses `mklink /D` under the hood. |
| 300 | +foreach (dir IN ITEMS "src" "assets") |
| 301 | + if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") |
| 302 | + string(REPLACE "/" "\\" __target_dir "${__target_dir}") |
| 303 | + string(REPLACE "/" "\\" GFXF_ROOT_DIR "${GFXF_ROOT_DIR}") |
| 304 | + |
| 305 | + add_custom_command(TARGET ${target_name} POST_BUILD |
| 306 | + COMMAND rmdir /S /Q "${__target_dir}\\${dir}" ${__error_sink} |
| 307 | + COMMAND mklink /J "${__target_dir}\\${dir}" "${GFXF_ROOT_DIR}\\${dir}" ${__error_sink} |
| 308 | + ) |
| 309 | + else() |
| 310 | + add_custom_command(TARGET ${target_name} POST_BUILD |
| 311 | + COMMAND rm -rf "${__target_dir}/${dir}" |
| 312 | + COMMAND ln -s "${GFXF_ROOT_DIR}/${dir}" "${__target_dir}/${dir}" |
| 313 | + ) |
| 314 | + endif() |
| 315 | +endforeach() |
| 316 | + |
| 317 | +# For builds that are supplied with closed-source modules, |
| 318 | +# we copy those modules next to the target. If you already |
| 319 | +# have access to the original source code, there's no need |
| 320 | +# for this step. |
| 321 | +if (NOT USE_DEV_COMPONENTS) |
| 322 | + add_custom_command(TARGET ${target_name} POST_BUILD |
| 323 | + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${GFXF_ROOT_DIR}/deps/prebuilt/GFXComponents/${__cmake_arch}/GFXComponents.${__cmake_shared_suffix}" "${__target_dir}" |
| 324 | + ) |
| 325 | +endif() |
0 commit comments