|
| 1 | +--- |
| 2 | +date: 2023-09-09T03:11:08.658Z |
| 3 | +categories: |
| 4 | + - GameDev |
| 5 | + - C++ |
| 6 | + - CMake |
| 7 | + - CPM |
| 8 | + - SDL3 |
| 9 | + - SDL2 |
| 10 | + - CLion |
| 11 | +authors: |
| 12 | + - tolstenko |
| 13 | +--- |
| 14 | + |
| 15 | +# Setup SDL with CMake and CPM |
| 16 | + |
| 17 | +In my opinion, the minimum toolset needed to give you the hability to start creating games cross-platform from scratch is the combination of the following tools: |
| 18 | + |
| 19 | +1. [CLion](https://www.jetbrains.com/clion/) - Cross-platform C++ IDE with embedded CMake support |
| 20 | + |
| 21 | + - [Apply for a student license](https://www.jetbrains.com/community/education); |
| 22 | + - [Download](https://www.jetbrains.com/clion/download) and install it; |
| 23 | + - For Macs, you will need extra tools: `XCode` and the command line tools. You can install them by running `xcode-select --install` on the terminal; |
| 24 | + |
| 25 | +2. (Required for Windows) [Git](https://git-scm.com/) - Version control system |
| 26 | + |
| 27 | + - [Download](https://git-scm.com/downloads) only if you are on Windows and add don't forget to tick the option to add it to your environment path (CMake will be calling it). On Mac and Linux, you can install via your package manager (ex. brew on Mac e apt on Ubuntu). |
| 28 | + |
| 29 | +3. (Optional but desirable) [GitKraken](https://www.gitkraken.com/) - Git GUI |
| 30 | + |
| 31 | + - [Apply for a student license through GitHub Student Pack](https://education.github.com/pack) |
| 32 | + - [Login into GitKraken via social login with your GitHub account](https://www.gitkraken.com/github-student-developer-pack-bundle) |
| 33 | + |
| 34 | +After installing the tools above, you can follow the steps below to create a new project: |
| 35 | + |
| 36 | +## CLion project |
| 37 | + |
| 38 | +1. Open CLion and select `New Project`: |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +2. Create a new project and select `C++ Executable` and `C++XX` as the language standard. Use the default compiler and toolchain: |
| 43 | + |
| 44 | + |
| 45 | + |
| 46 | +3. Start coding: |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | +You might note the existence of a `CMakeLists.txt` file on the left side of the IDE on the `Project` tab. This file is used by CMake to generate the build files for your project. Now we are going it to set up everything you need to use `SDL3`. If you open the `CMakeLists.txt` file, you will see something similar to the following: |
| 51 | + |
| 52 | +```cmake |
| 53 | +# cmake_minimum_required(VERSION <specify CMake version here>) |
| 54 | +cmake_minimum_required(VERSION 3.26) |
| 55 | +# project(<name> [<language-name>...]) |
| 56 | +project(MyGame) |
| 57 | +# set(CMAKE_CXX_STANDARD <specify C++ standard here>) |
| 58 | +set(CMAKE_CXX_STANDARD 17) |
| 59 | +# add_executable(<name> file.cpp file2.cpp ...) |
| 60 | +add_executable(MyGame main.cpp) |
| 61 | +``` |
| 62 | + |
| 63 | +## CPM - C++ Package Manager |
| 64 | + |
| 65 | +CPM is a setup-free C++ package manager. It is a single CMake script that you can add to your project and use it to download and install packages from GitHub. It is a great tool to manage dependencies and it is used by many C++ projects. |
| 66 | + |
| 67 | +You can make this as simple as adding the following lines to your `CMakeLists.txt` file (after the `project` command): |
| 68 | + |
| 69 | +```cmake |
| 70 | +set(CPM_DOWNLOAD_VERSION 0.38.2) |
| 71 | +
|
| 72 | +if(CPM_SOURCE_CACHE) |
| 73 | + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") |
| 74 | +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) |
| 75 | + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") |
| 76 | +else() |
| 77 | + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") |
| 78 | +endif() |
| 79 | +
|
| 80 | +# Expand relative path. This is important if the provided path contains a tilde (~) |
| 81 | +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) |
| 82 | +
|
| 83 | +function(download_cpm) |
| 84 | + message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") |
| 85 | + file(DOWNLOAD |
| 86 | + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake |
| 87 | + ${CPM_DOWNLOAD_LOCATION} |
| 88 | + ) |
| 89 | +endfunction() |
| 90 | +
|
| 91 | +if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION})) |
| 92 | + download_cpm() |
| 93 | +else() |
| 94 | + # resume download if it previously failed |
| 95 | + file(READ ${CPM_DOWNLOAD_LOCATION} check) |
| 96 | + if("${check}" STREQUAL "") |
| 97 | + download_cpm() |
| 98 | + endif() |
| 99 | + unset(check) |
| 100 | +endif() |
| 101 | +
|
| 102 | +include(${CPM_DOWNLOAD_LOCATION}) |
| 103 | +``` |
| 104 | + |
| 105 | +This will download the `CPM.cmake` file to your project and you can use it to download and install packages from GitHub. |
| 106 | + |
| 107 | +In order to checx if `CPM` is being automatically downloaded, you can go to `CLion` and click on `CMake` :simple-cmake: icon the left side of the `Project`, it is the first one on the bottom. And then click the `Reload CMake Project` :material-reload: button: |
| 108 | + |
| 109 | + |
| 110 | + |
| 111 | +Now that you have `CPM`, you can start adding packages to your project. Here goes some ways of doing that: |
| 112 | + |
| 113 | +```cmake |
| 114 | +# A git package from a given uri with a version |
| 115 | +CPMAddPackage("uri@version") |
| 116 | +# A git package from a given uri with a git tag or commit hash |
| 117 | +CPMAddPackage("uri#tag") |
| 118 | +# A git package with both version and tag provided |
| 119 | +CPMAddPackage("uri@version#tag") |
| 120 | +# examples: |
| 121 | +# CPMAddPackage("gh:fmtlib/fmt#7.1.3") |
| 122 | +# CPMAddPackage("gh:nlohmann/json@3.10.5") |
| 123 | +# CPMAddPackage("gh:catchorg/Catch2@3.2.1") |
| 124 | +# An archive package from a given url. The version is inferred |
| 125 | +# CPMAddPackage("https://example.com/my-package-1.2.3.zip") |
| 126 | +# An archive package from a given url with an MD5 hash provided |
| 127 | +# CPMAddPackage("https://example.com/my-package-1.2.3.zip#MD5=68e20f674a48be38d60e129f600faf7d") |
| 128 | +# An archive package from a given url. The version is explicitly given |
| 129 | +# CPMAddPackage("https://example.com/my-package.zip@1.2.3") |
| 130 | +
|
| 131 | +# A complex package with options: |
| 132 | +CPMAddPackage( |
| 133 | + NAME # The unique name of the dependency (should be the exported target's name) |
| 134 | + VERSION # The minimum version of the dependency (optional, defaults to 0) |
| 135 | + OPTIONS # Configuration options passed to the dependency (optional) |
| 136 | + DOWNLOAD_ONLY # If set, the project is downloaded, but not configured (optional) |
| 137 | + GITHUB_REPOSITORY # The GitHub repository (owner/repo) to download from (optional) |
| 138 | + GIT_TAG # The git tag or commit hash to download (optional) |
| 139 | + [...] # Origin parameters forwarded to FetchContent_Declare |
| 140 | +) |
| 141 | +``` |
| 142 | + |
| 143 | +## SDL |
| 144 | + |
| 145 | +Now that we have `CPM` set up, we can use it to download and install `SDL`. If you want to try the stable version `v2`, add the following lines to your `CMakeLists.txt` file and refresh CMake: |
| 146 | + |
| 147 | +```cmake |
| 148 | +CPMAddPackage( |
| 149 | + NAME SDL2 |
| 150 | + GITHUB_REPOSITORY libsdl-org/SDL |
| 151 | + GIT_TAG release-2.28.3 |
| 152 | + VERSION 2.28.3 |
| 153 | +) |
| 154 | +``` |
| 155 | + |
| 156 | +If you don't have `git` installed on your machine, you might want to use the `ZIP` version(it is even faster to download, but slower to switch versions). In this case, you can use the following lines and refresh CMake: |
| 157 | + |
| 158 | +```cmake |
| 159 | +CPMAddPackage( |
| 160 | + NAME SDL2 |
| 161 | + URL "https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.28.3.zip" |
| 162 | + VERSION 2.28.3 |
| 163 | +) |
| 164 | +``` |
| 165 | + |
| 166 | +If you want to try the bleeding edge version `v3`, add the following lines to your `CMakeLists.txt` file at your own risk: |
| 167 | + |
| 168 | +```cmake |
| 169 | +CPMAddPackage( |
| 170 | + NAME SDL3 |
| 171 | + GITHUB_REPOSITORY libsdl-org/SDL |
| 172 | + GIT_TAG main |
| 173 | +) |
| 174 | +``` |
| 175 | + |
| 176 | +Now that we have `SDL` set up, we should link it to our project. In order to do that, we can add the following lines after the line `add_executable` to our `CMakeLists.txt` file and refresh CMake: |
| 177 | + |
| 178 | +```cmake |
| 179 | +target_link_libraries(MyGame SDL2::SDL2) |
| 180 | +# change SDL2 to SDL3 if you are using the bleeding edge version |
| 181 | +#target_link_libraries(MyGame SDL2::SDL2) |
| 182 | +``` |
| 183 | + |
| 184 | +And this will make `SDL` available to our project. Now we can start coding. Let's create a simple window: |
| 185 | + |
| 186 | +```cpp |
| 187 | +#include <SDL.h> |
| 188 | + |
| 189 | +int main(int argc, char** argv) { |
| 190 | + SDL_Init(SDL_INIT_VIDEO); |
| 191 | + |
| 192 | + SDL_Window* window = SDL_CreateWindow( |
| 193 | + "SDL2Test", |
| 194 | + SDL_WINDOWPOS_UNDEFINED, |
| 195 | + SDL_WINDOWPOS_UNDEFINED, |
| 196 | + 640, |
| 197 | + 480, |
| 198 | + 0 |
| 199 | + ); |
| 200 | + |
| 201 | + SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); |
| 202 | + |
| 203 | + SDL_Event e; |
| 204 | + bool quit = false; |
| 205 | + while (!quit){ |
| 206 | + while (SDL_PollEvent(&e)){ |
| 207 | + if (e.type == SDL_QUIT){ |
| 208 | + quit = true; |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); |
| 213 | + SDL_RenderClear(renderer); |
| 214 | + SDL_RenderPresent(renderer); |
| 215 | + SDL_Delay(0); |
| 216 | + } |
| 217 | + |
| 218 | + SDL_DestroyWindow(window); |
| 219 | + SDL_Quit(); |
| 220 | + |
| 221 | + return 0; |
| 222 | +} |
| 223 | +``` |
| 224 | +
|
| 225 | +If you feel that you want to test the bleeding-edge version, you can use this code instead: |
| 226 | +
|
| 227 | +```cpp |
| 228 | +#include <SDL.h> |
| 229 | +
|
| 230 | +int main(int argc, char* argv[]) { |
| 231 | + SDL_Init(SDL_INIT_VIDEO); |
| 232 | +
|
| 233 | + SDL_Window *window = SDL_CreateWindow( |
| 234 | + "MyGame", |
| 235 | + 640, |
| 236 | + 480, |
| 237 | + 0 |
| 238 | + ); |
| 239 | +
|
| 240 | + SDL_Renderer* renderer = SDL_CreateRenderer(window, nullptr, SDL_RENDERER_ACCELERATED); |
| 241 | + SDL_Event e; |
| 242 | + bool quit = false; |
| 243 | +
|
| 244 | + while (!quit) { |
| 245 | + while (SDL_PollEvent(&e)) { |
| 246 | + if (e.type == SDL_EVENT_QUIT) { |
| 247 | + quit = true; |
| 248 | + } |
| 249 | + } |
| 250 | + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); |
| 251 | + SDL_RenderClear(renderer); |
| 252 | + SDL_RenderPresent(renderer); |
| 253 | + SDL_Delay(0); |
| 254 | + } |
| 255 | +
|
| 256 | + SDL_DestroyWindow(window); |
| 257 | + SDL_Quit(); |
| 258 | + |
| 259 | + return 0; |
| 260 | +} |
| 261 | +``` |
| 262 | + |
| 263 | +Now you have a way to code games with `SDL` in a way that is cross-platform, and easy to setup. |
| 264 | + |
| 265 | +If you hit `Run` or `Debug` on `CLion`, you will see a window like this: |
| 266 | + |
| 267 | + |
| 268 | + |
| 269 | +and then: |
| 270 | + |
| 271 | + |
| 272 | + |
| 273 | +I hope it works for you. If you have any problems, please let me know on Discord or via GitHub issues. |
0 commit comments