Sane C++ Libraries
C++ Platform Abstraction Libraries
Build

🟥 Minimal build system where builds are described in C++

Build uses C++ to imperatively describe a sequence of build operations.

Features

  • Describe builds in a cpp file
  • Generate XCode 14 console Projects
  • Generate Visual Studio 2022 console Projects

Status

🟥 Draft
Build currently used to generate test projects of this repository but still not mature enough to be used for anything else.

Description

Build C++ files (named by convention SC-build.cpp) are compiled the fly and they generate project files for existing build systems.
In the future the plan is to allow also the system to run standalone directly invoking compilers to produce libraries and executables. Projects are generated by invoking ./SC.sh build or SC.bat build.

Note
Check the Tools page for more details on SC.sh build.

This is for example the Tools/SC-build.cpp file for the test suite:

// Copyright (c) Stefano Cristiano
// SPDX-License-Identifier: MIT
#include "SC-build.h"
#include "Libraries/Strings/StringBuilder.h"
namespace SC
{
namespace Build
{
static constexpr StringView PROJECT_NAME = "SCTest";
Result configure(Build::Definition& definition, Build::Parameters& parameters)
{
SC_COMPILER_WARNING_PUSH_UNUSED_RESULT; // Doing some optimistic coding here, ignoring all failures
// Workspace
Workspace workspace;
workspace.name.assign(PROJECT_NAME);
// Project
Project project;
project.targetType = TargetType::Executable;
project.name.assign(PROJECT_NAME);
project.targetName.assign(PROJECT_NAME);
// All relative paths are evaluated from this project root directory.
project.setRootDirectory(parameters.directories.libraryDirectory.view());
// Project Configurations
project.addPresetConfiguration(Configuration::Preset::Debug);
project.addPresetConfiguration(Configuration::Preset::Release);
if (parameters.generator == Build::Generator::VisualStudio2022)
{
project.addPresetConfiguration(Configuration::Preset::Debug, "Debug Clang");
project.getConfiguration("Debug Clang")->visualStudio.platformToolset = "ClangCL";
}
else
{
project.addPresetConfiguration(Configuration::Preset::DebugCoverage);
}
// Project Configurations special flags
for (Configuration& config : project.configurations)
{
config.compile.set<Compile::enableASAN>(config.preset == Configuration::Preset::Debug);
}
// Defines
// $(PROJECT_ROOT) is the same directory set with Project::setRootDirectory
project.compile.addDefines({"SC_LIBRARY_PATH=$(PROJECT_ROOT)", "SC_COMPILER_ENABLE_CONFIG=1"});
// Includes
project.compile.addIncludes({
".", // Libraries path (for PluginTest)
"Tests/SCTest", // SCConfig.h path (enabled by SC_COMPILER_ENABLE_CONFIG == 1)
});
// Libraries to link
if (parameters.platforms.contains(Build::Platform::MacOS))
{
project.link.addFrameworks({"CoreFoundation", "CoreServices"});
}
// File overrides (order matters regarding to add / remove)
project.addDirectory("Bindings/c", "**.cpp"); // add all cpp support files for c bindings
project.addDirectory("Bindings/c", "**.c"); // add all c bindings
project.addDirectory("Bindings/c", "**.h"); // add all c bindings
project.addDirectory("Tests/SCTest", "*.cpp"); // add all .cpp from SCTest directory
project.addDirectory("Tests/SCTest", "*.h"); // add all .h from SCTest directory
project.addDirectory("Libraries", "**.cpp"); // recursively add all cpp files
project.addDirectory("Libraries", "**.h"); // recursively add all header files
project.addDirectory("Libraries", "**.inl"); // recursively add all inline files
project.addDirectory("LibrariesExtra", "**.h"); // recursively add all header files
project.addDirectory("LibrariesExtra", "**.cpp"); // recursively add all cpp files
project.addDirectory("Support/DebugVisualizers", "*.cpp"); // add debug visualizers
project.addDirectory("Tools", "SC-*.cpp"); // add all tools
project.addDirectory("Tools", "*.h"); // add tools headers
project.addDirectory("Tools", "*Test.cpp"); // add tools tests
// Debug visualization helpers
if (parameters.generator == Build::Generator::VisualStudio2022)
{
project.addDirectory("Support/DebugVisualizers/MSVC", "*.natvis");
}
else
{
project.addDirectory("Support/DebugVisualizers/LLDB", "*");
}
// Adding to workspace and definition
workspace.projects.push_back(move(project));
definition.workspaces.push_back(move(workspace));
return Result(true);
}
Result executeAction(const Action& action) { return Build::Action::execute(action, configure, PROJECT_NAME); }
} // namespace Build
} // namespace SC
#define SC_COMPILER_WARNING_POP
Pops warning from inside a macro.
Definition: Compiler.h:104
#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT
Disables unused-result warning (due to ignoring a return value marked as [[nodiscard]])
Definition: Compiler.h:143
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition: Compiler.h:247
@ enableASAN
Address Sanitizer.
Definition: Build.h:132
@ Debug
Debug configuration.
@ Release
Release configuration.
@ DebugCoverage
Debug coverage configuration.
@ VisualStudio2022
Generate projects for Visual Studio 2022.
Definition: Build.h:84
@ Executable
Create executable program.
Definition: Build.h:328

The abstraction is described by the following (top-down) hierarchy:

Class Description
SC::Build::Definition Top level build description holding all Workspace objects.
SC::Build::Workspace Groups multiple Project together with shared compile and link flags.
SC::Build::Project Groups multiple Configuration and source files with their compile and link flags.
SC::Build::Configuration Groups SC::Build::CompileFlags and SC::Build::LinkFlags for a given SC::Build::Architecture.

Some additional types allow describing detailed properties of the build:

Class Description
SC::Build::Platform Build Platform (Operating System)
SC::Build::Architecture Build Architecture (Processor / Instruction set)
SC::Build::Generator Build system generator (Xcode / Visual Studio)
SC::Build::Optimization Optimization level (Debug / Release)
SC::Build::Compile Compilation switches (include paths, preprocessor defines, etc.)
SC::Build::CompileFlags Map of SC::Build::Compile flags (include paths, preprocessor defines etc.)
SC::Build::Link Linking switches (library paths, LTO etc.)
SC::Build::LinkFlags Map of SC::Build::Link flags (library paths, LTO switch etc.)

Architecture

Note
Check the Tools page for more details on SC.sh build.

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.

Roadmap

🟨 MVP Features:

  • Build non-console type projects
  • Build artifacts invoking with direct compiler invocation (bypass XCode / VisualStudio build systems)

🟩 Usable Features:

  • Describe more project types (dynamic libraries, static libraries etc.)
  • Describe dependencies between targets
  • Allow nested builds (where the root script should compile child scripts found down the path)

🟦 Complete Features:

  • Generate one click ready to debug projects for build itself
  • Describe very complex builds (this will be probably only doable porting makefiles of some external library)

💡 Unplanned Features:

  • Compile scripts to WASM so that they can't run arbitrary code