Introduction
Hello everyone and welcome to my first ever tutorial! In this tutorial I will walk you through how to create your own static library project from scratch in C++ with Premake5.
We will be using premake5 as it allows us to write some lua code to configure our project and then create a build system for any platform we required to develop on. It is very easy to setup and this tutorial will cover it.
This tutorial will be done for windows 11 currently, however future tutorials on different operating systems will be release later on but for now windows is what this tutorial will focus on.
I will provide some references to other operating systems in case you would like to follow along anyways but if you come across issues they will not be directly supported in this tutorial.
Requirements
- You must already have knowledge of what a static library is and when to use them.
- Have Visual Studio 2022 installed correctly. (With C++ development addons)
- Basic knowledge of C++ syntax
- Using windows (Preferably), linux or macos.
- Have a basic code editor installed such as vscode, sublime or something else.
Tutorial
Step 01 - Setting up our project directories
So the first thing we need to do is create a folder called whatever our project is for example I will call mine Static_Library_Project_Template
.
Next we will need to open this folder in our preferred minimal code editor, for me this is vscode:
Once you have go to this stage we can create a number of folders ready to be used for our project, here is my recommended folder structure:
Static_Library_Project_Template
-> Build - This will be used to hold the premake5 binary executable.
-> Scripts - This will be used to hold the scripts to run the premake build
system creation for each platform (Windows, Linux, MacOS).
-> Libs - Holds all libraries in our project/solution
-> Apps - Holds all application in our project/solution
Step 02 - Setting Up our Base Configuration Files
Next we can create the base files in our root project directory:
Static_Library_Project_Template
-> Build-Solution.lua - This file is the premake5 configuration file for
creating our project buld system.
-> .gitignore - Include this file only if you are using git
-> README.md - Include this file only if you are using git
Lets go ahead and start writing our configuration file in lua
, so to do this open your Build-Solution.lua
file and write the following code:
-- Define a new workspace named "PROJECT_NAME"
workspace "PROJECT_NAME"
-- Set the target architecture to 64-bit
architecture "x64"
-- Define 3 build configurations: DEBUG, RELEASE, and DIST (distribution)
configurations { "DEBUG", "RELEASE", "DIST" }
-- Specify the default startup project when the solution is opened
startproject "Apps/DebuggerApp"
-- Apply the following settings **only on Windows systems**
filter "system:windows"
-- Enable C++ exception handling using standard C++ semantics
buildoptions { "/EHsc",
-- Enforce use of standard conforming preprocessor
"/Zc:preprocessor",
-- Ensure __cplusplus macro reflects the actual C++ language version
"/Zc:__cplusplus" }
-- Define a variable that sets the output directory pattern based on system, architecture, and config
OutputDir = "%{cfg.system}-%{cfg.architecture}/%{cfg.buildcfg}"
-- Start a new group in the solution explorer (grouping related projects)
group ""
-- Include a Lua build script for a static library called StaticLibName
include "Libs/StaticLibName/Build-StaticLibName.lua"
-- Return to root group (no name)
group ""
-- Include the build script for the DebuggerApp application
include "Apps/DebuggerApp/Build-DebuggerApp.lua"
So with this please not you can change the PROJECT_NAME
to what your project is called. You can also change the StaticLibName
to your library name. If you would also like you can change the DebuggerApp
to your own custom name however we called it this as it will only be used for testing our library works which is the reason we are creating an Executable application in our library project.
So far you should have something like this:
Step 03 - Next we need to install and setup premake5.exe
We can download premake5.exe
from the following link:
https://premake.github.io/download
Make sure that you download the version that is for your operating system.
Once downloaded we need to copy/move the premake5.exe
file into our Build directory.
I have downloaded the file and it gives me a zipped executable file, so I will now unzip this and I will have the following:
Then we go into the extracted folder and find our executable:
This is the file we must copy / move into our Build directory in our project folder so lets go ahead and do that:
As you can see I have now moved this file into the correct folder and this is also what you should have too.
Step 04 - Windows Pre-Build Script
In this step we need to create the windows batch script that will run premake5.exe
with our configuration to create our development environment based on our custom configuration.
Lets start with creating a file called Setup-Win64.bat
in the Scripts
Folder:
Now lets write some batch script code:
@echo off
REM Disable command echoing for cleaner output
pushd ..
REM Save current directory and change to parent directory
Build\premake5.exe --file=Build-Solution.lua vs2022
REM Run Premake5 to generate Visual Studio 2022 project files using Build-Solution.lua
popd
REM Return to the original directory
Perfect now you should have something that looks like this:
This is great but if we were to run this batch script now we would have an error: why is that? Well you see although we created the configuration file we actually need to create our static library project and Debugger App project with a configuration file in each of these projects for this to all work.
Step 05 - Create the Static Library Project
So lets start by creating a folder in our Libs
folder called whatever it is we named our static library in our Build-Solution
Configuration File.
For me that is StaticLibName
.
As you can see I have created the folder called StaticLibName
inside of the Libs
folder.
Next we need to create another configuration file in lua
called Build-StaticLibName.lua
. And then we must make sure we have the following code:
-- Define a new project named "StaticLibName"
project "StaticLibName"
-- Set the project type to a static library (.lib)
kind "StaticLib"
-- Set the programming language to C++
language "C++"
-- Use the C++23 standard for compilation
cppdialect "C++23"
-- (Temporary) set the output directory for binaries based on build config (e.g., DEBUG/RELEASE)
targetdir "Binaries/%{cfg.buildcfg}"
-- Use the shared C runtime (not statically linked)
staticruntime "off"
-- Add all header (.hpp) and source (.cpp) files from these folders to the project
files { "Includes/**.hpp", "Source/**.cpp" }
-- Include the "Includes" folder so headers can be found during compilation
includedirs
{
"Includes"
}
-- Set final target output path using system, architecture, config, and project name
targetdir ("../../Binaries/" .. OutputDir .. "/%{prj.name}")
-- Set intermediate object files output path for compiled objects
objdir ("../../Binaries/Intermediates/" .. OutputDir .. "/%{prj.name}")
-- Apply settings only for Windows systems
filter "system:windows"
-- Use the latest available Windows SDK version
systemversion "latest"
-- Define a macro indicating the build is for 64-bit Windows
defines { "DEF_WIN64" }
-- Apply settings for the DEBUG configuration
filter "configurations:DEBUG"
-- Define a macro for debug builds
defines { "DEF_DEBUG" }
-- Link the debug version of the runtime library
runtime "Debug"
-- Enable debug symbols (for stepping through code in debugger)
symbols "On"
-- Apply settings for the RELEASE configuration
filter "configurations:RELEASE"
-- Define a macro for release builds
defines { "DEF_RELEASE" }
-- Link the release version of the runtime library
runtime "Release"
-- Enable compiler optimizations
optimize "On"
-- Keep debug symbols enabled (optional, for profiling/symbolic stack traces)
symbols "On"
-- Apply settings for the DIST (distribution/final product) configuration
filter "configurations:DIST"
-- Define a macro for final distribution builds
defines { "DEF_DIST" }
-- Use release runtime
runtime "Release"
-- Enable compiler optimizations
optimize "On"
-- Disable debug symbols to reduce binary size and hide internals
symbols "Off"
Now we have this configuration file lets write some sample code for our library:
Firstly lets create two folders in the StaticLibName
folder:
StaticLibName
-> Includes
-> Source
After that lets create two files a .cpp
and .hpp
file now the .hpp
file will go inside the Includes folder and the .cpp
file will go inside the source folder. The file should be named Add.hpp
and Add.cpp
.
Add.hpp
namespace MATH {
int add(int a, int b);
}
Add.cpp
#include "Add.hpp"
int MATH::add(int a, int b) {
return a + b;
}
Step 06 - Create the Debugger App Project
So lets start by creating a folder in our Apps
folder called whatever it is we named our Debugger App in our Build-Solution
Configuration File.
For me that is DebuggerApp
.
As you can see I have created the folder called DebuggerApp
inside of the Apps
folder.
Next we need to create another configuration file in lua
called Build-DebuggerApp.lua
. And then we must make sure we have the following code:
-- Define a new project named "DebuggerApp"
project "DebuggerApp"
-- Set the project type to a console application (produces .exe)
kind "ConsoleApp"
-- Use the C++ programming language
language "C++"
-- Use the C++23 standard for compiling the code
cppdialect "C++23"
-- Set a temporary target output directory based on build configuration
targetdir "Binaries/%{cfg.buildcfg}"
-- Link against the dynamic C runtime (instead of statically)
staticruntime "off"
-- Add all header (.hpp) and source (.cpp) files from these folders to the project
files { "Includes/**.hpp", "Source/**.cpp" }
-- Specify include directories for header file lookup during compilation
includedirs
{
"Includes", -- Local project headers
"../../Libs/StaticLibName/Includes" -- Headers from the linked static library
}
-- Link this app against the "StaticLibName" static library
links
{
"StaticLibName"
}
-- Set the final output directory for the executable (organized by OS, arch, config, and project)
targetdir ("../../Binaries/"..OutputDir.."/%{prj.name}")
-- Set the intermediate directory for object files during compilation
objdir ("../../Binaries/Intermediates/"..OutputDir.."/%{prj.name}")
-- Apply the following settings only when building on Windows
filter "system:windows"
-- Use the latest available Windows SDK
systemversion "latest"
-- Define a macro to indicate the build is for 64-bit Windows
defines { "DEF_WIN64" }
-- Configuration-specific settings for DEBUG
filter "configurations:DEBUG"
-- Define a macro to indicate a debug build
defines { "DEF_DEBUG" }
-- Use the debug runtime library
runtime "Debug"
-- Enable debug symbols for debugging in IDEs
symbols "On"
-- Configuration-specific settings for RELEASE
filter "configurations:RELEASE"
-- Define a macro to indicate a release build
defines { "DEF_RELEASE" }
-- Use the release runtime library
runtime "Release"
-- Enable optimizations for performance
optimize "On"
-- Keep debug symbols (optional for debugging or profiling)
symbols "On"
-- Configuration-specific settings for DIST (distribution/final release)
filter "configurations:DIST"
-- Define a macro to indicate a distribution build
defines { "DEF_DIST" }
-- Use the release runtime library
runtime "Release"
-- Enable full compiler optimizations
optimize "On"
-- Disable debug symbols to reduce binary size and improve load time
symbols "Off"
Now we have this configuration file lets write some sample code for our library:
Firstly lets create two folders in the DebuggerApp
folder:
DebuggerApp
-> Includes
-> Source
After that lets create two files a .cpp
and .hpp
file, now the .hpp
file will go inside the Includes folder and the .cpp
file will go inside the source folder. The files should be named Test.hpp
and Main.cpp
.
Test.hpp
#include <iostream>
void log_test(int res) {
std::cout << res << std::endl;
}
Main.cpp
#include "Test.hpp"
#include <Add.hpp>
int main() {
int result = MATH::add(5, 6);
log_test(result);
return 0;
}
Step 07 - Running our Pre-Build Setup and Testing
So now that we have set everything up go to a terminal inside the Scripts
folder like this:
And type the following command:
.\Setup-Win64.bat
Press enter and you should see this:
Perfect now you can open the PROJECT_NAME.sln
file and it should open this window:
We can now press the Local Window Debugger
button with a big green arrow before it to run our solutions and see what happens.
Here is what you should get:
SUCCESS
If you get this then well done you have SUCCESSFULLY completed this tutorial and setup your first project with a static library. :)
Contact Information
https://www.instagram.com/estrolabz/
https://www.patreon.com/c/ESTROLABZ
https://www.youtube.com/@estrolabzuk
https://www.reddit.com/r/ESTROLABZ/
https://autumn-oboe-c16.notion.site/ESTROLABZ-Blog-237763e1ef908090a5fec3ea8c04331e?source=copy_link
Top comments (0)