Build uses C++ to imperatively describe a sequence of build operations.
#include "SC-build.h"
#include "Libraries/Strings/StringBuilder.h"
#include "SC-package.h"
namespace SC
{
namespace Tools
{
[[nodiscard]] Result installSokol(const Build::Directories& directories, Package& package)
{
Download download;
download.packagesCacheDirectory = directories.packagesCacheDirectory;
download.packagesInstallDirectory = directories.packagesInstallDirectory;
download.packageName = "sokol";
download.packageVersion = "7b5cfa7";
download.url = "https://github.com/floooh/sokol.git";
download.isGitClone = true;
download.createLink = false;
package.packageBaseName = "sokol";
CustomFunctions functions;
functions.testFunction = &verifyGitCommitHash;
SC_TRY(packageInstall(download, package, functions));
return Result(true);
}
[[nodiscard]] Result installDearImGui(const Build::Directories& directories, Package& package)
{
Download download;
download.packagesCacheDirectory = directories.packagesCacheDirectory;
download.packagesInstallDirectory = directories.packagesInstallDirectory;
download.packageName = "dear-imgui";
download.packageVersion = "00ad3c6";
download.url = "https://github.com/ocornut/imgui.git";
download.isGitClone = true;
download.createLink = false;
package.packageBaseName = "dear-imgui";
CustomFunctions functions;
functions.testFunction = &verifyGitCommitHash;
SC_TRY(packageInstall(download, package, functions));
return Result(true);
}
}
namespace Build
{
void addSaneCppLibraries(Project& project, const Parameters& parameters)
{
project.addDirectory("Bindings/c", "**.cpp");
project.addDirectory("Bindings/c", "**.c");
project.addDirectory("Bindings/c", "**.h");
project.addDirectory("Libraries", "**.cpp");
project.addDirectory("Libraries", "**.h");
project.addDirectory("Libraries", "**.inl");
project.addDirectory("LibrariesExtra", "**.h");
project.addDirectory("LibrariesExtra", "**.cpp");
project.addDirectory("Support/DebugVisualizers", "*.cpp");
if (parameters.platform == Platform::Apple)
{
project.link.addFrameworks({"CoreFoundation", "CoreServices"});
}
if (parameters.platform != Platform::Windows)
{
project.link.addLibraries({"dl", "pthread"});
}
{
project.addDirectory("Support/DebugVisualizers/MSVC", "*.natvis");
}
else
{
project.addDirectory("Support/DebugVisualizers/LLDB", "*");
}
}
static constexpr StringView TEST_PROJECT_NAME = "SCTest";
Result buildTestProject(const Parameters& parameters, Project& project)
{
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.compile.addDefines({"SC_LIBRARY_PATH=$(PROJECT_ROOT)", "SC_COMPILER_ENABLE_CONFIG=1"});
project.compile.addIncludes({
".",
"Tests/SCTest",
});
addSaneCppLibraries(project, parameters);
project.addDirectory("Tests/SCTest", "*.cpp");
project.addDirectory("Tests/SCTest", "*.h");
project.addDirectory("Tools", "SC-*.cpp");
project.addDirectory("Tools", "*.h");
project.addDirectory("Tools", "*Test.cpp");
return Result(true);
}
static constexpr StringView EXAMPLE_PROJECT_NAME = "SCExample";
Result buildExampleProject(const Parameters& parameters, Project& project)
{
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.iconPath = "Documentation/Doxygen/SC.svg";
Tools::Package sokol;
SC_TRY(Tools::installSokol(parameters.directories, sokol));
Tools::Package dearImGui;
SC_TRY(Tools::installDearImGui(parameters.directories, dearImGui));
project.compile.addIncludes({".", sokol.packageLocalDirectory.view(), dearImGui.packageLocalDirectory.view()});
addSaneCppLibraries(project, parameters);
project.removeFiles("Bindings/c", "*");
project.removeFiles("Libraries", "**Test.cpp");
project.removeFiles("LibrariesExtra", "**Test.cpp");
project.removeFiles("Support", "**Test.cpp");
project.addDirectory(dearImGui.packageLocalDirectory.view(), "*.cpp");
project.addDirectory(sokol.packageLocalDirectory.view(), "*.h");
String imguiRelative, imguiDefine;
Path::AsNative));
SC_TRY(StringBuilder(imguiDefine).format(
"SC_IMGUI_PATH=$(PROJECT_ROOT)/{}", imguiRelative));
project.compile.addDefines({"SC_LIBRARY_PATH=$(PROJECT_ROOT)", imguiDefine.view()});
if (parameters.platform == Platform::Apple)
{
project.addDirectory("Examples/SCExample", "*.m");
project.link.addFrameworks({"Metal", "MetalKit", "QuartzCore"});
project.link.addFrameworks({"Cocoa"}, PlatformApple::macOS);
project.link.addFrameworks({"UIKit", "Foundation"}, PlatformApple::iOS);
}
else
{
project.addDirectory("Examples/SCExample", "*.c");
if (parameters.platform == Platform::Linux)
{
project.link.addLibraries({"GL", "EGL", "X11", "Xi", "Xcursor"});
}
}
if (parameters.platform == Platform::Windows)
{
project.compile.addDefines({"IMGUI_API=__declspec( dllexport )"});
}
else
{
project.compile.addDefines({"IMGUI_API=__attribute__((visibility(\"default\")))"});
}
project.addDirectory("Examples/SCExample", "**.h");
project.addDirectory("Examples/SCExample", "**.cpp");
return Result(true);
}
Result configure(Definition& definition, const Parameters& parameters)
{
Workspace workspace = {"SCTest"};
SC_TRY(workspace.projects.resize(2));
SC_TRY(buildTestProject(parameters, workspace.projects[0]));
SC_TRY(buildExampleProject(parameters, workspace.projects[1]));
definition.workspaces.push_back(
move(workspace));
return Result(true);
}
Result executeAction(const Action& action) { return Build::Action::execute(action, configure, TEST_PROJECT_NAME); }
}
}
#define SC_COMPILER_WARNING_POP
Pops warning from inside a macro.
Definition: Compiler.h:107
#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT
Disables unused-result warning (due to ignoring a return value marked as [[nodiscard]])
Definition: Compiler.h:146
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition: Compiler.h:269
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition: Result.h:48
@ Debug
Debug configuration.
@ Release
Release configuration.
@ DebugCoverage
Debug coverage configuration.
@ VisualStudio2022
Generate projects for Visual Studio 2022.
Definition: Build.h:82
@ guiApplication
gui application
Definition: Build.h:201
@ Executable
Create executable program.
Definition: Build.h:334
static bool relativeFromTo(StringView source, StringView destination, String &output, Type type, Type outputType=AsNative)
Get relative path that appended to source resolves to destination.
This is the list of videos that have been recorded showing some of the internal thoughts that have been going into this library:
So far the entire build configuration is created in C++ but each invocation with a different set of "build parameters" it's building a data structure that is free of conditionals, as they've been evaluated by the imperative code. Such "post-configure" build settings could be serialized to JSON (or using binary Serialization) or to any other declarative format if needed.