Skip to content

simongeilfus/project_starter_kit

Repository files navigation

project_starter_kit

This repository is an attempt at unifying the build scripts and tools I often use to setup a c++ project on Windows.

This is a collection of python and cmake scripts that I have found useful or use often. The common idea behind those scripts is to make iterative prototyping fast and effortless. Spending less time in visual studio project settings and more time writing code.

It is also an ongoing project and might still contain some rough edges but it has made my life easier so far.

Requirements

CMake 3.6 is required to build the project and Python to easily add new subprojects. If not already installed the easiest to get them is to run setup cmake python.

Introduction

CMake is used to generate a single solution with everything in it; a list of projects, third party libraries and if needed a common shared library. A system of project template is used to facilitate the addition of new subprojects and favours working with small prototype/test projects inside the same solution. You can easily duplicate projects and move things around without the fear of breaking the solution. It allows to easily add third party libraries and experiments sometimes with just a console application, maybe a small glfw prototype or move to a more complete cinder app.

Here's an example of setup after copying the content of the boilerplate inside a new repository.

setup glfw glad imgui
create glfw GlfwProject 
configure

This will add submodules for glfw, glad and imgui, create a glfw project named GlfwProject and generate a visual studio solution inside the build folder.

📂 MyProject
├─ 📂 build
│ └─ 🏭 MyProject.sln
├─ 📂 projects
│ ├─ 📂 GlfwProject
│ │ └─ 📃 GlfwProject.cpp 
└─ 📂 third_party
  ├─ 📂 imgui
  ├─ 📂 glad
  └─ 📂 glfw

The following will add a new project to the solution using another template for raw cpp. No need to change solution or create a separate project.

create cpp ConsoleApp
configure

Let's say that at that point you want to build a larger or more complex app; you could use cinder but not sure whether you want it as a submodule yet and want to just clone it for now.

setup clone cinder
create cinder CinderTestApp
configure

You get the idea, at that point your project folder should look like this:

📂 MyProject
├─ 📂 build
│  └─ 🏭 MyProject.sln
├─ 📂 projects
│ ├─ 📂 CinderTestApp
│ │ └─ 📃 CinderTestApp.cpp 
│ ├─ 📂 ConsoleApp
│ │ └─ 📃 ConsoleApp.cpp 
│ ├─ 📂 GlfwProject
│ │ └─ 📃 GlfwProject.cpp 
└─ 📂 third_party
│ ├─ 📂 cinder
│ ├─ 📂 imgui
│ ├─ 📂 glad
│ └─ 📂 glfw
├─ 📂 tools
├─ 📃 CMakeLists.txt
├─ 🍍 configure.bat
├─ 🍓 create.bat
├─ 📃 options.cmake
└─ 🍉 setup.bat

SETUP script

setup takes two kind of arguments, the names of libraries or tools to add to the project and whether the script has to add them as clones or submodules. You can change mode as many time as you want but it will start and default to submodules. setup can also be used to download and install cmake, python or vulkan.

setup cmake glfw imgui stb

This will download and instand cmake, and setup glfw, imgui and stb as submodules inside the third_party folder.

The setup scripts makes cloning and adding submodule easier for a few of the libraries I tend to use often but the content of third_party.txt can be customized to support more libraries. It currently supports cereal, cinder, csv, cxxopts, date, entt, glad, glfw, glm, glslang, hfsm2, imgui, imgui_utils, json, liveplusplus, pybind11, sokol, stb, taskflow, tinyexr, tinyobj, ufbx, vma, volk, and vulkanhpp. By default it will add those as submodule but you can easily mix clone and submodule by adding those to your setup command.

setup glfw imgui clone liveplusplus submodule imgui_utils json

This will will add glfw, imgui, imgui_utils and json as submodule but clone liveplusplus.

An easy way to get a vulkan project up would be to run the following, which would download and install the latest vulkan sdk and add glfw, volk and vma as submodule.

setup vulkan glfw volk vma

CREATE script

create is used to quickly generate new projects to be added to the solution. Running create template project_name will create a new project inside the projects folder. There's a few templates to choose from that live inside tools/project_templates folder and are meant to be customized.

create currently supports the following templates: cinder,cpp, glfw and sokol.

