#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");
if (parameters.platform == Platform::Apple)
{
project.addLinkFrameworks({"CoreFoundation", "CoreServices", "CFNetwork", "Foundation"});
}
if (parameters.platform == Platform::Windows)
{
project.addLinkLibraries({"Advapi32"});
}
else
{
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";
static constexpr StringView BUILD_TEST_PROJECT_NAME = "SCBuildTest";
Result configureTests(const Parameters& parameters, Workspace& workspace)
{
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/.*\\.*|"
".*\\/Extra/Deprecated/.*\\.*";
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.removeFiles("Tests/Libraries/Build", "BuildTest.cpp");
project.addFiles("Tests/Support", "**.cpp");
project.addFiles("Tests/Tools", "**.cpp");
project.addFiles("Tools", "SC-*.cpp");
project.addFiles("Tools", "*.h");
if (not project.addExportLibraries({"Foundation", "Memory", "Strings", "Containers"}))
{
return Result::Error("Failed to configure exported SCTest libraries");
}
project.link.preserveExportedSymbols = true;
project.addFiles("Extra/Deprecated/Tests", "**.cpp");
project.addFiles("Extra/Deprecated/Libraries", "**.h");
project.addFiles("Extra/Deprecated/Libraries", "**.cpp");
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);
SC_TRY(workspace.projects.push_back(
move(project)));
return Result(true);
}
Result configureSCBuildTest(const Parameters& parameters, Workspace& workspace)
{
Project project = {TargetType::ConsoleExecutable, BUILD_TEST_PROJECT_NAME};
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
project.addDefines({"SC_LIBRARY_PATH=$(PROJECT_ROOT)", "SC_COMPILER_ENABLE_CONFIG=1"});
project.addIncludePaths({
".",
"Tests/SCBuildTest",
});
addSaneCppLibraries(project, parameters);
project.addFiles("Tests/SCBuildTest", "*.cpp");
project.addFiles("Tests/SCBuildTest", "*.h");
project.addFiles("Tests/Libraries/Build", "BuildTest.cpp");
project.addFiles("Tools", "SC-*.cpp");
project.addFiles("Tools", "*.h");
SC_TRY(workspace.projects.push_back(
move(project)));
return Result(true);
}
Result configureSCSharedLibrary(const Parameters& parameters, Workspace& workspace)
{
Project project = {TargetType::SharedLibrary, "SC"};
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
project.addIncludePaths({"."});
addSaneCppLibraries(project, parameters);
SC_TRY_MSG(project.addExportAllLibraries(),
"Failed to configure exported Sane C++ libraries");
SC_TRY(workspace.projects.push_back(
move(project)));
return Result(true);
}
Result configureTestSTLInterop(const Parameters& parameters, Workspace& workspace)
{
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");
workspace.projects.push_back(
move(project));
return Result(true);
}
static constexpr StringView EXAMPLE_PROJECT_NAME = "SCExample";
Result configureExamplesGUI(const Parameters& parameters, Workspace& workspace)
{
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()});
project.addExportAllLibraries();
SC_TRY(project.addExportDirectories({imgui.packageLocalDirectory.view()}));
project.link.preserveExportedSymbols = true;
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");
if (not project.addExportLibraries({"Async", "Containers", "ContainersReflection", "File", "FileSystem",
"Foundation", "Http", "Memory", "Plugin", "Process", "Reflection",
"SerializationBinary", "SerializationText", "Socket", "Strings", "Threading"}))
{
return Result::Error("Failed to configure exported SCExample libraries");
}
SC_TRY(workspace.projects.push_back(
move(project)));
return Result(true);
}
Result configureExamplesConsole(const Parameters& parameters, Workspace& workspace)
{
FileSystemIterator::FolderState entries[2];
FileSystemIterator fsi;
String path;
SC_TRY(Path::join(path, {parameters.directories.libraryDirectory.view(),
"Examples"}));
fsi.init(path.view(), entries);
while (fsi.enumerateNext())
{
FileSystemIterator::Entry entry = fsi.get();
if (not entry.isDirectory() or entry.name == EXAMPLE_PROJECT_NAME)
continue;
StringView name, extension;
SC_TRY(Path::parseNameExtension(entry.name, name, extension));
Project project;
project.targetType = TargetType::ConsoleExecutable;
project.name = name;
project.targetName = name;
project.setRootDirectory(parameters.directories.libraryDirectory.view());
project.addPresetConfiguration(Configuration::Preset::Debug, parameters);
project.addPresetConfiguration(Configuration::Preset::Release, parameters);
#if 0
addSaneCppLibraries(project, parameters);
#else
project.addFile("SC.cpp");
if (parameters.platform == Platform::Apple)
{
project.addLinkFrameworks({"CoreFoundation", "CoreServices"});
}
if (parameters.platform != Platform::Windows)
{
project.addLinkLibraries({"dl", "pthread"});
}
#endif
project.addFiles(entry.path, "**.cpp");
workspace.projects.push_back(
move(project));
}
return Result(true);
}
Result configureSingleFileLibs(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 = "SCWorkspace";
Result configure(Definition& definition, const Parameters& parameters)
{
Workspace defaultWorkspace = {DEFAULT_WORKSPACE};
SC_TRY(configureTests(parameters, defaultWorkspace));
SC_TRY(configureSCBuildTest(parameters, defaultWorkspace));
SC_TRY(configureSCSharedLibrary(parameters, defaultWorkspace));
SC_TRY(configureTestSTLInterop(parameters, defaultWorkspace));
SC_TRY(configureExamplesConsole(parameters, defaultWorkspace));
SC_TRY(configureExamplesGUI(parameters, defaultWorkspace));
definition.workspaces.push_back(
move(defaultWorkspace));
(void)configureSingleFileLibs(definition, parameters);
return Result(true);
}
Result executeAction(const Action& action) { return Build::Action::execute(action, configure, DEFAULT_WORKSPACE); }
}
}
#define SC_COMPILER_WARNING_POP
Pops warning from inside a macro.
Definition Compiler.h:120
#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT
Disables unused-result warning (due to ignoring a return value marked as [[nodiscard]])
Definition Compiler.h:155
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:274
#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:60
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition Result.h:49
This is the list of videos that have been recorded showing some of the internal thoughts that have been going into this library: