A cross-platform SFML 2.5.1 & C++17 build environment for Visual Studio Code
A cross-platform SFML 2.5.1 & C++17 build environment for Visual Studio Code
Note: This project has been superseded by: https://github.com/chalet-org/chalet-example-sfml, utilizing a new build system called Chalet. Please give that a try instead!
Note: You can manage the "Path" environment variable from Windows if you'd like, but I've found sandboxing it in VS Code is better for tracking things like .dll dependencies.
At this point, everything you need is installed
Source files and folders are automatically detected by the Makefile. It looks for them in the "src" folder, and at the moment builds from .c, .cpp, .cc & .rc files.
This build system assumes that any libraries includes in the "lib" folder are either pre-built or header-only. It's auto-included as one of the search directories in the Makefile.
Usage example:
+ lib/
+ catch2/
+ catch.hpp
+ nlohmann_json/
+ json.hpp
+ XInput/
+ XInput.h
+ XInput.lib
test/test_someTest.cpp
#include <catch2/catch.hpp>
...
src/JsonImpl.hpp
#include <nlohmann_json/json.hpp>
...
src/InputManager.hpp
#include <XInput/XInput.h>
...
env/windows.all.mk
LINK_LIBRARIES := \
XInput
The environment variables used by the Makefile are managed from the env folder in separate .mk (Make) files, organized by build type & platform, so you can customize which SFML libraries to include if you want, or pretty much anything without having to edit the tasks.json. Each file is outlined below:
./build.sh: Contains the build scripts that tasks.json calls
./env/.all.mk: All platforms & builds
./env/.debug.mk: All platforms, Debug build
./env/.release.mk: All platforms, Release build
./env/linux.all.mk: Linux, All builds
./env/linux.debug.mk: Linux, Debug build
./env/linux.release.mk: Linux, Release build
./env/osx.all.mk: MacOS, All builds
./env/osx.debug.mk: MacOS, Debug build
./env/osx.release.mk: MacOS, Release build
./env/rpi.release.mk: Linux (Raspberry Pi), Release build
./env/windows.all.mk: Windows, All builds
./env/windows.debug.mk: Windows, Debug build
./env/windows.release.mk: Windows, Release build
Unit Tests use the same settings as the Release build.
The environment variables that can be added to each .mk file are outlined below. If you need a line-break anywhere simply add a "\" character. You can set base variables in _.all.mk and then build specific variables using "VAR := $(VAR)" syntax in _.debug.mk or *.release.mk. The hierarchy goes:
./env/.all.mk
./env/.(build).mk
./env/(platform).all.mk
./env/(platform).(build).mk
CFLAGS:
Compiler flags to use.
MAX_PARALLEL_JOBS:
Max number of parallel jobs to run, based on number of cpus cores available
CLEAN_OUTPUT:
If set to 'true', the build output will only show the path/filename of the source file being built as well as the linking step and a couple helpful messages. All other commands will be hidden (including assembly dumps)
DUMP_ASSEMBLY:
If set to 'true', *.o.asm files will generate within the bin/(Build)/asm folder. The bin folder is hidden from VS Code by default, but you can open the asm folder in a separate instance and browse the assembly that way if you'd like to, or customize it from settings.json.
PRECOMPILED_HEADER:
Define a precompiled header file (no extension). If this variable is not defined in the env files, then the precompiled header will not be used. This file will be excluded from Rebuild/Build tasks, but if the bin/(build) directory is removed, it will be as well.
If you're unfamiliar with how precompiled headers work, these speed up compile time by precompiling commonly used includes like standard libraries and the SFML includes. The PCH.hpp gets implicitly included in each cpp file, so you don't need to manually include it each time like with Visual Studio. When it actually compiles, it can be large, but it does not affect the size of the final binary (which would be the same size with or without the PCH).
PRECOMPILED_HEADER:=PCH
LIB_DIRS:
Add any additional lib directories (full path)
LIB_DIRS= \
C:/sfeMovie/lib \
C:/myLibraries/lib
INCLUDE_DIRS:
Add any additional include directories (full path)
INCLUDE_DIRS= \
C:/sfeMovie/include \
C:/myLibraries/include
LINK_LIBRARIES:
Add any additional link libraries
LINK_LIBRARIES= \
XInput \
user32 \
something
BUILD_FLAGS:
Additional compiler flags for the particular build (including prefix)
BUILD_FLAGS= \
-mwindows
BUILD_MACROS:
Macros to include in the build
BUILD_MACROS= \
_DEBUG
BUILD_DEPENDENCIES:
Dependency .dll/.so files to include in the bin/(build) folders
BUILD_DEPENDENCIES= \
C:/SFML-2.5.1/bin/openal32.dll
MACOS_FRAMEWORK_PATHS:
Framework paths, other than /System/Library/Frameworks
MACOS_FRAMEWORK_PATHS= \
/Library/Frameworks
MACOS_FRAMEWORKS: Frameworks to include, (no extension)
MACOS_FRAMEWORKS= \
CoreFoundation
I thought it was important to include a build task that creates a final "build" folder and copies the files in the bin/Release folder, any dependency .dlls, and any other directories into it. It's accessed via (Ctrl+Shift+B > Build: Production) and uses a couple special environment variables:
PRODUCTION_DEPENDENCIES:
Files & folders to copy into the "build" folder upon using the "Build: Production" task. In MacOS, this is anything going into the the app bundle's "Resources" folder.
PRODUCTION_DEPENDENCIES= \
C:/mingw32/bin/libgcc_s_dw2-1.dll \
C:/mingw32/bin/libstdc++-6.dll \
C:/mingw32/bin/libwinpthread-1.dll \
C:/SFML-2.5.1/bin/openal32.dll \
C:/SFML-2.5.1/bin/sfml-audio-2.dll \
C:/SFML-2.5.1/bin/sfml-graphics-2.dll \
C:/SFML-2.5.1/bin/sfml-network-2.dll \
C:/SFML-2.5.1/bin/sfml-system-2.dll \
C:/SFML-2.5.1/bin/sfml-window-2.dll \
content
PRODUCTION_EXCLUDE:
Files & extensions to exclude from the production build.
PRODUCTION_EXCLUDE= \
*.psd \
*.rar \
*.7z \
Thumbs.db
PRODUCTION_FOLDER:
The folder the production build will go into. This can be an absolute path or a relative path. Defaults to "build" if not defined.
PRODUCTION_FOLDER=build
Option 1: The "Build: Production" script creates a bundle & a basic .dmg image, but it does no code signing whatsoever! You must do that yourself (for now). There's a lot to document about, but to start, it requires a MacOS/MacHelper.cpp file to ensure the working directory is looking for resources inside the bundle's Resource folder. There's an Info.plist.json that gets compiled to the binary Info.plist, and an icon that gets compiled to an *.icns file. See osx.all.mk for additional production environment variables. Be aware some of it is still pretty experimental. The variables are outlined below.
Option 2: Use Xcode to bundle your final build! It's as simple as that. Follow the rest of the directions outlined HERE, copy your code-base in the Xcode project folder, and go from there.
PRODUCTION_MACOS_ICON:
The app bundle's icon (.png, no extension)
PRODUCTION_MACOS_ICON := sfml
PRODUCTION_MACOS_BUNDLE_DEVELOPER:
Your name, company, etc.
PRODUCTION_MACOS_BUNDLE_DEVELOPER := developer
PRODUCTION_MACOS_BUNDLE_DISPLAY_NAME:
App's display name (used everywhere)
PRODUCTION_MACOS_BUNDLE_DISPLAY_NAME := SFML Boilerplate
PRODUCTION_MACOS_BUNDLE_NAME:
Internal app name (used somewhere by MacOS... ???)
PRODUCTION_MACOS_BUNDLE_NAME := SFML Boilerplate
PRODUCTION_MACOS_MAKE_DMG:
set to "true" to make a .dmg image
PRODUCTION_MACOS_MAKE_DMG := true
PRODUCTION_MACOS_BACKGROUND:
Background image file (.png) to use in the .dmg image. A "[email protected]" file is also expected
PRODUCTION_MACOS_BACKGROUND := dmg-background
PRODUCTION_MACOS_DYLIBS:
Dynamically linked libraries to include in the final build.
PRODUCTION_MACOS_DYLIBS := \
/usr/local/lib/libsfml-graphics.2.5 \
/usr/local/lib/libsfml-audio.2.5 \
/usr/local/lib/libsfml-network.2.5 \
/usr/local/lib/libsfml-window.2.5 \
/usr/local/lib/libsfml-system.2.5
PRODUCTION_MACOS_FRAMEWORKS:
Any frameworks to add to the app bundle's "Frameworks" folder. (Path, no extension)
PRODUCTION_MACOS_FRAMEWORKS :=
/Library/Frameworks/ogg
A default Ubuntu app build is included, but beyond that, you're on your own. The App's configuration is set in env/linux/exec.desktop. Similar to MacOS build these are the linux specific variables:
PRODUCTION_LINUX_ICON:
The app icon (.png, no extension)
PRODUCTION_LINUX_ICON := sfml
PRODUCTION_LINUX_APP_NAME:
The app's name
PRODUCTION_LINUX_APP_NAME := SFML Boilerplate
PRODUCTION_LINUX_APP_COMMENT:
The app's description
PRODUCTION_LINUX_APP_COMMENT := My SFML Game
Unit Testing uses Catch2.
One can build & run the unit tests with the appropriately named "Build & Run: Tests" task in vscode. The Unit tests are a slightly different build target. You create tests in the test/ directory, and they get built alongside the "Release" build target. Refer to the Catch2 docs to build your test cases.
How you write your unit tests will obviously depend on how you write your engine code, but here are some examples:
Running the Profile: Debug task will build the Debug target (if necessary) and generate a profiler_analysis.stats file from a gmon.out file using gcc's "gprof" profiler. You can then examine the stats file in the workspace.
If you need to add additional external libraries, these are a couple different places to keep in mind.
.vscode/c_cpp_properties.json - You'll see compilerPath & includePath. The compilerPath includes all the compiler's directories so, the includePath only needs the root project directory and any additional libraries you want to include. SFML is included as well in this boilerplate. See details below.
.vscode/settings.json - Contain all of your workspace settings & overrides VS Code's main settings.json. Here are some settings of interest:
.vscode/launch.json - Used to store the configuration to launch the debugger.
.vscode/tasks.json - Used to store the task definitions (Build & Run commands, etc.).
.vscode/_keybindings.json - As mentioned before, this is used purely to store handy keybindings that one can add themselves, and not recognized by VS Code.
There's some interesting nuances to creating Windows icons, so I've included two easy-to-use shell scripts that will create an icon for you from .png files:
win-make_icon_from_all.sh
win-make_icon_from256.sh
They only require you to install ImageMagick, available here: https://www.imagemagick.org/script/download.php#windows (top-most binary)
The "win-make_icon_from_all.sh" script looks for 4 files: icon_16.png, icon_32.png, icon_48.png & icon_256.png. Edit them in the program of your choice & run the script using git bash and you'll get an app.ico file that you can import in src/Win32/Icon.rc
. The WindowsHelper
class will read all the icons from the .ico file, and pick out the 16x16 & 32x32 ones for use as the application icon, while windows uses the other sizes for explorer.
The "win-make_icon_from256.sh" script is even simpler. You make one icon - icon_256.png, and it will generate the other sizes for you and output the app.ico file.
You can obviously modify these scripts to support other sizes used in edge cases (scaling factors use 20, 40, 64 & 96 for instance), but the 4 included are the most widely used.
Recently, I wanted to avoid duplicate Makefiles in my various projects, so I found a nice little solution to do this.
include ../Makefile
#!/bin/bash
bash ../build.sh $1 $2 $3 $4
Multiple targets (dynamic libraries + 1 executable) are supported at the moment, although there's a couple setup changes you'll need.
"options": {
"env": {
"BUILD_TARGETS": "target1 target2 main"
}
}
BUILD_TARGETS is a simple list of the folders, which then get output as the library name. For instance, "target1" would build out to "target1.dll" in Release, and "target1-d.dll" in Debug. "main" triggers the main target, and outputs "(root folder).exe" as it does w/o multiple targets.
Note: Ordered from first built to last built (main must be last if it's included)
#!/bin/bash
export BUILD_TARGETS='target1 target2 main'
bash ../build.sh $1 $2 $3 $4
This will be an ongoing project that I'll try to update as new SFML versions come out. Updating SFML releases should be relatively painless as I'll keep the pre-reqs up to date as well. Feel free to offer suggestions/report issues if there's anything I missed, or could do better.
That should be all you need to get started. Happy game making and/or programming!
If you have a reason to build your project without Code (on Raspbian or something), you can run build.sh the following way:
bash build.sh (build|buildrun|rebuild|run|buildprod|profile) (Debug|Release) (executable commmand line options)
For instance, to build & run the Release build, you'd use:
bash build.sh buildrun Release
If you run the script without any parameters, it's the same as the following:
bash build.sh buildprod Release
To build & run the unit tests, use:
bash build.sh buildrun Tests vscode '-w NoTests -s'
(The last parameter contains Catch2 command line options)
If the build mode is not Debug or Release, it will default to Release. If you need to, change the "Path" variables within the build.sh file in the "if [[$VSCODE != 'vscode']] ; then" block.
I'll maybe make a full guide for this, but I'd recommend doing your development on another machine, and then just pulling the project via git and building it on the Pi with the build script in the previous section. Raspbian Lite (as of 1/6/2019) only comes with GCC 6.x, so you'll want to add GCC 8.x via this guide and compile SFML 2.5.1 from source. Once your app/game is compiled, you can launch it via startx & matchbox-window-manager (after enabling OpenGL from raspi-config).
In the precompiled header (src/PCH.hpp), I added an extra SFML define for the Pi aptly named SFML_SYSTEM_PI so you can conditionalize parts of your code for PI specific things (think "kiosk mode"). From there, you're in the wild west.
GCC 7.3.0 is still probably the most stable GCC build on Windows, but if you want to try out newer versions, you can use MSYS2.
Start with a clean install from here:
C:/msys64
(default)pacman -Syu
& restart Msys2 when it tells you do.pacman -Su
to update packagespacman -S mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain mingw-w64-i686-openal mingw-w64-x86_64-openal
_MINGW := C:/msys64/mingw64/bin
_SFML := C:/SFML-2.5.1-gcc-10.1.0/mingw64
if [[ $1 == '' && $2 == '' ]]; then
if [[ $OSTYPE == 'msys' || $OSTYPE == 'win32' ]]; then
export PATH="/c/SFML-2.5.1-gcc-10.1.0/mingw64/bin:/c/msys64/mingw64/bin:$PATH"
bash ../build.sh buildprod Release vscode
exit 0
fi
fi
Run any build task (from scratch) and you should be good to go!