It can also accept a few optional arguments such as:

  • --pch specifies whether the project needs to be generated with pch files

  • --cmake specifies whether the project needs a custom cmake config file

  • --folders specifies whether the project wants sources to be created inside subfolders instead of at the project root

  • --configure specifies whether solution need to be generated after creating the project

  • --configure++ specifies whether solution need to be generated after creating the project

Manually creating or duplicating projects

Manually creating a new folder and adding sources to it will work too; meaning you can also easily duplicate a project by just copying its folder. Projects inside the projects folder can be a single .cpp file or they can follow the usual /include,/src ,/assets structure. If a pch.h is detected it will automatically be added to the project configuration. A project.cmake file can be added to the root of a project if it needs custom cmake specific to the project.

Custom template

You can also easily add new template by adding a new folder inside tools/project_templates containing at least a template.cpp. The template process doesn't do much apart from copying the content of the folder and renaming the template.cpp to the name of your project. It will also look for a TEMPLATE string inside that file and replace it with the name of the project as well.

CONFIGURE script

configure calls the main CMakeLists.txt and generates a visual studio solution with the projects presents in the projects folder, a shared library if any and any third party libraries recognized inside the third_party folder. The solution file will be generated inside the build folder. You can use configure live++ to enable Live++ in the solution.

The main CMakeLists.txt will include a few variables from options.cmake . You'll find there a few options like the name of the generated solution/project which you might want to customize if your project isn't named project_starter_kit.

# project name
set(PROJECT project_starter_kit) # change the name of your project here
Common library

If an include and a src folder are detected at the root of the repository a common library will be added to the solution. This can be useful to share a common set of tools, a common base app class, etc... among the different projects. The library includes will be added and its binaries will be linked to all projects.

assets

CMake will check for the existence of an assets folder. Assets and shaders will be added to the project in their respective folders. As cmake doesn't build inside the projects folders an ASSETS_DIR_PATH definition will be added to the project preprocessor (and could for instance be used with a addAssetDirectory( ASSETS_DIR_PATH )).

project.cmake

As mentioned before, adding a project.cmake allows to customize the configuration of a specific project. The most basic customization is to override the default THIRD_PARTY_LIBRARIES to link to only a selection of the shared libraries.

set(THIRD_PARTY_LIBRARIES glfw glm)

The code contained inside the project's project.cmake will be executed after the call to add_executable but before the rest of the project configuration. You can use ${PROJECT_TARGET} as the target name to set any target property, libraries, include directories, etc... specific to that project.

# set the executable type
target_link_options(${PROJECT_TARGET} PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")

The following variables are accessible for each project: ${PROJECT_DIR}, ${PROJECT_OUTPUT_DIR}, ${PROJECT_TARGET}, ${PROJECT_OS_BUNDLE}, ${PROJECT_SOURCE_FILES}, ${PROJECT_UI_FILES}, ${PROJECT_RESOURCES_FILES}.

If there's a need for more granularity or to customize what happens before or inside the call to add_executable a project can also use a CMakeLists.txt instead. By doing so the project loses all the default configuration and the CMakeLists.txt becomes responsible for fully setting up the project. The variables mentioned before are still available so a basic example would look like this:

find_package(SomeLibrary REQUIRED)
add_executable(${PROJECT_TARGET} ${PROJECT_OS_BUNDLE} ${PROJECT_SOURCE_FILES})
target_link_libraries(${PROJECT_TARGET} PRIVATE SomeLibrary)
Third party libraries

The configure build scripts will try to automatically add recognized folders inside the third_party folder. It currently supports the same list of libraries included in third_party.txt. Other third party libraries can be added to the empty section at the end of third_party/CMakeLists.txt. When adding a new third party library it is important to append the name of the library to the THIRD_PARTY_LIBRARIES list if you want it to be linked to your projects.

# custom third party libraries
#----------------------------------------------------------------
# my custom lib
list(APPEND THIRD_PARTY_LIBRARIES custom_lib) # allows linking in other projects
add_subdirectory(custom_lib)
Live++

Live++ can easily be added to both the repository and the solution by doing the following:

setup liveplusplus
configure live++

You can later on decide to re-generate the solution without it by simply calling configure without the argument:

configure