Nest is a tool that generates pre-configured C++ projects from templates. The templates use the Premake build system and manage external dependencies with vcpkg. Nest is a standalone executable file designed to be used as a command-line program. The idea is to provide a project structure that handles cross-platform building and development on multiple architectures and build configurations automatically.
Nest produces reusable C++ projects that meet the following requirements :
- Automated external dependency management The user specifies the external dependencies name and version, the system handles the installation and usage.
- Automated build system IDE project files are generated from pre-configured scripts describing the project structure.
- Automated tasks Tasks such as generating project files, installing dependencies and clearing the build are performed by calling a script.
- Versatile build The project generated from the template can be built in 32 or 64 bits, in Debug or Release mode, with static or dynamic linkage, with the corresponding version of the external libraries.
- Cross-platform build The project generated from the template can be built and developed on multiple platforms in the same way.
To use Nest, simply run the executable file with commands described below.
Note that Nest should always be used at the root of generated templates (with the exception of the init command which creates a template).
nest [-h, --help] | [--help-all] # C++ project generator with external dependencies and build management
init <--application> | <--library> # Create an empty project
environment # Perform an operation on the environment
set [--vcpkg-path path] # Install external dependencies
reset # Uninstall external dependencies
workspace # Perform an operation on the workspace
set [--target target] # Generate IDE project files
reset # Remove IDE project files
build # Perform an operation on the build
clear # Remove the build directory
The templates generated by Nest are autonomous and can be used independently from Nest. Once a template is created with nest init, Nest can be removed entirely as it is merely a helper that provides a comfortable command-line interface to run the scripts from the scripts folder. The choice between using the Nest executable at the root of the project template or using the scripts directly is up to the user.
This section describes the structure of the projects generated by Nest. The generated projects can vary depending on the template they were created from. The projects follow this structure :
Project/
Application/ # Project application
res/ # Application resource folder
src/ # Application source code folder
premake5.lua # Application Premake script
Library/ # Project library
external/ # External dependencies
bin/ # External .dll/.so files
include/ # External header files
lib/ # External .lib/.a files
vcpkg_manifests/ # Vcpkg manifest files
scripts/ # Scripts used to automate project operations
linux/ # Linux scripts
windows/ # Windows scripts
.gitignore # Pre-configured .gitignore file for project and IDE files
premake5.lua # Main Premake script representing the workspace and calling project scripts
README.md # Project description file with pre-written instructions
TODO.md # Empty to-do list file
Once a project is generated, running git init from the root folder sets up the project if git versioning is desired.
A .gitignore file is provided to avoid including build output, external dependencies and project files in the git repository.
.gitkeep files are present in many folders. This allows the project structure to remain intact when used as a git repository, even when some folders aren't filled yet.
The project external dependencies can be specified in the appropriate vcpkg_manifests subfolders.
There is one manifest file for static dependencies and another for dynamic dependencies. The syntax for vcpkg manifest files is described here.
While the external dependencies are handled by vcpkg and read from the external/vcpkg_installed folder, additional external libraries can be added manually if they are not available on vcpkg.
The projects are configured to read libraries in the bin, include and lib folders in the external folder. The bin and lib folders contain a debug and release folder to allow both types of build.
The Premake scripts can be modified as the project evolves. In particular, the applications and libraries should link the library (.lib/.a) files in their Premake script when they are needed. Header and binary files are automatically accessible as configured by the workspace Premake script.
The script folder contains a handful of scripts for each platform.
Each script contains a description at the beginning of the file.
- set_environment : installs external dependencies and generates the project workspace. It should be run first and usually only once.
- reset_environment : removes external dependencies, clears the project workspace and build files. It resets the project to its original state as when opened for the first time.
- set_workspace : generates the project workspace using the Premake scripts.
- reset_workspace : removes project files generated by Premake.
- clear_build removes the project build.
The set_workspace can be modified to pass arguments to the workspace Premake script. By default, the project can accept these options depending on the template it was created from.
--shared-librarybuilds the library as a shared library.--static-crtbuilds the library with static crt linkage (C runtime).
To build Nest, follow these steps :
- Download the Nest repository
- Download Premake
- Place the
premake5executable file at the root of the repository - Run the following command :
.\premake5.exe [target]on Windows or./premake5 [target]on Linux (replace [target] with the target IDE, the list of available targets can be found here) - Open the generated IDE project file, select the platform and configuration, and build the program
- Place the generated executable file in a standard executable path or anywhere relevant
Nest has the following external dependencies :
The licences can be found in the external/licenses folder.
Yes, Nest is completely optional. Project creation can be done without it by copying the desired template from the Templates folder. The templates are completely agnostic to Nest, each operation offered by Nest can be achieved by calling the corresponding script in the project scripts folder.
Concretely, Nest can do two things :
- Create an empty project from a template (the templates are embedded in the Nest executable)
- Run scripts from the templates
scriptsfolder
All of this is done through an intuitive command-line interface. For example, on Windows, calling nest workspace set from the root of the project is equivalent to calling .\scripts\windows\set_workspace.bat.
Also, project creation is easier with Nest since no template downloading is necessary.
Using Nest thus allows a simpler way to use the projects created from templates. A unified command-line interface like this can be preferred over manual script calling. This remains completely optional.
Yes, once the project is created from the template, the scripts, structure and files can be modified as needed.
It should be noted that changing the structure of the project can cause some elements to break. For example, the default external folder and its subfolder structure is expected to remain as-is by the workspace Premake script (the one at the root of the project). Any modification to the existing files and folders in the external folder must be reflected in the Premake script for dependency management to continue working.
The description of each script in the scripts folder should be taken into consideration when modifying them or moving files. They expect to be run from the root of the project.
If your project uses a library that is not available on vcpkg, you have three options :
- The
externalfolder contains abin,includeandlibsubfolder. The Premake scripts are configured to read these folders for external dependencies. They are all treated as a compiler search path for their respective category. The downside is that the process of placing the different versions of each library (debug and release) in the folders is tedious and time-consuming, since this is done manually. The content of these folders is cleared when resetting the environment. - Another package manager can be added to the
set_environmentscript, with the necessary adjustments to the workspace Premake script. This can take some time to set up but might be worth considering if many libraries are missing on vcpkg. One of the advantages of Nest templates is that they can easily be expanded upon : scripts can be added or modified, additional steps can be included. - If you own the library, you can make it a vcpkg registry following this article.
Premake is very easy to use, even for beginners. Reading the existing scripts provides some insight about how projects are set up. To modify the scripts, the Premake documentation is a great resource to get started.
The build system used in the templates is Premake. Explicitly avoiding CMake in C++ projects is one of the reasons Nest was created.
There are many reasons for this, here is a subjective list :
- CMake is much more verbose than Premake, achieving the same result than Premake requires a lot more scripting
- CMake uses imperative scripting, Premake uses declarative scripting which is more intuitive for project description
- Premake scripts are easier to maintain and modify than CMake scripts
- CMake produces much more files than Premake where Premake only generates files that are used by the user
- CMake takes much longer than Premake to generate project files
- CMake doesn't allow separating the build output from the intermediate build output
- Premake is overall less intrusive than CMake
This project was initially born from the need to avoid repeating the same tasks for every C++ project setup. External dependencies in C++ are difficult to manage. Just building a project in debug or release mode and switching between the two requires to have both versions of each external dependency and an IDE project configured to link the correct version depending on the target. The distinction between static and dynamic libraries, and between 32 and 64 bits adds even more complexity. This is not helped by the need to deploy the project on other development environments : platforms and IDE can be different. External dependencies are also better excluded from git repositories they are used in.
After experimenting with CMake, I concluded that it was way too verbose and complex for what it is supposed to achieve. Of course it is the most wide-spread build system, its userbase makes it the most complete and robust tool in that area. Maybe it is the only way to handle certain things, but I wasn't satisfied with it and it always felt too heavy, so I tried Premake. Project by project, I wrote many Premake scripts, each time handling more complex scenarios, applications, libraries, it was not always easy, but I know for sure it would have been much more difficult or even impossible to achieve the same result with CMake, not to mention how much more I would need to write with CMake.
After many projects, I noticed my projects scripts were converging into a reusable and complete structure. This is why I made a first version of my template : a folder with the main scripts, files and project structure, and a few convenience scripts ready to be used, so that starting a new project would require little to no steps. This version however, did not handle external dependencies automatically. I was using vcpkg and copying libraries files manually in the project external folders. This is how the second version of my template with a vcpkg integration came to be.
After many improvements, I finally had a fully functional template for my projects. For completeness, I created Nest, to support multiple types of templates and provide a better user experience. I do not expect anyone to use Nest, as I created it to suit my needs, but it might be interesting for people that are not satisfied with CMake for the same reasons I mentioned.