Add project

This commit is contained in:
2026-06-28 05:50:35 -04:00
commit 1671aca835
10 changed files with 889 additions and 0 deletions

357
.clang-format Normal file
View File

@@ -0,0 +1,357 @@
---
Language: Cpp
AlignAfterOpenBracket: true
AccessModifierOffset: -1
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowBreakBeforeQtProperty: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AttributeMacros:
- __capability
- absl_nonnull
- absl_nullable
- absl_nullability_unknown
BinPackArguments: true
BinPackLongBracedList: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BracedInitializerIndentWidth: -1
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterOpenBracketBracedList: false
BreakAfterOpenBracketFunction: false
BreakAfterOpenBracketIf: false
BreakAfterOpenBracketLoop: false
BreakAfterOpenBracketSwitch: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeCloseBracketBracedList: false
BreakBeforeCloseBracketFunction: false
BreakBeforeCloseBracketIf: false
BreakBeforeCloseBracketLoop: false
BreakBeforeCloseBracketSwitch: false
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: false
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: Yes
ColumnLimit: 80
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
#Cpp11BracedListStyle: AlignFirstComment
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
EnumTrailingComma: Leave
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: "^<.*"
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ".*"
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: "([-_](test|unittest))?$"
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigitsInsert: 0
BinaryMaxDigitsRemove: 0
Decimal: 0
DecimalMinDigitsInsert: 0
DecimalMaxDigitsRemove: 0
Hex: 0
HexMinDigitsInsert: 0
HexMaxDigitsRemove: 0
BinaryMinDigits: 0
DecimalMinDigits: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ""
MacroBlockEnd: ""
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
NumericLiteralCase:
ExponentLetter: Leave
HexDigit: Leave
Prefix: Leave
Suffix: Leave
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
OneLineFormatOffRegex: ""
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- "c++"
- "C++"
CanonicalDelimiter: ""
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: pb
BasedOnStyle: google
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes:
Enabled: true
IgnoreCase: false
IgnoreExtension: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterNot: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBraces: Never
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...

3
.clangd Normal file
View File

@@ -0,0 +1,3 @@
CompileFlags:
Add: -Wno-unknown-warning-option
Remove: [-m*, -f*]

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build/
.idea
build_script
build_script.exe

31
CMakeLists.txt Normal file
View File

@@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 4.2)
project(build_script)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
file(GLOB REQUIRED_CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.required.cmake")
foreach (cmake_file ${REQUIRED_CMAKE_FILES})
include(${cmake_file})
endforeach ()
file(GLOB CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.cmake")
foreach (cmake_file ${CMAKE_FILES})
include(${cmake_file})
endforeach ()
include_directories(src/)
file(GLOB_RECURSE SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
file(GLOB_RECURSE HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEADER_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC
"${structops_SOURCE_DIR}/include"
"${spdlog_SOURCE_DIR}/include"
)
target_link_libraries(${PROJECT_NAME} PUBLIC
structopt
spdlog
)

24
cmake/CPM.cmake Normal file
View File

@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.42.1)
set(CPM_HASH_SUM "f3a6dcc6a04ce9e7f51a127307fa4f699fb2bade357a8eb4c5b45df76e1dc6a5")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})

View File

@@ -0,0 +1,14 @@
##### SETUP COMPILE COMMANDS #####
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_EXPORT_COMPILE_COMMANDS on)
endif()
if(EXISTS "${CMAKE_BINARY_DIR}/compile_commands.json")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
file(
COPY "${CMAKE_BINARY_DIR}/compile_commands.json"
DESTINATION "${CMAKE_BINARY_DIR}/../"
)
endif()
endif()

10
cmake/platform.cmake Normal file
View File

@@ -0,0 +1,10 @@
message("System name: ${CMAKE_HOST_SYSTEM_NAME}")
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
add_compile_definitions(PLATFORM_WINDOWS)
elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
add_compile_definitions(PLATFORM_LINUX)
elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin")
add_compile_definitions(PLATFORM_MACOS)
else()
add_compile_definitions(PLATFORM_UNKNOWN)
endif()

3
cmake/spdlog.cmake Normal file
View File

