#include "SC-build.h"
#include "../Libraries/FileSystemIterator/FileSystemIterator.h"
#include "SC-build/Build.inl"
namespace SC
{
namespace Tools
{
Result installSokol(const Build::Directories& directories, Package& package)
{
Download download;
download.packagesCacheDirectory = directories.packagesCacheDirectory;
download.packagesInstallDirectory = directories.packagesInstallDirectory;
download.packageName = "sokol";
download.packageVersion = "d5863cb";
download.shallowClone = "d5863cb78ea1552558c81d6db780dfcec49557ce";
download.url = "https://github.com/floooh/sokol.git";
download.isGitClone = true;
download.createLink = false;
package.packageBaseName = "sokol";
CustomFunctions functions;
functions.testFunction = &verifyGitCommitHashCache;
SC_TRY(packageInstall(download, package, functions));
return Result(true);
}
Result installDearImGui(const Build::Directories& directories, Package& package)
{
Download download;
download.packagesCacheDirectory = directories.packagesCacheDirectory;
download.packagesInstallDirectory = directories.packagesInstallDirectory;
download.packageName = "dear-imgui";
download.packageVersion = "af987eb";
download.url = "https://github.com/ocornut/imgui.git";
download.shallowClone = "af987eb1176fb4c11a6f0a4f2550d9907d113df5";
download.isGitClone = true;
download.createLink = false;
package.packageBaseName = "dear-imgui";
CustomFunctions functions;
functions.testFunction = &verifyGitCommitHashCache;
SC_TRY(packageInstall(download, package, functions));
return Result(true);
}
}
namespace Build
{
void addSaneCppLibraries(Project& project, const Parameters& parameters)
{
project.addFiles("Libraries", "**.cpp");
project.addFiles("Libraries", "**.h");
project.addFiles("Libraries", "**.inl");
project.addFiles("LibrariesExtra", "**.h");
project.addFiles("LibrariesExtra", "**.cpp");
if (parameters.platform == Platform::Apple)
{
project.addLinkFrameworks({"CoreFoundation", "CoreServices"});
}
if (parameters.platform != Platform::Windows)
{
project.addLinkLibraries({"dl", "pthread"});
}
if (parameters.generator == Generator::VisualStudio2022)
{
project.addFiles("Support/DebugVisualizers/MSVC", "*.natvis");
}
else
{
project.addFiles("Support/DebugVisualizers/LLDB", "*");
}
}
static constexpr StringView TEST_PROJECT_NAME = "SCTest";
Result buildTestProject(const Parameters& parameters, Project& project)
{
project = {TargetType::ConsoleExecutable, TEST_PROJECT_NAME};
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
project.addPresetConfiguration(Configuration::Preset::DebugCoverage, parameters);
project.configurations.back().coverage.excludeRegex =
".*\\/Tools.*|"
".*\\Test.(cpp|h|c)|"
".*\\test.(c|h)|"
".*\\/Tests/.*\\.*|"
".*\\/LibC\\+\\+.inl|"
".*\\/Assert.h|"
".*\\/PluginMacros.h|"
".*\\/ProcessPosixFork.inl|"
".*\\/EnvironmentTable.h|"
".*\\/InitializerList.h|"
".*\\/Reflection/.*\\.*|"
".*\\/ContainersReflection/.*\\.*|"
".*\\/SerializationBinary/.*\\.*|"
".*\\/LibrariesExtra/.*\\.*";
if (parameters.platform == Platform::Linux)
{
project.addPresetConfiguration(Configuration::Preset::Debug, parameters, "DebugValgrind");
project.configurations.back().compile.enableASAN = false;
project.configurations.back().link.enableASAN = false;
}
project.addDefines({"SC_LIBRARY_PATH=$(PROJECT_ROOT)", "SC_COMPILER_ENABLE_CONFIG=1"});
project.addIncludePaths({
".",
"Tests/SCTest",
});
addSaneCppLibraries(project, parameters);
project.addFiles("Tests/SCTest", "*.cpp");
project.addFiles("Tests/SCTest", "*.h");
project.addFiles("Tests/Libraries", "**.c*");
project.addFiles("Tests/Libraries", "**.inl");
project.addFiles("Tests/LibrariesExtra", "**.cpp");
project.addFiles("Tests/Support", "**.cpp");
project.addFiles("Tests/Tools", "**.cpp");
project.addFiles("Tools", "SC-*.cpp");
project.addFiles("Tools", "*.h");
SourceFiles specificFiles;
specificFiles.addSelection("Tests/SCTest", "*.cpp");
specificFiles.removeSelection("Tests/SCTest", "SCTest.cpp");
specificFiles.compile.addDefines({"SC_SPACES_SPECIFIC_DEFINE=1"});
specificFiles.compile.addIncludePaths({"../Directory With Spaces"});
specificFiles.compile.disableWarnings({4100});
specificFiles.compile.disableWarnings({"unused-parameter"});
specificFiles.compile.disableClangWarnings({"reserved-user-defined-literal"});
project.addSpecificFileFlags(specificFiles);
return Result(true);
}
Result buildInteropSTL(const Parameters& parameters, Project& project)
{
project = {TargetType::ConsoleExecutable, "InteropSTL"};
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
project.files.compile.enableStdCpp = true;
project.files.compile.enableExceptions = true;
project.files.compile.enableRTTI = true;
project.files.compile.cppStandard = CppStandard::CPP17;
project.addDefines({"SC_COMPILER_ENABLE_STD_CPP=1"});
project.addIncludePaths({
".",
});
addSaneCppLibraries(project, parameters);
project.addFiles("Tests/InteropSTL", "*.cpp");
project.addFiles("Tests/InteropSTL", "*.h");
return Result(true);
}
static constexpr StringView EXAMPLE_PROJECT_NAME = "SCExample";
Result buildExampleProject(const Parameters& parameters, Project& project)
{
project = {TargetType::GUIApplication, EXAMPLE_PROJECT_NAME};
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.iconPath = "Documentation/Doxygen/SC.svg";
Tools::Package sokol;
SC_TRY(Tools::installSokol(parameters.directories, sokol));
Tools::Package imgui;
SC_TRY(Tools::installDearImGui(parameters.directories, imgui));
project.addIncludePaths({".", sokol.packageLocalDirectory.view(), imgui.packageLocalDirectory.view()});
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
project.addPresetConfiguration(Configuration::Preset::DebugCoverage, parameters);
addSaneCppLibraries(project, parameters);
project.addFiles(imgui.packageLocalDirectory.view(), "*.cpp");
project.addFiles(sokol.packageLocalDirectory.view(), "*.h");
String imguiRelative, imguiDefine;
SC_TRY(Path::relativeFromTo(imguiRelative, project.rootDirectory.view(), imgui.packageLocalDirectory.view(),
Path::AsNative));
SC_TRY(StringBuilder::format(imguiDefine,
"SC_IMGUI_PATH=$(PROJECT_ROOT)/{}", imguiRelative));
project.addDefines({"SC_LIBRARY_PATH=$(PROJECT_ROOT)", imguiDefine.view()});
if (parameters.platform == Platform::Apple)
{
project.addFiles("Examples/SCExample", "*.m");
project.addLinkFrameworks({"Metal", "MetalKit", "QuartzCore"});
project.addLinkFrameworksMacOS({"Cocoa"});
project.addLinkFrameworksIOS({"UIKit", "Foundation"});
}
else
{
project.addFiles("Examples/SCExample", "*.c");
if (parameters.platform == Platform::Linux)
{
project.addLinkLibraries({"GL", "EGL", "X11", "Xi", "Xcursor"});
}
}
if (parameters.platform == Platform::Windows)
{
project.addDefines({"IMGUI_API=__declspec( dllexport )"});
}
else
{
project.addDefines({"IMGUI_API=__attribute__((visibility(\"default\")))"});
}
project.addFiles("Examples/SCExample", "**.h");
project.addFiles("Examples/SCExample", "**.cpp");
return Result(true);
}
Result buildSingleFileLibs(Definition& definition, const Parameters& parameters)
{
Workspace workspace = {"SCSingleFileLibs"};
FileSystemIterator::FolderState entries[1];
FileSystemIterator fsi;
String path;
SC_TRY(Path::join(path, {parameters.directories.libraryDirectory.view(),
"_Build",
"_SingleFileLibrariesTest"}));
SC_TRY_MSG(fsi.init(path.view(), entries),
"Cannot access _Build/_SingleFileLibrariesTest");
while (fsi.enumerateNext())
{
StringView name, extension;
SC_TRY(Path::parseNameExtension(fsi.get().name, name, extension));
if (extension != "cpp" or not name.startsWith("Test_"))
continue;
Project project;
project.targetType = TargetType::ConsoleExecutable;
project.name = name;
project.targetName = project.name;
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
project.addDefines({"SC_COMPILER_ENABLE_STD_CPP=1"});
project.configurations[0].compile.enableStdCpp = true;
project.configurations[1].compile.enableStdCpp = true;
project.addIncludePaths({"_Build/_SingleFileLibraries"});
project.addFile(fsi.get().path);
if (parameters.platform == Platform::Apple)
{
project.addLinkFrameworks({"CoreFoundation", "CoreServices"});
}
if (parameters.platform != Platform::Windows)
{
project.addLinkLibraries({"dl", "pthread"});
}
workspace.projects.push_back(
move(project));
}
definition.workspaces.push_back(
move(workspace));
return Result(true);
}
static constexpr StringView DEFAULT_WORKSPACE_NAME = "SCWorkspace";
Result configure(Definition& definition, const Parameters& parameters)
{
Workspace workspace = {DEFAULT_WORKSPACE_NAME};
SC_TRY(workspace.projects.resize(3));
SC_TRY(buildTestProject(parameters, workspace.projects[0]));
SC_TRY(buildExampleProject(parameters, workspace.projects[1]));
SC_TRY(buildInteropSTL(parameters, workspace.projects[2]))
definition.workspaces.push_back(move(workspace));
(void)buildSingleFileLibs(definition, parameters);
return Result(true);
}
Result executeAction(const Action& action) { return Build::Action::execute(action, configure, DEFAULT_WORKSPACE_NAME); }
}
}
#define SC_COMPILER_WARNING_POP
Pops warning from inside a macro.
Definition Compiler.h:110
#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT
Disables unused-result warning (due to ignoring a return value marked as [[nodiscard]])
Definition Compiler.h:145
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:264
#define SC_TRY_MSG(expression, failedMessage)
Checks the value of the given expression and if failed, returns a result with failedMessage to caller...
Definition Result.h:59
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition Result.h:48
With any other debugger or IDE other than vscode, after 1. just debug _Build/_Tools/Windows/SC-build.exe (or the equivalent on other platform) with similar arguments as passed by the vscode task (replace ${workspaceFolder} with the path where Sane C++ Libraries are located). The first argument is the path to SC Libraries, then you have the tools directory and the directory of the build outputs. As forth argument you have the name of the tool (build for SC-Build) and then any custom argument to the tool (configure, SCTest in the example below)
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.