├── .github └── workflows │ ├── macOS.yml │ ├── ubuntu.yml │ └── windows.yml ├── .gitignore ├── .gitmodules ├── LICENCE ├── Makefile ├── README.md ├── docs ├── InstallingDependencies.md └── MakefileExplanation.md └── src └── main.cpp /.github/workflows/macOS.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | pull_request: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build: 12 | runs-on: macos-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: make setup 17 | run: make setup 18 | 19 | - name: make bin/app 20 | run: make bin/app 21 | 22 | - name: export binary 23 | uses: actions/upload-artifact@v4 24 | with: 25 | name: app 26 | path: bin/app 27 | 28 | - name: make clean 29 | run: make clean 30 | 31 | - name: make bin/app CXX=g++ 32 | run: make bin/app CXX=g++ 33 | 34 | - name: make clean 35 | run: make clean 36 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | pull_request: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: update apt 17 | run: sudo apt-get update 18 | 19 | - name: install raylib dependencies 20 | run: sudo apt install libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev 21 | 22 | - name: make setup 23 | run: make setup 24 | 25 | - name: make bin/app 26 | run: make bin/app 27 | 28 | - name: 'export binary' 29 | uses: actions/upload-artifact@v4 30 | with: 31 | name: app 32 | path: bin/app 33 | 34 | - name: make clean 35 | run: make clean 36 | 37 | - name: make bin/app CXX=g++ 38 | run: make bin/app CXX=g++ 39 | 40 | - name: make clean 41 | run: make clean 42 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | pull_request: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build: 12 | runs-on: windows-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: make setup 17 | run: mingw32-make setup 18 | shell: cmd 19 | 20 | - name: make bin/app 21 | run: mingw32-make bin/app 22 | shell: cmd 23 | 24 | - name: export binary 25 | uses: actions/upload-artifact@v4 26 | with: 27 | name: app.exe 28 | path: bin/app.exe 29 | 30 | - name: make clean 31 | run: mingw32-make clean 32 | shell: cmd 33 | 34 | - name: make bin/app CXX=g++ 35 | run: mingw32-make bin/app CXX=g++ 36 | shell: cmd 37 | 38 | - name: make clean 39 | run: mingw32-make clean 40 | shell: cmd 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | include 2 | lib 3 | bin 4 | .idea 5 | .DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/raylib-cpp"] 2 | path = vendor/raylib-cpp 3 | url = https://github.com/robloach/raylib-cpp 4 | [submodule "vendor/raylib"] 5 | path = vendor/raylib 6 | url = https://github.com/raysan5/raylib 7 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-present Caps Collective & contributors 2 | Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) 3 | 4 | This software is provided "as-is", without any express or implied warranty. In no event 5 | will the authors be held liable for any damages arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, including commercial 8 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 9 | 10 | 1. The origin of this software must not be misrepresented; you must not claim that you 11 | wrote the original software. If you use this software in a product, an acknowledgment 12 | in the product documentation would be appreciated but is not required. 13 | 14 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 15 | as being the original software. 16 | 17 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020-present Caps Collective & contributors 2 | # Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) 3 | # 4 | # This code is released under an unmodified zlib license. 5 | # For conditions of distribution and use, please see: 6 | # https://opensource.org/licenses/Zlib 7 | 8 | # Define custom functions 9 | rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) 10 | platformpth = $(subst /,$(PATHSEP),$1) 11 | 12 | # Set global macros 13 | buildDir := bin 14 | executable := app 15 | target := $(buildDir)/$(executable) 16 | sources := $(call rwildcard,src/,*.cpp) 17 | objects := $(patsubst src/%, $(buildDir)/%, $(patsubst %.cpp, %.o, $(sources))) 18 | depends := $(patsubst %.o, %.d, $(objects)) 19 | compileFlags := -std=c++17 -I include 20 | linkFlags = -L lib/$(platform) -l raylib 21 | 22 | # Check for Windows 23 | ifeq ($(OS), Windows_NT) 24 | # Set Windows macros 25 | platform := Windows 26 | CXX ?= g++ 27 | linkFlags += -Wl,--allow-multiple-definition -pthread -lopengl32 -lgdi32 -lwinmm -static -static-libgcc -static-libstdc++ 28 | THEN := && 29 | PATHSEP := \$(BLANK) 30 | MKDIR := -mkdir -p 31 | RM := -del /q 32 | COPY = -robocopy "$(call platformpth,$1)" "$(call platformpth,$2)" $3 33 | else 34 | # Check for MacOS/Linux 35 | UNAMEOS := $(shell uname) 36 | ifeq ($(UNAMEOS), Linux) 37 | # Set Linux macros 38 | platform := Linux 39 | CXX ?= g++ 40 | linkFlags += -l GL -l m -l pthread -l dl -l rt -l X11 41 | endif 42 | ifeq ($(UNAMEOS), Darwin) 43 | # Set macOS macros 44 | platform := macOS 45 | CXX ?= clang++ 46 | linkFlags += -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL 47 | endif 48 | 49 | # Set UNIX macros 50 | THEN := ; 51 | PATHSEP := / 52 | MKDIR := mkdir -p 53 | RM := rm -rf 54 | COPY = cp $1$(PATHSEP)$3 $2 55 | endif 56 | 57 | # Lists phony targets for Makefile 58 | .PHONY: all setup submodules execute clean 59 | 60 | # Default target, compiles, executes and cleans 61 | all: $(target) execute clean 62 | 63 | # Sets up the project for compiling, generates includes and libs 64 | setup: include lib 65 | 66 | # Pull and update the the build submodules 67 | submodules: 68 | git submodule update --init --recursive --depth 1 69 | 70 | # Copy the relevant header files into includes 71 | include: submodules 72 | $(MKDIR) $(call platformpth, ./include) 73 | $(call COPY,vendor/raylib/src,./include,raylib.h) 74 | $(call COPY,vendor/raylib/src,./include,raymath.h) 75 | $(call COPY,vendor/raylib-cpp/include,./include,*.hpp) 76 | 77 | # Build the raylib static library file and copy it into lib 78 | lib: submodules 79 | cd vendor/raylib/src $(THEN) "$(MAKE)" PLATFORM=PLATFORM_DESKTOP 80 | $(MKDIR) $(call platformpth, lib/$(platform)) 81 | $(call COPY,vendor/raylib/src,lib/$(platform),libraylib.a) 82 | 83 | # Link the program and create the executable 84 | $(target): $(objects) 85 | $(CXX) $(objects) -o $(target) $(linkFlags) 86 | 87 | # Add all rules from dependency files 88 | -include $(depends) 89 | 90 | # Compile objects to the build directory 91 | $(buildDir)/%.o: src/%.cpp Makefile 92 | $(MKDIR) $(call platformpth, $(@D)) 93 | $(CXX) -MMD -MP -c $(compileFlags) $< -o $@ $(CXXFLAGS) 94 | 95 | # Run the executable 96 | execute: 97 | $(target) $(ARGS) 98 | 99 | # Clean up all relevant files 100 | clean: 101 | $(RM) $(call platformpth, $(buildDir)/*) 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raylib C++ Starter 2 | The Raylib C++ Starter kit is a template project that provides a simple starter template for the [raylib](https://github.com/raysan5/raylib) game tools library incorporating the [raylib-cpp](https://github.com/robloach/raylib-cpp) C++ bindings and using [Make](https://www.gnu.org/software/make/) for building. The starter kit can automatcially clone down raylib and the bindings, compile them, and setup the project for separate compilation using a static library. 3 | 4 | > Why static linking? 5 | 6 | One of the most absurdly annoying things about C++ development is finding and linking dynamic libraries. The raylib project prides itself on having **"NO external dependencies"**, and we tend to agree that portability is way cooler than saving that fraction of a second on compile-time. 7 | 8 | > Why not just use CMake? 9 | 10 | I guess we just don't want the added headache. CMake is complex and sometimes feels like some *arcane magic* that we generally take for granted in build systems. If you look at the raylib library, yes it has CMake support, but it generally encourages the use of Make on all platforms because as the library reads: 11 | 12 | > raylib is a programming library to enjoy videogames programming; no fancy interface, no visual helpers, no auto-debugging... just coding in the most pure spartan-programmers way 13 | 14 | So that being said, we hope that this repository finds you well and wholeheartedly enjoying the *simple things in life* (i.e. video games programming). 15 | 16 | ### Current Compatibility 17 | | OS | Default Compiler | Last Manual Build | Compile Status | 18 | | ----------- | ---------------- | ------------------- | ---------------------------------------------------- | 19 | | **macOS** | Clang++ | `Big Sur 11.0.1` | ![macOS Status](../../workflows/macOS/badge.svg) | 20 | | **Linux** | G++ | `Ubuntu 20.04 LTS` | ![Linux Status](../../workflows/Ubuntu/badge.svg) | 21 | | **Windows** | MinGW (G++) | `Windows 10 19041` | ![Windows Status](../../workflows/Windows/badge.svg) | 22 | 23 | ## Getting Started 24 | 25 | ### Installing Dependencies 26 | 27 | Before building the project, you will need to install all relevant dependencies for your platform so that the project has access to all the tools required, and raylib can compile and link correctly. You can find intructions for installing dependencies on macOS, Linux, and Windows in the [docs file on installing dependencies](docs/InstallingDependencies.md). 28 | 29 | ### Building the Project 30 | Once you have cloned this repository and installed dependencies, building the project is as simple as running these two commands in its root directory: 31 | 32 | #### macOS & Linux 33 | ```console 34 | $ make setup 35 | $ make 36 | ``` 37 | 38 | #### Windows 39 | ```console 40 | > mingw32-make setup 41 | > mingw32-make 42 | ``` 43 | 44 | The first command will clone in the lastest C++ bindings and targeted version of raylib, copy across any relevant header files into `/includes`, and build a static library file from them, placing it in `/lib`. The second command then compiles, runs and cleans up your project using the source code in `/src/main.cpp`. 45 | 46 | *If a window pops up, congratulations, you've successfully built the project and you can now start programming your game!* 47 | 48 | ## Using This Template 49 | Now that you have the project setup and compiling on your system, it's time to start programming! If you aren't already familliar with [raylib](https://github.com/raysan5/raylib), we recommend looking over [this awesome cheatsheet](https://www.raylib.com/cheatsheet/cheatsheet.html) which lists every function, struct and macro available in the raylib C library. If you want specifics on how to use the C++ bindings, then you should check out the [raylib-cpp](https://github.com/robloach/raylib-cpp) repo, which nicely explains how the bindings work and contains [raylib's examples ported to C++](https://github.com/RobLoach/raylib-cpp/tree/master/examples). 50 | 51 | Once you're up and running, we first of all recommend that all your code for the game should go into the `/src` directory, which is automatically included in the compile process when you run Make. The default entry point for the program is `/src/main.cpp` (which is pretty standard). If you wish to change the program entry point, add more libraries, or really anything about your project, all build instructions are specified in the [`Makefile`](Makefile) - no smoke and mirrors! 52 | 53 | ### Making Use of Separate Compilation 54 | When building compiled applications from scratch, *each* source file needs to be compiled into an object file in order for them all to be linked together as a full program. This can become rather time-consuming and inefficient as your codebase expands to use tens or even hundreds of files that recompile each time you build. Fortunately, with a few clever rules in our [`Makefile`](Makefile), we can be sure to only have to recompile files affected by our changes. 55 | 56 | By using the following Make commands instead of the default target, we can skip the cleanup step, and only recompile files that changed: 57 | 58 | #### macOS & Linux 59 | 60 | ```console 61 | $ make bin/app; make execute 62 | ``` 63 | 64 | #### Windows 65 | 66 | ```console 67 | > mingw32-make bin/app && mingw32-make execute 68 | ``` 69 | 70 | Using this method can save you a huge amount of time compiling *(in reality, just a few seconds)* each time you make a small change to your code! If you want to know more about how it works, you should have a read through [the docs entry explaining the Makefile](docs/MakefileExplanation.md). 71 | 72 | While separate compilation works quite well in most scenarios, it's not magic, and there are a few caveats to take note of here: 73 | 74 | 1. Changing `.h` files will often result in longer compile times by causing all files that include them to recompile 75 | 2. Constant changes to files included by many others in your program (like a base-class) will also cause all of those dependent to recompile 76 | 3. Including widely-scoped files (like the whole of `raylib-cpp.hpp`) will add all of its own includes as dependent and increase the build time 77 | 4. Placing includes in `.h` files instead of forward-declarations will also increase recursive includes and therefore the build time 78 | 79 | ### Passing Args to the Executable 80 | For working with some projects, you may want to pass arguments to the program once it's been built. This can be achieved by assigning values to the `ARGS` flag in the Makefile like below: 81 | 82 | #### macOS & Linux 83 | 84 | ```console 85 | $ make ARGS="--somearg" 86 | ``` 87 | 88 | #### Windows 89 | 90 | ```console 91 | > mingw32-make ARGS="--somearg" 92 | ``` 93 | 94 | ### Specifying Custom Macro Definitions 95 | You may also want to pass in your own macro definitions for certain configurations (such as setting log levels). You can pass in your definitions using `CXXFLAGS`: 96 | 97 | #### macOS & Linux 98 | 99 | ```console 100 | $ make CXXFLAGS=-DMY_MACRO=1 101 | ``` 102 | 103 | #### Windows 104 | 105 | ```console 106 | > mingw32-make CXXFLAGS=-DMY_MACRO=1 107 | ``` 108 | 109 | ### Specifying a Non-Default Compiler 110 | If you want to use a compiler for your platform that isn't the default for your system (or potentially you would like to explicitly state it), you can make use of the system-implicit `CXX` variable like so: 111 | 112 | #### macOS & Linux 113 | 114 | ```console 115 | $ make CXX=g++ 116 | ``` 117 | 118 | #### Windows 119 | 120 | ```console 121 | > mingw32-make CXX=g++ 122 | ``` 123 | 124 | ## Contributing 125 | 126 | ### How do I contribute? 127 | It's pretty simple actually: 128 | 129 | 1. Fork it from [here](https://github.com/CapsCollective/raylib-cpp-starter/fork) 130 | 2. Create your feature branch (`git checkout -b cool-new-feature`) 131 | 3. Commit your changes (`git commit -m "Added some feature"`) 132 | 4. Push to the branch (`git push origin cool-new-feature`) 133 | 5. Create a new pull request for it! 134 | 135 | ### Contributors 136 | - [jonjondev](https://github.com/jonjondev) Jonathan Moallem - co-creator, maintainer 137 | - [Raelr](https://github.com/Raelr) Aryeh Zinn - co-creator, maintainer 138 | - [mTvare6](https://github.com/mTvare6) mTvare6 - contributor 139 | - [rafaeldelboni](https://github.com/rafaeldelboni) Rafael Delboni - contributor 140 | - [jason-cannon](https://github.com/jason-cannon) Jason Cannon - contributor 141 | - [return215](https://github.com/return215) Muhammad Hidayat - contributor 142 | - [Samuel Asher Rivello](https://github.com/SamuelAsherRivello) - contributor 143 | 144 | 145 | ## Licence 146 | 147 | This project is licenced under an unmodified zlib/libpng licence, which is an OSI-certified, BSD-like licence that allows static linking with closed source software. Check [`LICENCE`](LICENCE) for further details. 148 | -------------------------------------------------------------------------------- /docs/InstallingDependencies.md: -------------------------------------------------------------------------------- 1 | # Installing Dependencies 2 | 3 | ## macOS 4 | 5 | ### Installing Apple Developer Tools 6 | To do anything of value in the later versions of macOS, you're going to need the Xcode developer tools. Fortunately, if you want to skip downloading the behemoth of an IDE, then you can just get the command line tools package with the following command: 7 | ```console 8 | $ xcode-select --install 9 | ``` 10 | 11 | After installing the package, you should have Git (among other things) installed. You can verify this by running: 12 | ```console 13 | $ git --version 14 | git version 2.27.0 15 | ``` 16 | 17 | ## Linux 18 | 19 | ### Installing Git 20 | For the project build system to function correctly, you will need to have Git installed on your system if it isn't already (it's a good idea to have it anyway - take it from us). You can install it by running the following lines: 21 | 22 | #### Debian/Ubuntu 23 | ```console 24 | $ sudo apt update 25 | $ sudo apt install git-all 26 | ``` 27 | 28 | #### Fedora 29 | ```console 30 | $ sudo dnf check-update 31 | $ sudo dnf install git-all 32 | ``` 33 | 34 | ### Installing G++ & Make 35 | Some Linux distributions do not come preinstalled with the basic build tools required to do C/C++ development. In the case that you do not have them and you're on a Debian-based system, you can install them all with one very handy meta-package aptly named `build-essential`. Otherwise if you're using Fedora, you can install them each individually. Run the following lines to install them: 36 | 37 | #### Debian/Ubuntu 38 | ```console 39 | $ sudo apt update 40 | $ sudo apt install build-essential 41 | ``` 42 | 43 | #### Fedora 44 | ```console 45 | $ sudo dnf check-update 46 | $ sudo dnf install make automake gcc gcc-c++ kernel-devel 47 | ``` 48 | 49 | After installing the package, you should have both G++ and Make installed. You can verify this by running: 50 | ```console 51 | $ g++ --version 52 | g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 53 | 54 | $ make --version 55 | GNU Make 4.2.1 56 | Built for x86_64-pc-linux-gnu 57 | ``` 58 | 59 | ### Installing ALSA, Mesa & X11 60 | On Linux, raylib is reliant on a number of libraries for audio, graphics, and windowing that may not come preinstalled, these being ALSA, Mesa & X11 respecively. Fortunately they can all be easily installed through your distribution's package manager with just a few lines: 61 | 62 | #### Debian/Ubuntu 63 | ```console 64 | $ sudo apt update 65 | $ sudo apt install libasound2-dev mesa-common-dev libx11-dev libxrandr-dev libxi-dev xorg-dev libgl1-mesa-dev libglu1-mesa-dev 66 | ``` 67 | 68 | #### Fedora 69 | ```console 70 | $ sudo dnf check-update 71 | $ sudo dnf install alsa-lib-devel mesa-libGL-devel libX11-devel libXrandr-devel libXi-devel libXcursor-devel libXinerama-devel 72 | ``` 73 | 74 | ## Windows 75 | 76 | ### Installing Git 77 | For the project build system to function correctly, you will need to have Git installed on your system if it isn't already (it's a good idea to have it anyway - take it from us). You can install it by [downloading it from here](https://git-scm.com/download/win) and going through the setup wizard. 78 | 79 | ### Installing MinGW 80 | Building raylib libraries requires the installation of MinGW ([32](http://www.mingw.org/) and [64](http://mingw-w64.org/doku.php/download) bit versions). Please ensure that you link MinGW's `bin` directory to your system environment variables for BOTH the 32 and 64 bit versions. You can follow the instructions here for the [32-bit](https://www.youtube.com/watch?v=sXW2VLrQ3Bs) and here for the [64-bit](https://code.visualstudio.com/docs/cpp/config-mingw) bit versions. 81 | 82 | After installing MinGW, you should have G++ installed. You can verify this by running: 83 | ```console 84 | > g++ --version 85 | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0 86 | ``` 87 | -------------------------------------------------------------------------------- /docs/MakefileExplanation.md: -------------------------------------------------------------------------------- 1 | # How the Makefile Works 2 | This document attempts to explain how the project's build-system works, as well as general concepts in Makefile. It was created with the intention to help newcomers to C/C++ and Make understand how everything in the project is done, so that they can even dive in and make changes of their own if necessary. The format of the document orders items from top to bottom in general order of appearance throughout [the actual project Makefile](/Makefile). 3 | 4 | ### Contents 5 | - [Macro Definitions](#macro-definitions) 6 | - [Custom Functions](#custom-functions) 7 | - [Global Macros](#global-macros) 8 | - [Platform-Specific Macros](#platform-specific-macros) 9 | - [Targets](#targets) 10 | - [.PHONY](#phony) 11 | - [setup](#setup) 12 | - [all](#all) 13 | 14 | ## Macro Definitions 15 | At the top of the Makefile, macros are defined to be used within the ensuing targets. Macros provide two valuable uses throughout the file: defined values (read variables) that can be used repeatedly throughout the program, and functions that can be called to manipulate certain inputs. The macros in this file are arranged in the following groups, in the following order: custom functions, globals, and platform-specifics. 16 | 17 | ### Custom Functions 18 | There are two custom functions defined for the Makefile, `rwildcard` and `platformpth`, and appear in the file as follows: 19 | 20 | ```Makefile 21 | rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) 22 | platformpth = $(subst /,$(PATHSEP),$1) 23 | ``` 24 | Simply put, `rwildcard` takes a glob pattern and **recursively** searches through the project files and subdirectories, for matching files by pattern. `platformpth` takes a UNIX-style path and formats it for the current platform (e.g. `platformpth(/bin/app)` results in `\bin\app` on Windows). 25 | 26 | ### Global Macros 27 | The "global" macros are platform-agnostic values that are mostly used for defining compiler-related variables as below: 28 | 29 | ```Makefile 30 | buildDir := bin 31 | executable := app 32 | target := $(buildDir)/$(executable) 33 | sources := $(call rwildcard,src/,*.cpp) 34 | objects := $(patsubst src/%, $(buildDir)/%, $(patsubst %.cpp, %.o, $(sources))) 35 | depends := $(patsubst %.o, %.d, $(objects)) 36 | compileFlags := -std=c++17 -I include 37 | linkFlags = -L lib/$(platform) -l raylib 38 | ifdef MACRO_DEFS 39 | macroDefines := -D $(MACRO_DEFS) 40 | endif 41 | ``` 42 | 43 | In this snippet there are two different assignment operators used, `:=` meaning "instant, static assign", and `=` meaning lazy assign, where the macro will only be assigned on use (this is useful when it relies on another macro that may not yet be defined). The operator `?=` is also used in cases where assignment is contingent on the variable being previously undefined. Finally, the `+=` operator is used to append content to a previously defined macro. At the very end, it checks to see if any macros were defined in the `Makefile` declaration and adds them to our compilation steps. 44 | 45 | ### Platform-Specific Macros 46 | The final grouping of macros in the Makefile relate to those that differ on a per-platform basis. The structure uses nested if-statements to first determine whether the current platform is Windows or not to assign macros. If it is not Windows, it then checks whether the current platform is Linux or macOS and assigns macros accordingly. 47 | 48 | ```Makefile 49 | ifeq ($(OS), Windows_NT) 50 | # Set Windows macros 51 | platform := Windows 52 | CXX ?= g++ 53 | linkFlags += -Wl,--allow-multiple-definition -pthread -lopengl32 -lgdi32 -lwinmm -mwindows -static -static-libgcc -static-libstdc++ 54 | THEN := && 55 | PATHSEP := \$(BLANK) 56 | MKDIR := -mkdir -p 57 | RM := -del /q 58 | COPY = -robocopy "$(call platformpth,$1)" "$(call platformpth,$2)" $3 59 | else 60 | # Check for MacOS/Linux 61 | UNAMEOS := $(shell uname) 62 | ifeq ($(UNAMEOS), Linux) 63 | # Set Linux macros 64 | platform := Linux 65 | CXX ?= g++ 66 | linkFlags += -l GL -l m -l pthread -l dl -l rt -l X11 67 | endif 68 | ifeq ($(UNAMEOS), Darwin) 69 | # Set macOS macros 70 | platform := macOS 71 | CXX ?= clang++ 72 | linkFlags += -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL 73 | endif 74 | 75 | # Set UNIX macros 76 | THEN := ; 77 | PATHSEP := / 78 | MKDIR := mkdir -p 79 | RM := rm -rf 80 | COPY = cp $1$(PATHSEP)$3 $2 81 | endif 82 | ``` 83 | 84 | The macros defined above primarily contain platform-specific syntax for common functionality, as well as variables used during the compilation processes on each platform. For example, the `COPY` macro contains a functioning file copy command for each platform so that targets can easily specify a single command (`COPY`) that works on both UNIX and Windows systems. Another example of content pertains to the `linkFlags` macro, in which each platform must specify a series of libraries to link during compilation. 85 | 86 | ## Targets 87 | This section describes most of the Makefile's functionality by explaning of the function of the top level targets, `setup` and `all`, intending to provide a wholistic understanding of the Makefile's processes from top to bottom. 88 | 89 | ### .PHONY 90 | The `.PHONY` target is a special target in the world of Makefile, and is specifically used to note which targets "exist" and which are "phony". A target should theoretically refer to (in dev terms) an actual file or directory requirement of the project's build system (e.g. a static library file to link to the app), and so Make does some useful work in the background to work out whether changes have been made to certain files, running targets of only files that have had their dependencies changed since last run. In a more realistic sense, Make also recognises that not all targets will refer to real world files, and can be exluded from this "run only if new changes" behaviour using the `.PHONY` target. 91 | 92 | ```Makefile 93 | .PHONY: all setup submodules execute clean 94 | ``` 95 | 96 | So as you can see above, the first target of the file lists all the other "phony" targets in the file as dependencies. 97 | 98 | ### setup 99 | The first target we get you to call before building the project is `setup`, which essentially pulls in all raylib and raylib-cpp dependencies, and then formats the project file structure. 100 | 101 | As you can see below, the target simply depends on two sub-targets, `include` and `lib`: 102 | ```Makefile 103 | setup: include lib 104 | ``` 105 | 106 | However, looking at `include`, we can see that it depends on `submodules`, so we'll look at that first. 107 | ```Makefile 108 | include: submodules 109 | ... 110 | ``` 111 | 112 | `submodules` is a very simple target that will update the git submodules in the project recursively, pulling in the current raylib and raylib-cpp repositories as a [shallow clone](https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/) using the `--depth 1` option. You can [read more about git submodules here](https://git-scm.com/book/en/v2/Git-Tools-Submodules). 113 | ```Makefile 114 | submodules: 115 | git submodule update --init --recursive --depth 1 116 | ``` 117 | 118 | Having satisfied `submodules` and now returning to `include`, we can being to run its body (as can be seen below). 119 | 120 | It begins by creating the `/include` directory (converting the directory path for Windows if necessary with the custom `platformpth` function) if it doesn't already exist. 121 | 122 | Next, the target proceeds to call another custom function, `COPY` (a platform agnostic copy command), manually copying `raylib.h` and `raymath.h` from raylib's source code, and all files ending with `.hpp` from raylib-cpp's source code, into the newly created `/include` directory. 123 | ```Makefile 124 | include: submodules 125 | $(MKDIR) $(call platformpth, ./include) 126 | $(call COPY,vendor/raylib/src,./include,raylib.h) 127 | $(call COPY,vendor/raylib/src,./include,raymath.h) 128 | $(call COPY,vendor/raylib-cpp/include,./include,*.hpp) 129 | ``` 130 | 131 | Finally, we move on to `lib`, which also depends on `submodules`, however because submodules has already run, it will not run again. 132 | 133 | Next, we create the `/lib` directory (and a subdirectory for your current platform) if it doesn't already exist using the same method as above. 134 | 135 | Moving on to the body of the target, we move into raylib's `/src` directory and immediately run Make on raylib. Once complete, this results in the creation of a static library file named `libraylib.a` (*which will appear in slightly different directories based on the platform you build it in for whatever reason...*). 136 | 137 | To complete the target, it then copies that library file into the relevant directory for your platform under `/lib`. 138 | ```Makefile 139 | lib: submodules 140 | cd vendor/raylib/src $(THEN) "$(MAKE)" PLATFORM=PLATFORM_DESKTOP 141 | $(MKDIR) $(call platformpth, lib/$(platform)) 142 | $(call COPY,vendor/raylib/src,lib/$(platform),libraylib.a) 143 | ``` 144 | 145 | Once all of these targets have been fulfilled, `setup` ends and your project should now contain a copy of the relevant static library for your platform in `/lib`, and all the necessary header files under `/include`. 146 | 147 | ### all 148 | The target name `all` is used as a common convention as being the default target in any Makefile, and what makes it default is that it's the first target defined (aside from the the reserved target of `.PHONY`). In our case we consider the default behaviour of our build system as compiling, running and then cleaning up the build, avoiding including the steps defined in `setup`. 149 | 150 | The first line of the target simply lists its dependencies in order of execution: the application target (with its name defined by the `target` variable), the `execute` target to run the program, and finally `clean` to tidy up post-build. 151 | ```Makefile 152 | all: $(target) execute clean 153 | ``` 154 | 155 | The application target is first to run, and contains the instruction of compiling the program into the `target` file using the defined `CXX` command on a series of object files and linker flags. However this also contains a number of prerequisites as all object files list in `objects` must exist and be up to date. With this being the case, the Makefile will run the relevant target for each object file. 156 | ```Makefile 157 | $(target): $(objects) 158 | $(CXX) $(objects) -o $(target) $(linkFlags) 159 | ``` 160 | 161 | As such, the target `$(buildDir)/%.o` is responsible for ensuring the creation and update of object files (`.o` files). The target will create all necessary subdirectory structures needed for the files, and then compile each `.cpp` file in the source directory into an object file using a number of rather terse, [automatic variables that you can read up on here](https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html). Finally, it includes any custom macros that we defined for each of these files. 162 | ```Makefile 163 | $(buildDir)/%.o: src/%.cpp Makefile 164 | $(MKDIR) $(call platformpth, $(@D)) 165 | $(CXX) -MMD -MP -c $(compileFlags) $< -o $@ $(macroDefines) 166 | ``` 167 | That all being said, there are still two dependancies for the target, the `.cpp` files, and the Makefile itself. One might wonder why either of these need to be dependencies, given that without them, there would be nothing to compile and no instructions with which to compile it, however there is definitely some intention behind this. Firstly, the aforementioned automatic variables of `$<` and `$@` require a list of dependencies to iterate through, and secondly, we want to make sure everything is up-to-date. For instance, changing a `.cpp` file should trigger this step to run again for that file, or changing the Makefile should warrant a full recompilation. 168 | 169 | This is where things get a little hairy. There is a common scenario where one might change a `.cpp` or `.h` file that is included by another, and as such the changed file will recompile, but none that depend on it. So how can we track this dependency? The answer is by cheating, using the power of the C/C++ compiler. The flags `-MMD` and `-MP` in the compile command tell the compiler to automatically generate a list of file dependency targets for each file as it goes. These files are then output to the `/bin/` directory alongside their matching `.o` files for later reference, containing automatically generated Makefile targets. 170 | 171 | One might ask how these are then read back in and used, well that is done with another piece of Makefile magic: the `include` command, which when added to a Makefile, will import the content of any specified file to its body. The below command is entirely responsible for doing this, and the output of the operation is ignored by prefacing it with a dash. 172 | ```Makefile 173 | -include $(depends) 174 | ``` 175 | Now, finally returning from two levels of indirection in targets, the program can come back to the application target and link the newly generated and updated object files into the program, alongside any raylib and binding components. 176 | ```Makefile 177 | $(target): $(objects) 178 | $(CXX) $(objects) -o $(target) $(linkFlags) 179 | ``` 180 | 181 | After this, the execute target will simply attempt to run the program from the command line with any supplied arguments. 182 | ```Makefile 183 | execute: 184 | $(target) $(ARGS) 185 | ``` 186 | 187 | Once the application is closed, crashed, or otherwise ended, the clean command will then be run (for the appropriate platform path and command), by deleting the `/bin/` directory, including object files, dependency files and the application itself. This prepares the build system for a fresh compilation. 188 | ```Makefile 189 | clean: 190 | $(RM) $(call platformpth, $(buildDir)/*) 191 | ``` 192 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | 5 | // Initialization 6 | int screenWidth = 800; 7 | int screenHeight = 450; 8 | 9 | raylib::Color textColor(LIGHTGRAY); 10 | raylib::Window w(screenWidth, screenHeight, "Raylib C++ Starter Kit Example"); 11 | 12 | SetTargetFPS(60); 13 | 14 | // Main game loop 15 | while (!w.ShouldClose()) // Detect window close button or ESC key 16 | { 17 | // Update 18 | 19 | // TODO: Update your variables here 20 | 21 | // Draw 22 | BeginDrawing(); 23 | ClearBackground(RAYWHITE); 24 | textColor.DrawText("Congrats! You created your first window!", 190, 200, 20); 25 | EndDrawing(); 26 | } 27 | 28 | return 0; 29 | } --------------------------------------------------------------------------------