@@ -0,0 +1,3 @@
CPMAddPackage(
URI "gh:gabime/spdlog@1.17.0"
)

5
cmake/structopt.cmake Normal file
View File

@@ -0,0 +1,5 @@
CPMAddPackage(
URI "gh:p-ranav/structopt@0.1.3"
OPTIONS "STRUCTOPT_TESTS off"
OPTIONS "STRUCTOPT_SAMPLES off"
)

437
src/main.cpp Normal file
View File

@@ -0,0 +1,437 @@
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#include <filesystem>
#include <iostream>
#include <string>
#include <structopt/app.hpp>
#ifdef _WIN32
#define popen _popen
#define pclose _pclose
#endif
enum Command {
build,
configure,
clean,
del,
rebuild,
};
enum BuildType {
none,
debug,
release,
relwithdeb,
};
struct Options {
Command command;
std::optional<BuildType> buildType = BuildType::none;
std::optional<bool> verbose = false;
std::optional<bool> dryrun = false;
};
STRUCTOPT(Options, command, buildType, verbose, dryrun);
bool g_DryRun = false;
void initLogging() {
spdlog::init_thread_pool(8192, 1);
spdlog::flush_every(std::chrono::seconds(1));
}
void createLogger(const char* name, const char* filename, const bool verbose) {
std::vector<spdlog::sink_ptr> sinks;
const auto stdout_sink =
std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
stdout_sink->set_level(spdlog::level::debug);
stdout_sink->set_pattern("%^[%D %r %z] [%n] [%l] %v%$");
sinks.push_back(stdout_sink);
if (filename != nullptr) {
const auto file_sink =
std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename);
file_sink->set_level(spdlog::level::debug);
file_sink->set_pattern("[%D %r %z] [%n] [%l] %v");
sinks.push_back(file_sink);
}
const auto logger = std::make_shared<spdlog::async_logger>(
name, sinks.begin(), sinks.end(), spdlog::thread_pool(),
spdlog::async_overflow_policy::block);
logger->flush_on(spdlog::level::warn);
#ifdef DEBUG
logger->set_level(spdlog::level::debug);
#else
if (verbose)
logger->set_level(spdlog::level::debug);
else
logger->set_level(spdlog::level::info);
#endif
spdlog::register_logger(logger);
}
void deleteDir(const std::filesystem::path& path) {
if (g_DryRun) {
spdlog::get("filesystem")
->warn("[DRYRUN] Deleting '{}'", path.string());
return;
}
spdlog::get("filesystem")->warn("DELETING '{}' directory.", path.string());
spdlog::get("filesystem")->debug("Checking '{}'", path.string());
if (!std::filesystem::exists(path) ||
!std::filesystem::is_directory(path)) {
spdlog::get("filesystem")
->info(
"The {} directory either doesn't exist or its a file. "
"Continuing...",
path.string());
return;
}
spdlog::get("filesystem")->debug("Deleting '{}'", path.string());
std::filesystem::remove_all(path);
}
void createDir(const std::filesystem::path& path) {
if (g_DryRun) {
spdlog::get("filesystem")
->warn("[DRYRUN] Creating '{}'", path.string());
return;
}
spdlog::get("filesystem")->debug("Creating '{}'", path.string());
if (const bool res = std::filesystem::create_directories(path); !res) {
spdlog::get("filesystem")
->warn("Failed to create directory: '{}'", path.string());
}
}
void checkBuildDirs(const BuildType buildType) {
spdlog::get("filesystem")->debug("Checking 'build' directory.");
if (!std::filesystem::is_directory("build")) {
spdlog::get("filesystem")
->warn("'build' is not a directory. Deleting.");
deleteDir("build");
}
if (!std::filesystem::exists("build")) {
spdlog::get("filesystem")->info("Creating 'build' directory");
createDir("build");
}
switch (buildType) {
case none:
spdlog::get("filesystem")
->debug("Checking 'build/debug' directory.");
if (!std::filesystem::is_directory("build/debug")) {
spdlog::get("filesystem")
->warn("'build/debug' is not a directory. Deleting.");
deleteDir("build/debug");
}
if (!std::filesystem::exists("build/debug")) {
spdlog::get("filesystem")
->info("Creating 'build/debug' directory.");
createDir("build/debug");
}
spdlog::get("filesystem")
->debug("Checking 'build/release' directory.");
if (!std::filesystem::is_directory("build/release")) {
spdlog::get("filesystem")
->warn("'build/release' is not a directory. Deleting.");
deleteDir("build/release");
}
if (!std::filesystem::exists("build/release")) {
spdlog::get("filesystem")
->info("Creating 'build/release' directory.");
createDir("build/release");
}
spdlog::get("filesystem")
->debug("Checking 'build/relwithdeb' directory.");
if (!std::filesystem::is_directory("build/relwithdeb")) {
spdlog::get("filesystem")
->warn("'build/relwithdeb' is not a directory. Deleting.");
deleteDir("build/relwithdeb");
}
if (!std::filesystem::exists("build/relwithdeb")) {
spdlog::get("filesystem")
->info("Creating 'build/relwithdeb' directory.");
createDir("build/relwithdeb");
}
break;
case debug:
spdlog::get("filesystem")
->debug("Checking 'build/debug' directory.");
if (!std::filesystem::is_directory("build/debug")) {
spdlog::get("filsystem")
->warn("'build/debug' is not a directory. Deleting.");
deleteDir("build/debug");
}
if (!std::filesystem::exists("build/debug")) {
spdlog::get("filesystem")
->info("Creating 'build/debug' directory.");
createDir("build/debug");
}
break;
case release:
spdlog::get("filesystem")
->debug("Checking 'build/release' directory.");
if (!std::filesystem::is_directory("build/release")) {
spdlog::get("filesystem")
->warn("'build/release' is not a directory. Deleting.");
deleteDir("build/release");
}
if (!std::filesystem::exists("build/release")) {
spdlog::get("filesystem")
->info("Creating 'build/release' directory.");
createDir("build/release");
}
break;
case relwithdeb:
spdlog::get("filesystem")
->debug("Checking 'build/relwithdeb' directory.");
if (!std::filesystem::is_directory("build/relwithdeb")) {
spdlog::get("filesystem")
->warn("'build/relwithdeb' is not a directory. Deleting.");
deleteDir("build/relwithdeb");
}
if (!std::filesystem::exists("build/relwithdeb")) {
spdlog::get("filesystem")
->info("Creating 'build/relwithdeb' directory.");
createDir("build/relwithdeb");
};
}
spdlog::get("filesystem")->info("All directories checked.");
}
int runCmd(std::string cmd) {
if (g_DryRun) {
spdlog::get("cmd")->warn("[DRYRUN] Running '{}'", cmd);
return 0;
}
spdlog::get("cmd")->debug("Running '{}'", cmd);
spdlog::get("cmd")->debug("Opening pipe");
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) {
spdlog::get("cmd")->warn("Failed to start the process");
return 1;
}
spdlog::get("cmd")->debug("Buffering and offloading pipe");
std::array<char, 256> buffer;
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
std::cout << buffer.data() << std::flush;
}
spdlog::get("filesystem")->debug("Closing pipe");
int exitCode = pclose(pipe);
spdlog::get("cmd")->info("Process ended with exit code: {}", exitCode);
return exitCode;
}
void buildDir(const std::filesystem::path& path) {
if (g_DryRun) {
spdlog::get("build")->warn("[DRYRUN] Building '{}'", path.string());
return;
}
spdlog::get("build")->info("Building '{}'", path.string());
if (int exitCode = runCmd(std::format("cd {} && ninja", path.string()));
exitCode != 0) {
spdlog::get("build")->critical("Command exited with exit code: {}",
exitCode);
exit(EXIT_FAILURE);
}
}
void configureDir(const std::filesystem::path& path, std::string buildStr) {
if (g_DryRun) {
spdlog::get("configure")
->warn("[DRYRUN] Configuring '{}'", path.string());
return;
}
spdlog::get("configure")->info("Configuring '{}'", path.string());
if (int exitCode = runCmd(
std::format("cd {} && cmake ../../ -G Ninja -DCMAKE_BUILD_TYPE={}",
path.string(), buildStr));
exitCode != 0) {
spdlog::get("configure")
->critical("Command exited with exit code: {}", exitCode);
exit(EXIT_FAILURE);
}
}
void cleanDir(const std::filesystem::path& path) {
if (g_DryRun) {
spdlog::get("clean")->warn("[DRYRUN] Cleaning '{}'", path.string());
return;
}
spdlog::get("clean")->info("Cleaning '{}'", path.string());
if (int exitCode =
runCmd(std::format("cd {} && cmake clean", path.string()));
exitCode != 0) {
spdlog::get("clean")->critical("Command exited with exit code: {}",
exitCode);
exit(EXIT_FAILURE);
}
}
void buildProject(const BuildType buildType) {
checkBuildDirs(buildType);
switch (buildType) {
case none:
configureDir("build/debug", "Debug");
buildDir("build/debug");
configureDir("build/release", "Release");
buildDir("build/release");
configureDir("build/relwithdeb", "RelWithDeb");
buildDir("build/relwithdeb");
break;
case debug:
configureDir("build/debug", "Debug");
buildDir("build/debug");
break;
case release:
configureDir("build/release", "Release");
buildDir("build/release");
break;
case relwithdeb:
configureDir("build/relwithdeb", "RelWithDeb");
buildDir("build/relwithdeb");
break;
}
}
void configureProject(const BuildType buildType) {
checkBuildDirs(buildType);
switch (buildType) {
case none:
configureDir("build/debug", "Debug");
configureDir("build/release", "Release");
configureDir("build/relwithdeb", "RelWithDeb");
break;
case debug:
configureDir("build/debug", "Debug");
break;
case release:
configureDir("build/release", "Release");
break;
case relwithdeb:
configureDir("build/RelWithDeb", "RelWithDeb");
break;
}
}
void cleanProject(const BuildType buildType) {
checkBuildDirs(buildType);
switch (buildType) {
case none:
cleanDir("build/debug");
cleanDir("build/release");
cleanDir("build/relwithdeb");
break;
case debug:
cleanDir("build/debug");
break;
case release:
cleanDir("build/release");
break;
case relwithdeb:
cleanDir("build/RelWithDeb");
break;
}
}
void deleteProject(const BuildType buildType) {
switch (buildType) {
case none:
deleteDir("build");
break;
case debug:
deleteDir("build/debug");
break;
case release:
deleteDir("build/release");
break;
case relwithdeb:
deleteDir("build/relwithdeb");
break;
}
}
void rebuildProject(const BuildType buildType) {
deleteProject(buildType);
checkBuildDirs(buildType);
configureProject(buildType);
buildProject(buildType);
}
int main(const int argc, char** argv) {
Options options;
try {
options = structopt::app(argv[0], "1.0.0").parse<Options>(argc, argv);
} catch (structopt::exception& e) {
std::cout << e.what() << std::endl;
std::cout << e.help();
exit(EXIT_FAILURE);
}
assert(options.verbose.has_value());
assert(options.dryrun.has_value());
assert(options.buildType.has_value());
g_DryRun = options.dryrun.value();
initLogging();
createLogger("app", nullptr, options.verbose.value());
spdlog::get("app")->debug("Creating logger: 'build'.");
createLogger("build", nullptr, options.verbose.value());
spdlog::get("app")->debug("Creating logger: 'configure'.");
createLogger("configure", nullptr, options.verbose.value());
spdlog::get("app")->debug("Creating logger: 'clean'.");
createLogger("clean", nullptr, options.verbose.value());
spdlog::get("app")->debug("Creating logger: 'filesystem'.");
createLogger("filesystem", nullptr, options.verbose.value());
spdlog::get("app")->debug("Creating logger: 'cmd'.");
createLogger("cmd", nullptr, options.verbose.value());
spdlog::get("app")->debug("Loggers created.");
spdlog::get("app")->debug("Running command");
switch (options.command) {
case build:
buildProject(options.buildType.value());
break;
case configure:
configureProject(options.buildType.value());
break;
case clean:
cleanProject(options.buildType.value());
break;
case del:
deleteProject(options.buildType.value());
break;
case rebuild:
rebuildProject(options.buildType.value());
break;
}
spdlog::get("app")->info("All work done!");
return 0;
}