diff --git a/.gitignore b/.gitignore index 636bded..bb4160f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ .idea +*.dot diff --git a/CMakeLists.txt b/CMakeLists.txt index 97c7346..ce943a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,9 @@ project(build_script) set(CMAKE_CXX_STANDARD 26) set(CMAKE_POLICY_VERSION_MINIMUM 3.5) +# Taskflow has a deprecated declaration issue in its small_vector.hpp file +add_compile_options(-Wno-deprecated-declarations) + file(GLOB REQUIRED_CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.required.cmake") foreach (cmake_file ${REQUIRED_CMAKE_FILES}) include(${cmake_file}) @@ -23,13 +26,16 @@ add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEADER_FILES}) target_include_directories(${PROJECT_NAME} PUBLIC "${structops_SOURCE_DIR}/include" "${spdlog_SOURCE_DIR}/include" + "${taskflow_SOURCE_DIR}" ) target_link_libraries(${PROJECT_NAME} PUBLIC structopt spdlog + Taskflow ) # Structopt includes an outdated version of magic_enum that breaks some default defines # This is needed to bypass it. Im not happy about it, but it is what it is target_link_options(build_script PRIVATE -Wl,--allow-multiple-definition) + diff --git a/cmake/taskflow.cmake b/cmake/taskflow.cmake new file mode 100644 index 0000000..9421480 --- /dev/null +++ b/cmake/taskflow.cmake @@ -0,0 +1,5 @@ +CPMAddPackage ( + URI "gh:taskflow/taskflow@4.1.0" + OPTIONS "TF_BUILD_EXAMPLES off" + OPTIONS "TF_BUILD_TESTS off" +) diff --git a/src/app.cpp b/src/app.cpp index 6495116..37d439e 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,6 +1,10 @@ #include "app.h" +#include + #include "args.h" +#include "logging.h" +#include "taskflow/core/executor.hpp" Application::Application(Options options) : m_DryRun(options.dryrun.value()), @@ -10,7 +14,7 @@ Application::Application(Options options) createAllLoggers(); } -void Application::run() { +void Application::assemble() { spdlog::get("app")->debug("Running command"); switch (m_Command) { case build: @@ -29,7 +33,20 @@ void Application::run() { rebuildProject(); break; } +} +void Application::save_graph(std::string filename) { + spdlog::get("app")->info("Saving task flow graph to '{}'", filename); + spdlog::get("app")->info( + "You can use a website like " + "'https://dreampuf.github.io/GraphvizOnline/?engine=dot' to view it."); + std::ofstream os(filename); + m_Taskflow.dump(os); +} + +void Application::run() { + tf::Executor executor; + executor.run(m_Taskflow).wait(); spdlog::get("app")->info("All work done!"); } diff --git a/src/app.h b/src/app.h index 3259039..e8708e2 100644 --- a/src/app.h +++ b/src/app.h @@ -2,14 +2,19 @@ #define BUILD_SCRIPT_APP #include +#include #include "args.h" #include "logging.h" +#include "taskflow/core/executor.hpp" +#include "taskflow/core/taskflow.hpp" #include "types.h" class Application { public: Application(Options options); + void assemble(); + void save_graph(std::string filename); void run(); private: @@ -18,6 +23,8 @@ class Application { BuildType m_BuildType; Command m_Command; + tf::Taskflow m_Taskflow; + void createAllLoggers(); void buildProject(); diff --git a/src/args.h b/src/args.h index adc64f8..0bb62f7 100644 --- a/src/args.h +++ b/src/args.h @@ -1,6 +1,7 @@ #ifndef BUILD_SCRIPT_ARGS #define BUILD_SCRIPT_ARGS +#include #include #include "types.h" @@ -11,8 +12,9 @@ struct Options { std::optional verbose = false; std::optional dryrun = false; + std::optional graphFilename; }; -STRUCTOPT(Options, command, buildType, verbose, dryrun); +STRUCTOPT(Options, command, buildType, verbose, dryrun, graphFilename); Options parse(int argc, char** argv); diff --git a/src/commands.cpp b/src/commands.cpp index 0c782e4..f5d96d8 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -1,87 +1,247 @@ +#include + #include "app.h" +#include "types.h" void Application::buildProject() { - checkBuildDirs(); - switch (m_BuildType) { - case none: - configureDir("build/debug", "Debug"); - buildDir("build/debug"); - configureDir("build/release", "Release"); - buildDir("build/release"); - configureDir("build/relwithdeb", "RelWithDeb"); - buildDir("build/relwithdeb"); - configureDir("build/minsizerel", "MinSizeRel"); - buildDir("build/minsizerel"); - 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; - case minsizerel: - configureDir("build/minsizerel", "MinSizeRel"); - buildDir("build/minsizerel"); - break; + auto checkBuildDirsTask = + m_Taskflow.emplace([this]() { this->checkBuildDirs(); }) + .name("checkBuildDirs"); + if (m_BuildType == BuildType::none) { + auto configureDirDebugTask = + m_Taskflow + .emplace( + [this]() { this->configureDir("build/debug", "debug"); }) + .name("configureDir(build/debug)"); + auto buildDirDebugTask = + m_Taskflow.emplace([this]() { this->buildDir("build/debug"); }) + .name("buildDir(build/debug)"); + + configureDirDebugTask.precede(buildDirDebugTask); + checkBuildDirsTask.precede(configureDirDebugTask); + + auto configureDirReleaseTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/release", "Release"); + }) + .name("configureDir(build/release)"); + auto buildDirReleaseTask = + m_Taskflow.emplace([this]() { this->buildDir("build/release"); }) + .name("buildDir(build/release)"); + + configureDirReleaseTask.precede(buildDirReleaseTask); + checkBuildDirsTask.precede(configureDirReleaseTask); + + auto configureDirRelWithDebTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/relwithdeb", "RelWithDeb"); + }) + .name("configureDir(build/relwithdeb)"); + auto buildDirRelWithDebTask = + m_Taskflow.emplace([this]() { this->buildDir("build/relwithdeb"); }) + .name("buildDir(build/relwithdeb)"); + + configureDirRelWithDebTask.precede(buildDirRelWithDebTask); + checkBuildDirsTask.precede(configureDirRelWithDebTask); + + auto configureDirMinSizeRelTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/minsizerel", "MinSizeRel"); + }) + .name("configureDir(build/minsizerel)"); + auto buildDirMinSizeRelTask = + m_Taskflow.emplace([this]() { this->buildDir("build/minsizerel"); }) + .name("buildDir(build/minsizerel)"); + + configureDirMinSizeRelTask.precede(buildDirMinSizeRelTask); + checkBuildDirsTask.precede(configureDirMinSizeRelTask); + + } else if (m_BuildType == BuildType::debug) { + auto configureDirTask = + m_Taskflow + .emplace( + [this]() { this->configureDir("build/debug", "debug"); }) + .name("configureDir(build/debug)"); + auto buildDirTask = + m_Taskflow.emplace([this]() { this->buildDir("build/debug"); }) + .name("buildDir(build/debug)"); + + configureDirTask.precede(buildDirTask); + checkBuildDirsTask.precede(configureDirTask); + + } else if (m_BuildType == BuildType::release) { + auto configureDirTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/release", "Release"); + }) + .name("configureDir(build/release)"); + auto buildDirTask = + m_Taskflow.emplace([this]() { this->buildDir("build/release"); }) + .name("buildDir(build/release)"); + + configureDirTask.precede(buildDirTask); + checkBuildDirsTask.precede(configureDirTask); + } else if (m_BuildType == BuildType::relwithdeb) { + auto configureDirTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/relwithdeb", "RelWithDeb"); + }) + .name("configureDir(build/relwithdeb)"); + auto buildDirTask = + m_Taskflow.emplace([this]() { this->buildDir("build/relwithdeb"); }) + .name("buildDir(build/relwithdeb)"); + + configureDirTask.precede(buildDirTask); + checkBuildDirsTask.precede(configureDirTask); + } else if (m_BuildType == BuildType::minsizerel) { + auto configureDirTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/minsizerel", "MinSizeRel"); + }) + .name("configureDir(build/minsizerel)"); + auto buildDirTask = + m_Taskflow.emplace([this]() { this->buildDir("build/minsizerel"); }) + .name("buildDir(build/minsizerel)"); + + configureDirTask.precede(buildDirTask); + checkBuildDirsTask.precede(configureDirTask); } } void Application::configureProject() { - checkBuildDirs(); - switch (m_BuildType) { - case none: - configureDir("build/debug", "Debug"); - configureDir("build/release", "Release"); - configureDir("build/relwithdeb", "RelWithDeb"); - configureDir("build/minsizerel", "MinSizeRel"); - break; - case debug: - configureDir("build/debug", "Debug"); - break; - case release: - configureDir("build/release", "Release"); - break; - case relwithdeb: - configureDir("build/relwithbeb", "RelWithDeb"); - break; - case minsizerel: - configureDir("build/minsizerel", "MinSizeRel"); - break; + auto checkBuildDirsTask = + m_Taskflow.emplace([this]() { this->checkBuildDirs(); }) + .name("checkBuildDirs"); + if (m_BuildType == BuildType::none) { + auto configureDirDebugTask = + m_Taskflow + .emplace( + [this]() { this->configureDir("build/debug", "debug"); }) + .name("configureDir(build/debug)"); + checkBuildDirsTask.precede(configureDirDebugTask); + + auto configureDirReleaseTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/release", "Release"); + }) + .name("configureDir(build/release)"); + checkBuildDirsTask.precede(configureDirReleaseTask); + + auto configureDirRelWithDebTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/relwithdeb", "RelWithDeb"); + }) + .name("configureDir(build/relwithdeb)"); + checkBuildDirsTask.precede(configureDirRelWithDebTask); + + auto configureDirMinSizeRelTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/minsizerel", "MinSizeRel"); + }) + .name("configureDir(build/minsizerel)"); + checkBuildDirsTask.precede(configureDirMinSizeRelTask); + + } else if (m_BuildType == BuildType::debug) { + auto configureDirDebugTask = + m_Taskflow + .emplace( + [this]() { this->configureDir("build/debug", "debug"); }) + .name("configureDir(build/debug)"); + checkBuildDirsTask.precede(configureDirDebugTask); + + } else if (m_BuildType == BuildType::release) { + auto configureDirReleaseTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/release", "Release"); + }) + .name("configureDir(build/release)"); + checkBuildDirsTask.precede(configureDirReleaseTask); + + } else if (m_BuildType == BuildType::relwithdeb) { + auto configureDirRelWithDebTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/relwithdeb", "RelWithDeb"); + }) + .name("configureDir(build/relwithdeb)"); + checkBuildDirsTask.precede(configureDirRelWithDebTask); + + } else if (m_BuildType == BuildType::minsizerel) { + auto configureDirMinSizeRelTask = + m_Taskflow + .emplace([this]() { + this->configureDir("build/minsizerel", "MinSizeRel"); + }) + .name("configureDir(build/minsizerel)"); + checkBuildDirsTask.precede(configureDirMinSizeRelTask); } } void Application::cleanProject() { - checkBuildDirs(); + auto checkBuildDirsTask = + m_Taskflow.emplace([this]() { this->checkBuildDirs(); }) + .name("checkBuildDirs"); - switch (m_BuildType) { - case none: - cleanDir("build/debug"); - cleanDir("build/release"); - cleanDir("build/relwithdeb"); - cleanDir("build/minsizerel"); - break; - case debug: - cleanDir("build/debug"); - break; - case release: - cleanDir("build/release"); - break; - case relwithdeb: - cleanDir("build/relwithdeb"); - break; - case minsizerel: - cleanDir("build/minsizerel"); - break; + if (m_BuildType == BuildType::none) { + auto cleanDirDebugTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/debug"); }) + .name("cleanDir(build/debug)"); + checkBuildDirsTask.precede(cleanDirDebugTask); + + auto cleanDirReleaseTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/release"); }) + .name("cleanDir(build/release)"); + checkBuildDirsTask.precede(cleanDirReleaseTask); + + auto cleanDirRelWithDebTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/relwithdeb"); }) + .name("cleanDir(build/relwithdeb)"); + checkBuildDirsTask.precede(cleanDirRelWithDebTask); + auto cleanDirMinSizeRelTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/minsizerel"); }) + .name("cleanDir(build/minsizerel)"); + checkBuildDirsTask.precede(cleanDirMinSizeRelTask); + + } else if (m_BuildType == BuildType::debug) { + auto cleanDirDebugTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/debug"); }) + .name("cleanDir(build/debug)"); + checkBuildDirsTask.precede(cleanDirDebugTask); + + } else if (m_BuildType == BuildType::release) { + auto cleanDirReleaseTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/release"); }) + .name("cleanDir(build/release)"); + checkBuildDirsTask.precede(cleanDirReleaseTask); + + } else if (m_BuildType == BuildType::relwithdeb) { + auto cleanDirRelWithDebTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/relwithdeb"); }) + .name("cleanDir(build/relwithdeb)"); + checkBuildDirsTask.precede(cleanDirRelWithDebTask); + + } else if (m_BuildType == BuildType::minsizerel) { + auto cleanDirMinSizeRelTask = + m_Taskflow.emplace([this]() { this->cleanDir("build/minsizerel"); }) + .name("cleanDir(build/minsizerel)"); + checkBuildDirsTask.precede(cleanDirMinSizeRelTask); } } void Application::deleteProject() { + // No point in using taskflow for this... + // In all cases its just deleting a single directory... + // Bit overkill for that switch (m_BuildType) { case none: deleteDir("build"); @@ -103,7 +263,5 @@ void Application::deleteProject() { void Application::rebuildProject() { deleteProject(); - checkBuildDirs(); - configureProject(); buildProject(); } diff --git a/src/logging.cpp b/src/logging.cpp index 7995e48..6ca8067 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -35,7 +35,7 @@ void createLogger(const char* name, const char* filename, const bool verbose) { if (verbose) logger->set_level(spdlog::level::debug); else - logger->set_level(spdlog::level::warn); + logger->set_level(spdlog::level::info); #endif spdlog::register_logger(logger); diff --git a/src/main.cpp b/src/main.cpp index 2cd21fd..8be4d72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,12 @@ int main(const int argc, char** argv) { Options options = parse(argc, argv); Application app(options); + app.assemble(); + if (options.graphFilename.has_value()) { + app.save_graph(options.graphFilename.value()); + spdlog::get("app")->info("Exiting.."); + return 0; + } app.run(); return 0;