diff --git a/bootstrap/include/bootstrap/build_buildcc.h b/bootstrap/include/bootstrap/build_buildcc.h index 340066a5..7dcb9aee 100644 --- a/bootstrap/include/bootstrap/build_buildcc.h +++ b/bootstrap/include/bootstrap/build_buildcc.h @@ -59,9 +59,8 @@ class BuildBuildCC { static constexpr const char *const kBuildccLibName = "libbuildcc"; public: - BuildBuildCC(Register ®, const BaseToolchain &toolchain, - const TargetEnv &env) - : reg_(reg), toolchain_(toolchain), env_(env) {} + BuildBuildCC(const BaseToolchain &toolchain, const TargetEnv &env) + : toolchain_(toolchain), env_(env) {} BuildBuildCC(const BuildBuildCC &) = delete; void Setup(const ArgToolchainState &state); @@ -75,7 +74,6 @@ class BuildBuildCC { } private: - Register ®_; const BaseToolchain &toolchain_; TargetEnv env_; diff --git a/bootstrap/include/bootstrap/build_tpl.h b/bootstrap/include/bootstrap/build_tpl.h index 9695f7d3..9d00cc5e 100644 --- a/bootstrap/include/bootstrap/build_tpl.h +++ b/bootstrap/include/bootstrap/build_tpl.h @@ -21,13 +21,7 @@ namespace buildcc { -struct TplConfig { - TplConfig() = default; - - OsId os_id{OsId::Linux}; -}; - -void tpl_cb(BaseTarget &target, const TplConfig &config = TplConfig()); +void tpl_cb(BaseTarget &target); } // namespace buildcc diff --git a/bootstrap/main.buildcc.cpp b/bootstrap/main.buildcc.cpp index 7ee8afd6..9115346e 100644 --- a/bootstrap/main.buildcc.cpp +++ b/bootstrap/main.buildcc.cpp @@ -38,31 +38,32 @@ int main(int argc, char **argv) { .AddToolchain("host", "Host Toolchain", custom_toolchain_arg) .Parse(argc, argv); - Register reg; - reg.Clean(clean_cb); + Reg::Init(); + Reg::Call(Args::Clean()).Func(clean_cb); BaseToolchain toolchain = custom_toolchain_arg.ConstructToolchain(); + toolchain.Verify(); BuildBuildCC buildcc( - reg, toolchain, TargetEnv(Project::GetRootDir(), Project::GetBuildDir())); + toolchain, TargetEnv(Project::GetRootDir(), Project::GetBuildDir())); buildcc.Setup(custom_toolchain_arg.state); const auto &buildcc_lib = buildcc.GetBuildcc(); ExecutableTarget_generic buildcc_hybrid_simple_example( "buildcc_hybrid_simple_example", toolchain, "example/hybrid/simple"); - reg.Build(custom_toolchain_arg.state, hybrid_simple_example_cb, - buildcc_hybrid_simple_example, buildcc_lib); - reg.Dep(buildcc_hybrid_simple_example, buildcc_lib); + Reg::Toolchain(custom_toolchain_arg.state) + .Build(hybrid_simple_example_cb, buildcc_hybrid_simple_example, + buildcc_lib) + .Dep(buildcc_hybrid_simple_example, buildcc_lib); // Runners - reg.RunBuild(); - reg.RunTest(); + Reg::Run(); // - Clang Compile Commands plugin::ClangCompileCommands({&buildcc_lib}).Generate(); // - Plugin Graph - std::string output = reg.GetTaskflow().dump(); + std::string output = Reg::GetTaskflow().dump(); const bool saved = env::save_file("graph.dot", output, false); env::assert_fatal(saved, "Could not save graph.dot file"); diff --git a/bootstrap/src/build_buildcc.cpp b/bootstrap/src/build_buildcc.cpp index 0d367c3d..d5b111b6 100644 --- a/bootstrap/src/build_buildcc.cpp +++ b/bootstrap/src/build_buildcc.cpp @@ -131,7 +131,6 @@ void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen, if constexpr (env::is_win()) { // TODO, Clang switch (target.GetToolchain().GetId()) { - case ToolchainId::Gcc: case ToolchainId::MinGW: { target.AddPreprocessorFlag("-DFMT_HEADER_ONLY=1"); target.AddPreprocessorFlag("-DSPDLOG_FMT_EXTERNAL"); @@ -147,7 +146,7 @@ void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen, } } - if constexpr (env::is_linux()) { + if constexpr (env::is_linux() || env::is_unix() || env::is_clang()) { // TODO, Clang switch (target.GetToolchain().GetId()) { case ToolchainId::Gcc: { @@ -196,51 +195,41 @@ void BuildBuildCC::Setup(const ArgToolchainState &state) { TargetEnv(env_.GetTargetRootDir() / "third_party" / "flatbuffers", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, global_flags_cb, flatc_exe, toolchain_); - reg_.Build(state, build_flatc_exe_cb, flatc_exe); - // Schema auto &schema_gen = storage_.Add( kSchemaGenName, kSchemaGenName, TargetEnv(env_.GetTargetRootDir() / "buildcc" / "schema", env_.GetTargetBuildDir() / toolchain_.GetName())); - reg_.Build(schema_gen_cb, schema_gen, flatc_exe); - reg_.Dep(schema_gen, flatc_exe); // Flatbuffers HO lib auto &flatbuffers_ho_lib = storage_.Add( kFlatbuffersHoName, toolchain_, TargetEnv(env_.GetTargetRootDir() / "third_party" / "flatbuffers", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, flatbuffers_ho_cb, flatbuffers_ho_lib); // CLI11 HO lib auto &cli11_ho_lib = storage_.Add( kCli11HoName, toolchain_, TargetEnv(env_.GetTargetRootDir() / "third_party" / "CLI11", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, cli11_ho_cb, cli11_ho_lib); // fmt HO lib auto &fmt_ho_lib = storage_.Add( kFmtHoName, toolchain_, TargetEnv(env_.GetTargetRootDir() / "third_party" / "fmt", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, fmt_ho_cb, fmt_ho_lib); // spdlog HO lib auto &spdlog_ho_lib = storage_.Add( kSpdlogHoName, toolchain_, TargetEnv(env_.GetTargetRootDir() / "third_party" / "spdlog", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, spdlog_ho_cb, spdlog_ho_lib); // taskflow HO lib auto &taskflow_ho_lib = storage_.Add( kTaskflowHoName, toolchain_, TargetEnv(env_.GetTargetRootDir() / "third_party" / "taskflow", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, taskflow_ho_cb, taskflow_ho_lib); // Tiny-process-library lib // TODO, Make this a generic selection between StaticTarget and @@ -250,21 +239,31 @@ void BuildBuildCC::Setup(const ArgToolchainState &state) { TargetEnv(env_.GetTargetRootDir() / "third_party" / "tiny-process-library", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, global_flags_cb, tpl_lib, toolchain_); - TplConfig tpl_config; - tpl_config.os_id = get_host_os(); - reg_.Build(state, tpl_cb, tpl_lib, tpl_config); + // BuildCC lib // TODO, Make this a generic selection between StaticTarget and // DynamicTarget auto &buildcc_lib = storage_.Add( kBuildccLibName, kBuildccLibName, toolchain_, TargetEnv(env_.GetTargetRootDir() / "buildcc", env_.GetTargetBuildDir())); - reg_.CallbackIf(state, global_flags_cb, buildcc_lib, toolchain_); - reg_.Build(state, buildcc_cb, buildcc_lib, schema_gen, flatbuffers_ho_lib, - fmt_ho_lib, spdlog_ho_lib, cli11_ho_lib, taskflow_ho_lib, tpl_lib); - reg_.Dep(buildcc_lib, schema_gen); - reg_.Dep(buildcc_lib, tpl_lib); + + Reg::Toolchain(state) + .Func(global_flags_cb, flatc_exe, toolchain_) + .Build(build_flatc_exe_cb, flatc_exe) + .Build(schema_gen_cb, schema_gen, flatc_exe) + .Dep(schema_gen, flatc_exe) + .Func(flatbuffers_ho_cb, flatbuffers_ho_lib) + .Func(cli11_ho_cb, cli11_ho_lib) + .Func(fmt_ho_cb, fmt_ho_lib) + .Func(spdlog_ho_cb, spdlog_ho_lib) + .Func(taskflow_ho_cb, taskflow_ho_lib) + .Func(global_flags_cb, tpl_lib, toolchain_) + .Build(tpl_cb, tpl_lib) + .Func(global_flags_cb, buildcc_lib, toolchain_) + .Build(buildcc_cb, buildcc_lib, schema_gen, flatbuffers_ho_lib, + fmt_ho_lib, spdlog_ho_lib, cli11_ho_lib, taskflow_ho_lib, tpl_lib) + .Dep(buildcc_lib, schema_gen) + .Dep(buildcc_lib, tpl_lib); } } // namespace buildcc diff --git a/bootstrap/src/build_tpl.cpp b/bootstrap/src/build_tpl.cpp index 0bd53b14..847161b1 100644 --- a/bootstrap/src/build_tpl.cpp +++ b/bootstrap/src/build_tpl.cpp @@ -18,22 +18,17 @@ namespace buildcc { -void tpl_cb(BaseTarget &target, const TplConfig &config) { +void tpl_cb(BaseTarget &target) { target.AddSource("process.cpp"); target.AddIncludeDir(""); target.AddHeader("process.hpp"); - switch (config.os_id) { - case OsId::Win: + if constexpr (env::is_win()) { target.AddSource("process_win.cpp"); - break; - case OsId::Linux: - case OsId::Unix: - case OsId::Mac: + } + + if constexpr (env::is_linux() || env::is_unix() || env::is_clang()) { target.AddSource("process_unix.cpp"); - break; - default: - break; } target.Build(); diff --git a/buildcc/lib/args/include/args/args.h b/buildcc/lib/args/include/args/args.h index f26e006d..6cccb1f3 100644 --- a/buildcc/lib/args/include/args/args.h +++ b/buildcc/lib/args/include/args/args.h @@ -27,13 +27,14 @@ #include "toolchain/toolchain.h" +#include "target/common/target_config.h" + namespace fs = std::filesystem; namespace buildcc { /** - * @brief Toolchain State used by the Register module to selectively build or - * test targets + * @brief Toolchain State used to selectively build and test targets */ struct ArgToolchainState { bool build{false}; @@ -81,8 +82,15 @@ struct ArgToolchain { struct ArgTarget { ArgTarget(){}; - std::string compile_command{""}; - std::string link_command{""}; + TargetConfig GetTargetConfig() { + TargetConfig config; + config.compile_command = compile_command; + config.link_command = link_command; + return config; + } + + std::string compile_command; + std::string link_command; }; struct ArgCustom { @@ -91,56 +99,8 @@ struct ArgCustom { class Args { private: - class Instance { - public: - /** - * @brief Parse command line information to CLI11 - * - * @param argc from int main(int argc, char ** argv) - * @param argv from int main(int argc, char ** argv) - */ - static void Parse(int argc, const char *const *argv); - - /** - * @brief Add toolchain with a unique name and description - * - * @param out Receive the toolchain information through the CLI - * @param initial Set the default toolchain information as a fallback - */ - Instance &AddToolchain(const std::string &name, - const std::string &description, ArgToolchain &out, - const ArgToolchain &initial = ArgToolchain()); - - /** - * @brief Add toolchain with a unique name and description - * - * @param out Receive the toolchain information through the CLI - * @param initial Set the default toolchain information as a fallback - */ - Instance &AddTarget(const std::string &name, const std::string &description, - ArgTarget &out, const ArgTarget &initial = ArgTarget()); - - /** - * @brief Custom callback for data - * - * @param add_cb Add callback that exposes underlying CLI::App - */ - Instance &AddCustomCallback(const std::function &add_cb); - - /** - * @brief Add custom data - * - * @param data Derive from `buildcc::ArgCustom` and override the `Add` API - */ - Instance &AddCustomData(ArgCustom &data); - }; - - struct Internal { - Instance instance; - CLI::App app{"BuildCC Buildsystem"}; - CLI::App *toolchain{nullptr}; - CLI::App *target{nullptr}; - }; + class Instance; + struct Internal; public: Args() = delete; @@ -151,6 +111,8 @@ class Args { static void Deinit(); // Getters + static bool IsInit(); + static bool IsParsed(); static bool Clean(); static env::LogLevel GetLogLevel(); @@ -159,12 +121,64 @@ class Args { private: static void RootArgs(); - static CLI::App &Ref(); + static Internal &RefInternal(); + static CLI::App &RefApp(); private: static std::unique_ptr internal_; }; +class Args::Instance { +public: + /** + * @brief Parse command line information to CLI11 + * + * @param argc from int main(int argc, char ** argv) + * @param argv from int main(int argc, char ** argv) + */ + static void Parse(int argc, const char *const *argv); + + /** + * @brief Add toolchain with a unique name and description + * + * @param out Receive the toolchain information through the CLI + * @param initial Set the default toolchain information as a fallback + */ + Instance &AddToolchain(const std::string &name, + const std::string &description, ArgToolchain &out, + const ArgToolchain &initial = ArgToolchain()); + + /** + * @brief Add toolchain with a unique name and description + * + * @param out Receive the toolchain information through the CLI + * @param initial Set the default toolchain information as a fallback + */ + Instance &AddTarget(const std::string &name, const std::string &description, + ArgTarget &out, const ArgTarget &initial = ArgTarget()); + + /** + * @brief Custom callback for data + * + * @param add_cb Add callback that exposes underlying CLI::App + */ + Instance &AddCustomCallback(const std::function &add_cb); + + /** + * @brief Add custom data + * + * @param data Derive from `buildcc::ArgCustom` and override the `Add` API + */ + Instance &AddCustomData(ArgCustom &data); +}; + +struct Args::Internal { + Instance instance; + CLI::App app{"BuildCC Buildsystem"}; + CLI::App *toolchain{nullptr}; + CLI::App *target{nullptr}; +}; + } // namespace buildcc #endif diff --git a/buildcc/lib/args/include/args/register.h b/buildcc/lib/args/include/args/register.h index 110e5246..a52a08de 100644 --- a/buildcc/lib/args/include/args/register.h +++ b/buildcc/lib/args/include/args/register.h @@ -31,22 +31,41 @@ namespace buildcc { -class Register { +class Reg { +private: + class Instance; + class CallbackInstance; + class ToolchainInstance; + public: - Register() { Initialize(); } - Register(const Register &) = delete; + Reg() = delete; + Reg(const Reg &) = delete; + Reg(Reg &&) = delete; - /** - * @brief Folders and files that need to be cleaned when `clean == true` - */ - void Clean(const std::function &clean_cb); + static void Init(); + static void Deinit(); + static void Run(const std::function &post_build_cb = + std::function()); + static CallbackInstance Call(bool condition = true); + static ToolchainInstance Toolchain(const ArgToolchainState &condition); + + static const tf::Taskflow &GetTaskflow(); + +private: + static Instance &Ref(); + +private: + static std::unique_ptr instance_; +}; +class Reg::Instance { +public: /** * @brief Generic register callback with variable arguments * Can be used to organize code into functional chunks */ template - void Callback(const C &build_cb, Params &&...params) { + static void Callback(const C &build_cb, Params &&...params) { build_cb(std::forward(params)...); } @@ -56,43 +75,25 @@ class Register { * Can be used to add Toolchain-Target specific information */ template - void CallbackIf(bool expression, const C &build_cb, Params &&...params) { + static void CallbackIf(bool expression, const C &build_cb, + Params &&...params) { if (expression) { Callback(build_cb, std::forward(params)...); } } /** - * @brief Generic register callback that is run when `toolchain_state.build == - * true` - * Can be used to add Toolchain-Target specific information - */ - template - void CallbackIf(const ArgToolchainState &toolchain_state, const C &build_cb, - Params &&...params) { - CallbackIf(toolchain_state.build, build_cb, - std::forward(params)...); - } - - /** - * @brief Register the Target to be built + * @brief Reg::Instance for Target to be built */ template - void Build(const ArgToolchainState &toolchain_state, const C &build_cb, - BaseTarget &target, Params &&...params) { - tf::Task task; - CallbackIf( - toolchain_state, - [&](BaseTarget <arget, Params &&...lparams) { - build_cb(ltarget, std::forward(lparams)...); - task = BuildTargetTask(ltarget); - }, - target, std::forward(params)...); + void Build(const C &build_cb, BaseTarget &target, Params &&...params) { + build_cb(target, std::forward(params)...); + tf::Task task = BuildTargetTask(target); BuildStoreTask(target.GetUniqueId(), task); } /** - * @brief Register the generator to be built + * @brief Reg::Instance for Generator to be built */ template void Build(const C &build_cb, BaseGenerator &generator, Params &&...params) { @@ -103,7 +104,7 @@ class Register { /** * @brief Setup dependency between 2 Targets - * PreReq: Call `Register::Build` before calling `Register::Dep` + * PreReq: Call `Reg::Instance::Build` before calling `Reg::Instance::Dep` * * Target runs after dependency is built */ @@ -111,8 +112,8 @@ class Register { const internal::BuilderInterface &dependency); /** - * @brief Register the Target to be run - * PreReq: Call `Register::Build` before calling `Register::Test` + * @brief Instance the Target to be run + * PreReq: Call `Reg::Instance::Build` before calling `Reg::Instance::Test` * PreReq: Requires ArgToolchainState::build && ArgToolchainState::test to be * true * @@ -120,19 +121,18 @@ class Register { * We can add more fmt::format arguments using the TestConfig arguments * parameter */ - void Test(const ArgToolchainState &toolchain_state, - const std::string &command, const BaseTarget &target, + void Test(const std::string &command, const BaseTarget &target, const TestConfig &config = TestConfig()); /** * @brief Builds the targets that have been dynamically added through - * `Register::Build` + * `Reg::Instance::Build` */ void RunBuild(); /** * @brief Runs the targets that have been dynamically added through - * `Register::Test` + * `Reg::Instance::Test` */ void RunTest(); @@ -143,11 +143,6 @@ class Register { private: private: - void Initialize(); - - // Setup env:: defaults - void Env(); - // BuildTasks tf::Task BuildTargetTask(BaseTarget &target); tf::Task BuildGeneratorTask(BaseGenerator &generator); @@ -158,12 +153,71 @@ class Register { tf::Taskflow build_tf_{"Targets"}; std::unordered_map build_; - - // Tests std::unordered_map tests_; +}; + +class Reg::CallbackInstance { +public: + CallbackInstance(bool condition = true) : condition_(condition) {} - // - tf::Executor executor_; + // Duplicated code + template + CallbackInstance &Func(const C &cb, Params &&...params) { + Instance::CallbackIf(condition_, cb, std::forward(params)...); + return *this; + } + + template + CallbackInstance &Build(const C &build_cb, BaseGenerator &generator, + Params &&...params) { + if (condition_) { + Ref().Build(build_cb, generator, std::forward(params)...); + }; + return *this; + } + +private: + bool condition_; +}; + +class Reg::ToolchainInstance { +public: + ToolchainInstance(const ArgToolchainState &condition) + : condition_(condition) {} + + template + ToolchainInstance &Func(const C &cb, Params &&...params) { + Instance::CallbackIf(condition_.build, cb, std::forward(params)...); + return *this; + } + + template + ToolchainInstance &Build(const C &build_cb, BaseGenerator &generator, + Params &&...params) { + return BuildInternal(build_cb, generator, std::forward(params)...); + } + template + ToolchainInstance &Build(const C &build_cb, BaseTarget &target, + Params &&...params) { + return BuildInternal(build_cb, target, std::forward(params)...); + } + ToolchainInstance &Dep(const internal::BuilderInterface &target, + const internal::BuilderInterface &dependency); + ToolchainInstance &Test(const std::string &command, const BaseTarget &target, + const TestConfig &config = TestConfig()); + +private: + template + ToolchainInstance &BuildInternal(const C &build_cb, T &t, + Params &&...params) { + if (condition_.build) { + Ref().Build(build_cb, t, std::forward(params)...); + } + return *this; + } + +private: + ArgToolchainState condition_; }; } // namespace buildcc diff --git a/buildcc/lib/args/include/args/register/test_info.h b/buildcc/lib/args/include/args/register/test_info.h index 50d61f41..a2e25dc7 100644 --- a/buildcc/lib/args/include/args/register/test_info.h +++ b/buildcc/lib/args/include/args/register/test_info.h @@ -35,7 +35,7 @@ struct TestOutput { }; /** - * @brief Configure your Register::Test to get test output + * @brief Configure your `Reg::Instance::Test` to get test output * * @param output_type Select your output type (behaviour) * @param redirect_stdout User stdout redirection @@ -64,7 +64,7 @@ struct TestOutput { struct TestConfig { public: /** - * @brief Configure your Register::Test using TestConfig + * @brief Configure your `Reg::Instance::Test` using TestConfig * * @param arguments fmt::format args passed to test commands * @param working_directory Working directory from which the test runs diff --git a/buildcc/lib/args/mock/parse.cpp b/buildcc/lib/args/mock/parse.cpp index 53213201..db3a1c6f 100644 --- a/buildcc/lib/args/mock/parse.cpp +++ b/buildcc/lib/args/mock/parse.cpp @@ -6,7 +6,7 @@ namespace buildcc { void Args::Instance::Parse(int argc, const char *const *argv) { try { - Ref().parse(argc, argv); + RefApp().parse(argc, argv); } catch (const CLI::ParseError &e) { env::assert_fatal(e.what()); } diff --git a/buildcc/lib/args/mock/tasks.cpp b/buildcc/lib/args/mock/tasks.cpp index 939e0100..40bc8eec 100644 --- a/buildcc/lib/args/mock/tasks.cpp +++ b/buildcc/lib/args/mock/tasks.cpp @@ -4,20 +4,20 @@ namespace buildcc { -tf::Task Register::BuildTargetTask(BaseTarget &target) { +tf::Task Reg::Instance::BuildTargetTask(BaseTarget &target) { mock().actualCall(fmt::format("BuildTask_{}", target.GetName()).c_str()); return build_tf_.placeholder().name(target.GetUniqueId()); } -tf::Task Register::BuildGeneratorTask(BaseGenerator &generator) { +tf::Task Reg::Instance::BuildGeneratorTask(BaseGenerator &generator) { mock().actualCall( fmt::format("BuildGeneratorTask_{}", generator.GetName()).c_str()); return build_tf_.placeholder().name(generator.GetUniqueId()); } -void Register::RunBuild() {} +void Reg::Instance::RunBuild() {} -void Register::RunTest() { +void Reg::Instance::RunTest() { std::for_each(tests_.begin(), tests_.end(), [](const auto &p) { p.second.TestRunner(); }); } diff --git a/buildcc/lib/args/src/args.cpp b/buildcc/lib/args/src/args.cpp index 378bd7d4..0d10823c 100644 --- a/buildcc/lib/args/src/args.cpp +++ b/buildcc/lib/args/src/args.cpp @@ -18,6 +18,10 @@ namespace { +// Error messages +constexpr const char *const kArgsNotInit = + "Initialize Args using the Args::Init API"; + // Groups constexpr const char *const kRootGroup = "Root"; @@ -99,9 +103,10 @@ std::unique_ptr Args::internal_; Args::Instance &Args::Init() { if (!internal_) { internal_ = std::make_unique(); + auto &app = RefApp(); internal_->toolchain = - Ref().add_subcommand(kToolchainSubcommand, kToolchainDesc); - internal_->target = Ref().add_subcommand(kTargetSubcommand, kTargetDesc); + app.add_subcommand(kToolchainSubcommand, kToolchainDesc); + internal_->target = app.add_subcommand(kTargetSubcommand, kTargetDesc); RootArgs(); } return internal_->instance; @@ -109,6 +114,13 @@ Args::Instance &Args::Init() { void Args::Deinit() { internal_.reset(nullptr); } +bool Args::IsInit() { return static_cast(internal_); } +bool Args::IsParsed() { + if (!IsInit()) { + return false; + } + return RefApp().parsed(); +} bool Args::Clean() { return clean_; } env::LogLevel Args::GetLogLevel() { return loglevel_; } @@ -118,7 +130,7 @@ const fs::path &Args::GetProjectBuildDir() { return project_build_dir_; } // Private void Args::RootArgs() { - auto &app = Ref(); + auto &app = RefApp(); app.set_help_all_flag(kHelpAllParam, kHelpAllDesc); app.set_config(kConfigParam, "", kConfigDesc)->expected(kMinFiles, kMaxFiles); @@ -137,7 +149,11 @@ void Args::RootArgs() { ->required(); } -CLI::App &Args::Ref() { return internal_->app; } +Args::Internal &Args::RefInternal() { + env::assert_fatal(internal_ != nullptr, kArgsNotInit); + return *internal_; +} +CLI::App &Args::RefApp() { return RefInternal().app; } // Args::Instance @@ -151,9 +167,7 @@ Args::Instance &Args::Instance::AddToolchain(const std::string &name, const std::string &description, ArgToolchain &out, const ArgToolchain &initial) { - CLI::App *toolchain = internal_->toolchain; - env::assert_fatal(toolchain != nullptr, - "Initialize Args using the Args::Init API"); + CLI::App *toolchain = RefInternal().toolchain; CLI::App *t_user = toolchain->add_subcommand(name, description)->group(kToolchainGroup); t_user->add_flag(kToolchainBuildParam, out.state.build); @@ -186,9 +200,7 @@ Args::Instance &Args::Instance::AddTarget(const std::string &name, const std::string &description, ArgTarget &out, const ArgTarget &initial) { - CLI::App *target = internal_->target; - env::assert_fatal(target != nullptr, - "Initialize Args using the Args::Init API"); + CLI::App *target = RefInternal().target; CLI::App *targetuser = target->add_subcommand(name, description)->group(kTargetGroup); targetuser->add_option(kTargetCompileCommandParam, out.compile_command) @@ -200,13 +212,13 @@ Args::Instance &Args::Instance::AddTarget(const std::string &name, Args::Instance &Args::Instance::AddCustomCallback( const std::function &add_cb) { - auto &app = Ref(); + auto &app = RefApp(); add_cb(app); return *this; } Args::Instance &Args::Instance::AddCustomData(ArgCustom &data) { - auto &app = Ref(); + auto &app = RefApp(); data.Add(app); return *this; } diff --git a/buildcc/lib/args/src/parse.cpp b/buildcc/lib/args/src/parse.cpp index bbb6b745..0d2aa186 100644 --- a/buildcc/lib/args/src/parse.cpp +++ b/buildcc/lib/args/src/parse.cpp @@ -19,7 +19,7 @@ namespace buildcc { void Args::Instance::Parse(int argc, const char *const *argv) { - auto &app = Ref(); + auto &app = RefApp(); try { app.parse(argc, argv); } catch (const CLI::ParseError &e) { diff --git a/buildcc/lib/args/src/register.cpp b/buildcc/lib/args/src/register.cpp index cbd1e719..dd042ae3 100644 --- a/buildcc/lib/args/src/register.cpp +++ b/buildcc/lib/args/src/register.cpp @@ -26,6 +26,11 @@ namespace fs = std::filesystem; +namespace { +constexpr const char *const kRegkNotInit = + "Initialize Reg using the Reg::Init API"; +} + namespace { void DepDetectDuplicate(const tf::Task &target_task, const std::string &match) { @@ -60,24 +65,80 @@ void DepDetectCyclicDependency(const tf::Task &target_task, namespace buildcc { -void Register::Clean(const std::function &clean_cb) { - if (Args::Clean()) { - clean_cb(); +std::unique_ptr Reg::instance_; + +void Reg::Init() { + if (!instance_) { + instance_ = std::make_unique(); + env::assert_fatal(Args::IsParsed(), "Setup your Args"); + Project::Init(fs::current_path() / Args::GetProjectRootDir(), + fs::current_path() / Args::GetProjectBuildDir()); + env::set_log_level(Args::GetLogLevel()); + } +} + +void Reg::Deinit() { + instance_.reset(nullptr); + Project::Deinit(); +} + +void Reg::Run(const std::function &post_build_cb) { + auto &ref = Ref(); + ref.RunBuild(); + if (post_build_cb) { + post_build_cb(); + } + ref.RunTest(); +} + +const tf::Taskflow &Reg::GetTaskflow() { return Ref().GetTaskflow(); } + +Reg::Instance &Reg::Ref() { + env::assert_fatal(instance_ != nullptr, kRegkNotInit); + return *instance_; +} + +// Reg::ToolchainInstance + +Reg::ToolchainInstance Reg::Toolchain(const ArgToolchainState &condition) { + env::assert_fatal(instance_ != nullptr, kRegkNotInit); + return ToolchainInstance(condition); +} + +Reg::ToolchainInstance & +Reg::ToolchainInstance::Dep(const internal::BuilderInterface &target, + const internal::BuilderInterface &dependency) { + if (condition_.build) { + Ref().Dep(target, dependency); + } + return *this; +} + +Reg::ToolchainInstance &Reg::ToolchainInstance::Test(const std::string &command, + const BaseTarget &target, + const TestConfig &config) { + if (condition_.build && condition_.test) { + Ref().Test(command, target, config); } + return *this; +} + +// Reg::CallbackInstance + +Reg::CallbackInstance Reg::Call(bool condition) { + env::assert_fatal(instance_ != nullptr, kRegkNotInit); + return CallbackInstance(condition); } -void Register::Dep(const internal::BuilderInterface &target, - const internal::BuilderInterface &dependency) { +// Reg::Instance + +void Reg::Instance::Dep(const internal::BuilderInterface &target, + const internal::BuilderInterface &dependency) { const auto target_iter = build_.find(target.GetUniqueId()); const auto dep_iter = build_.find(dependency.GetUniqueId()); env::assert_fatal(!(target_iter == build_.end() || dep_iter == build_.end()), - "Call Register::Build API on target and " - "dependency before Register::Dep API"); - - // empty tasks -> not built so skip - if (target_iter->second.empty() || dep_iter->second.empty()) { - return; - } + "Call Instance::Build API on target and " + "dependency before Instance::Dep API"); const std::string &dep_unique_id = dependency.GetUniqueId(); DepDetectDuplicate(target_iter->second, dep_unique_id); @@ -87,17 +148,12 @@ void Register::Dep(const internal::BuilderInterface &target, target_iter->second.succeed(dep_iter->second); } -void Register::Test(const ArgToolchainState &toolchain_state, - const std::string &command, const BaseTarget &target, - const TestConfig &config) { - if (!(toolchain_state.build && toolchain_state.test)) { - return; - } - +void Reg::Instance::Test(const std::string &command, const BaseTarget &target, + const TestConfig &config) { const auto target_iter = build_.find(target.GetUniqueId()); env::assert_fatal( !(target_iter == build_.end()), - "Call Register::Build API on target before Register::Test API"); + "Call Instance::Build API on target before Instance::Test API"); const bool added = tests_.emplace(target.GetUniqueId(), TestInfo(target, command, config)) @@ -108,22 +164,14 @@ void Register::Test(const ArgToolchainState &toolchain_state, // Private -void Register::BuildStoreTask(const std::string &unique_id, - const tf::Task &task) { +void Reg::Instance::BuildStoreTask(const std::string &unique_id, + const tf::Task &task) { const bool stored = build_.emplace(unique_id, task).second; env::assert_fatal( - stored, fmt::format("Duplicate `Register::Build` call detected for '{}'", + stored, fmt::format("Duplicate `Instance::Build` call detected for '{}'", unique_id)); } -void Register::Initialize() { Env(); } - -void Register::Env() { - Project::Init(fs::current_path() / Args::GetProjectRootDir(), - fs::current_path() / Args::GetProjectBuildDir()); - env::set_log_level(Args::GetLogLevel()); -} - // void TestInfo::TestRunner() const { diff --git a/buildcc/lib/args/src/tasks.cpp b/buildcc/lib/args/src/tasks.cpp index 97e9cc4a..054b8eed 100644 --- a/buildcc/lib/args/src/tasks.cpp +++ b/buildcc/lib/args/src/tasks.cpp @@ -20,32 +20,34 @@ namespace buildcc { -tf::Task Register::BuildTargetTask(BaseTarget &target) { +tf::Task Reg::Instance::BuildTargetTask(BaseTarget &target) { return build_tf_.composed_of(target.GetTaskflow()).name(target.GetUniqueId()); } -tf::Task Register::BuildGeneratorTask(BaseGenerator &generator) { +tf::Task Reg::Instance::BuildGeneratorTask(BaseGenerator &generator) { return build_tf_.composed_of(generator.GetTaskflow()) .name(generator.GetUniqueId()); } -void Register::RunBuild() { - env::log_info(__FUNCTION__, fmt::format("Running with {} workers", - executor_.num_workers())); - executor_.run(build_tf_); - executor_.wait_for_all(); +void Reg::Instance::RunBuild() { + tf::Executor executor; + env::log_info(__FUNCTION__, + fmt::format("Running with {} workers", executor.num_workers())); + executor.run(build_tf_); + executor.wait_for_all(); env::assert_fatal(env::get_task_state() == env::TaskState::SUCCESS, "Task state is not successful!"); } -void Register::RunTest() { +void Reg::Instance::RunTest() { tf::Taskflow test_tf{"Tests"}; test_tf.for_each( tests_.begin(), tests_.end(), [](const std::pair &p) { p.second.TestRunner(); }); - executor_.run(test_tf); - executor_.wait_for_all(); + tf::Executor executor; + executor.run(test_tf); + executor.wait_for_all(); } } // namespace buildcc diff --git a/buildcc/lib/args/test/test_args.cpp b/buildcc/lib/args/test/test_args.cpp index 697df743..8b519174 100644 --- a/buildcc/lib/args/test/test_args.cpp +++ b/buildcc/lib/args/test/test_args.cpp @@ -19,6 +19,9 @@ TEST(ArgsTestGroup, Args_BasicParse) { std::vector av{"", "--config", "configs/basic_parse.toml"}; int argc = av.size(); + CHECK_FALSE(buildcc::Args::IsInit()); + CHECK_FALSE(buildcc::Args::IsParsed()); + (void)buildcc::Args::Init(); auto &instance = buildcc::Args::Init(); // Second init does nothing when // already initialized @@ -28,6 +31,8 @@ TEST(ArgsTestGroup, Args_BasicParse) { STRCMP_EQUAL(buildcc::Args::GetProjectBuildDir().string().c_str(), "build"); CHECK(buildcc::Args::GetLogLevel() == buildcc::env::LogLevel::Trace); CHECK_TRUE(buildcc::Args::Clean()); + CHECK_TRUE(buildcc::Args::IsInit()); + CHECK_TRUE(buildcc::Args::IsParsed()); } TEST(ArgsTestGroup, Args_BasicExit) { diff --git a/buildcc/lib/args/test/test_register.cpp b/buildcc/lib/args/test/test_register.cpp index bcd6b191..2403876c 100644 --- a/buildcc/lib/args/test/test_register.cpp +++ b/buildcc/lib/args/test/test_register.cpp @@ -15,6 +15,7 @@ TEST_GROUP(RegisterTestGroup) { void teardown() { + buildcc::Reg::Deinit(); buildcc::Args::Deinit(); mock().clear(); } @@ -32,7 +33,8 @@ TEST(RegisterTestGroup, Register_Initialize) { CHECK(buildcc::Args::GetLogLevel() == buildcc::env::LogLevel::Trace); CHECK_TRUE(buildcc::Args::Clean()); - buildcc::Register reg; + buildcc::Reg::Init(); + buildcc::Reg::Init(); // Second init does nothing } TEST(RegisterTestGroup, Register_Clean) { @@ -47,9 +49,12 @@ TEST(RegisterTestGroup, Register_Clean) { CHECK(buildcc::Args::GetLogLevel() == buildcc::env::LogLevel::Trace); CHECK_TRUE(buildcc::Args::Clean()); - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectOneCall("CleanCb"); - reg.Clean([]() { mock().actualCall("CleanCb"); }); + buildcc::Reg::Call(buildcc::Args::Clean()).Func([]() { + mock().actualCall("CleanCb"); + }); + buildcc::Reg::Deinit(); buildcc::Args::Deinit(); } @@ -70,8 +75,11 @@ TEST(RegisterTestGroup, Register_Clean) { CHECK(buildcc::Args::GetLogLevel() == buildcc::env::LogLevel::Trace); CHECK_FALSE(buildcc::Args::Clean()); - buildcc::Register reg; - reg.Clean([]() { mock().actualCall("CleanCb"); }); + buildcc::Reg::Init(); + buildcc::Reg::Call(buildcc::Args::Clean()).Func([]() { + mock().actualCall("CleanCb"); + }); + buildcc::Reg::Deinit(); buildcc::Args::Deinit(); } @@ -108,18 +116,65 @@ TEST(RegisterTestGroup, Register_Build) { { buildcc::ArgToolchainState state{false, false}; - buildcc::Register reg; - reg.Build( - state, [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(state).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + (void)buildcc::Reg::GetTaskflow(); + buildcc::Reg::Deinit(); + CHECK_THROWS(std::exception, buildcc::Reg::GetTaskflow()); } { buildcc::ArgToolchainState state{true, true}; - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - state, [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(state).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Deinit(); + } + + buildcc::Project::Deinit(); + mock().checkExpectations(); +} + +TEST(RegisterTestGroup, Register_Run_PostCb) { + std::vector av{ + "", + "--config", + "configs/basic_parse.toml", + }; + int argc = av.size(); + + buildcc::ArgToolchain gcc_toolchain; + buildcc::ArgToolchain msvc_toolchain; + buildcc::Args::Init() + .AddToolchain("gcc", "Generic gcc toolchain", gcc_toolchain) + .AddToolchain("msvc", "Generic msvc toolchain", msvc_toolchain) + .Parse(argc, av.data()); + + STRCMP_EQUAL(buildcc::Args::GetProjectRootDir().string().c_str(), "root"); + STRCMP_EQUAL(buildcc::Args::GetProjectBuildDir().string().c_str(), "build"); + CHECK(buildcc::Args::GetLogLevel() == buildcc::env::LogLevel::Trace); + CHECK_TRUE(buildcc::Args::Clean()); + + // Make dummy toolchain and target + buildcc::Project::Init(fs::current_path(), fs::current_path()); + buildcc::Toolchain toolchain(buildcc::ToolchainId::Gcc, "", "", "", "", "", + ""); + buildcc::BaseTarget target("dummyT", buildcc::TargetType::Executable, + toolchain, ""); + + { + buildcc::ArgToolchainState state{false, false}; + + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(state).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + + mock().expectOneCall("Build_PostCb"); + buildcc::Reg::Run([]() { mock().actualCall("Build_PostCb"); }); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); @@ -167,43 +222,48 @@ TEST(RegisterTestGroup, Register_NoBuildAndDep) { // T0D0 { - buildcc::Register reg; - CHECK_THROWS(std::exception, reg.Dep(target, dependency)); + buildcc::Reg::Init(); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency)); + buildcc::Reg::Deinit(); } // T0D1 { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_depT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency); - CHECK_THROWS(std::exception, reg.Dep(target, dependency)); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency)); + buildcc::Reg::Deinit(); } // T1D0 { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); - CHECK_THROWS(std::exception, reg.Dep(target, dependency)); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency)); + buildcc::Reg::Deinit(); } // T1D1 { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); mock().expectNCalls(1, "BuildTask_depT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency); - reg.Dep(target, dependency); + buildcc::Reg::Toolchain(trueState).Dep(target, dependency); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); @@ -251,54 +311,56 @@ TEST(RegisterTestGroup, Register_BuildAndDep) { // T0D0 { - buildcc::Register reg; - reg.Build( - falseState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - falseState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - - reg.Dep(target, dependency); + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(falseState) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target) + .Build([](buildcc::BaseTarget &target) { (void)target; }, dependency) + .Dep(target, dependency); + buildcc::Reg::Deinit(); } // T0D1 { - buildcc::Register reg; - reg.Build( - falseState, [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(falseState) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); mock().expectNCalls(1, "BuildTask_depT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - - reg.Dep(target, dependency); + // In this case, target is not built so Dep throws + // Bad usage + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState) + .Build([](buildcc::BaseTarget &target) { (void)target; }, + dependency) + .Dep(target, dependency)); + buildcc::Reg::Deinit(); } // T1D0 { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - falseState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(falseState) + .Build([](buildcc::BaseTarget &target) { (void)target; }, dependency); - reg.Dep(target, dependency); + // In this case dependency is not built + // Bad usage + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency)); + buildcc::Reg::Deinit(); } // T1D1 { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); mock().expectNCalls(1, "BuildTask_depT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - - reg.Dep(target, dependency); + buildcc::Reg::Toolchain(trueState) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target) + .Build([](buildcc::BaseTarget &target) { (void)target; }, dependency) + .Dep(target, dependency); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); @@ -340,41 +402,41 @@ TEST(RegisterTestGroup, Register_DepDuplicate) { // Duplicate dependency with 2 Targets { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); mock().expectNCalls(1, "BuildTask_depT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - - reg.Dep(target, dependency); - CHECK_THROWS(std::exception, reg.Dep(target, dependency)); + buildcc::Reg::Toolchain(trueState) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target) + .Build([](buildcc::BaseTarget &target) { (void)target; }, dependency) + .Dep(target, dependency); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency)); + buildcc::Reg::Deinit(); } // Duplicate dependency with 3 Targets { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); mock().expectNCalls(1, "BuildTask_depT"); mock().expectNCalls(1, "BuildTask_dep2T"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency2); - - reg.Dep(dependency, dependency2); - reg.Dep(target, dependency); - reg.Dep(target, dependency2); - - CHECK_THROWS(std::exception, reg.Dep(target, dependency)); - CHECK_THROWS(std::exception, reg.Dep(target, dependency2)); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency2); + + buildcc::Reg::Toolchain(trueState).Dep(dependency, dependency2); + buildcc::Reg::Toolchain(trueState).Dep(target, dependency); + buildcc::Reg::Toolchain(trueState).Dep(target, dependency2); + + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency)); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(target, dependency2)); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); @@ -416,40 +478,41 @@ TEST(RegisterTestGroup, Register_DepCyclic) { // Immediate cyclic depdendency { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); mock().expectNCalls(1, "BuildTask_depT"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - - reg.Dep(target, dependency); - CHECK_THROWS(std::exception, reg.Dep(dependency, target)); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency); + + buildcc::Reg::Toolchain(trueState).Dep(target, dependency); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(dependency, target)); + buildcc::Reg::Deinit(); } // Duplicate dependency with 3 Targets { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); mock().expectNCalls(1, "BuildTask_depT"); mock().expectNCalls(1, "BuildTask_dep2T"); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, target); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency); - reg.Build( - trueState, [](buildcc::BaseTarget &target) { (void)target; }, - dependency2); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency); + buildcc::Reg::Toolchain(trueState).Build( + [](buildcc::BaseTarget &target) { (void)target; }, dependency2); - reg.Dep(dependency, dependency2); - reg.Dep(target, dependency); + buildcc::Reg::Toolchain(trueState).Dep(dependency, dependency2); + buildcc::Reg::Toolchain(trueState).Dep(target, dependency); // dependency2 -> dependency -> target -> dependency2 - CHECK_THROWS(std::exception, reg.Dep(dependency2, target)); + CHECK_THROWS(std::exception, + buildcc::Reg::Toolchain(trueState).Dep(dependency2, target)); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); @@ -498,43 +561,48 @@ TEST(RegisterTestGroup, Register_Test) { // FF { - buildcc::Register reg; - reg.Test(stateFail, "{executable}", target); + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(stateFail).Test("{executable}", target); + buildcc::Reg::Deinit(); } // TF { - buildcc::Register reg; - reg.Test(state1, "{executable}", target); + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(state1).Test("{executable}", target); + buildcc::Reg::Deinit(); } // FT { - buildcc::Register reg; - reg.Test(state2, "{executable}", target); + buildcc::Reg::Init(); + buildcc::Reg::Toolchain(state2).Test("{executable}", target); + buildcc::Reg::Deinit(); } // TT - // Register::Build not called + // Reg::Instance::Build not called { - buildcc::Register reg; - CHECK_THROWS(std::exception, - reg.Test(stateSuccess, "{executable}", target)); + buildcc::Reg::Init(); + CHECK_THROWS( + std::exception, + buildcc::Reg::Toolchain(stateSuccess).Test("{executable}", target)); + buildcc::Reg::Deinit(); } // Correct Usage { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test(stateSuccess, "{executable}", target); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess).Test("{executable}", target); std::vector stdout_data; std::vector stderr_data; buildcc::env::m::CommandExpect_Execute(1, true, &stdout_data, &stderr_data); - reg.RunTest(); + buildcc::Reg::Run(); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); @@ -575,105 +643,111 @@ TEST(RegisterTestGroup, Register_TestWithOutput) { // TestOutput::Type::DefaultBehaviour { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test( - stateSuccess, "{executable}", target, - buildcc::TestConfig( - {}, {}, - buildcc::TestOutput(buildcc::TestOutput::Type::DefaultBehaviour))); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess) + .Test("{executable}", target, + buildcc::TestConfig( + {}, {}, + buildcc::TestOutput( + buildcc::TestOutput::Type::DefaultBehaviour))); buildcc::env::m::CommandExpect_Execute(1, true); - reg.RunTest(); + buildcc::Reg::Run(); + buildcc::Reg::Deinit(); } // TestOutput::Type::TestPrintOnStderr { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test( - stateSuccess, "{executable}", target, - buildcc::TestConfig( - {}, {}, - buildcc::TestOutput(buildcc::TestOutput::Type::TestPrintOnStderr))); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess) + .Test("{executable}", target, + buildcc::TestConfig( + {}, {}, + buildcc::TestOutput( + buildcc::TestOutput::Type::TestPrintOnStderr))); std::vector stderr_data; buildcc::env::m::CommandExpect_Execute(1, true, nullptr, &stderr_data); - reg.RunTest(); + buildcc::Reg::Run(); + buildcc::Reg::Deinit(); } // TestOutput::Type::TestPrintOnStdout { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test( - stateSuccess, "{executable}", target, - buildcc::TestConfig( - {}, {}, - buildcc::TestOutput(buildcc::TestOutput::Type::TestPrintOnStdout))); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess) + .Test("{executable}", target, + buildcc::TestConfig( + {}, {}, + buildcc::TestOutput( + buildcc::TestOutput::Type::TestPrintOnStdout))); std::vector stdout_data; buildcc::env::m::CommandExpect_Execute(1, true, &stdout_data, nullptr); - reg.RunTest(); + buildcc::Reg::Run(); + buildcc::Reg::Deinit(); } // TestOutput::Type::TestPrintOnStderrAndStdout { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test(stateSuccess, "{executable}", target, - buildcc::TestConfig( - {}, {}, - buildcc::TestOutput( - buildcc::TestOutput::Type::TestPrintOnStderrAndStdout))); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess) + .Test("{executable}", target, + buildcc::TestConfig( + {}, {}, + buildcc::TestOutput( + buildcc::TestOutput::Type::TestPrintOnStderrAndStdout))); std::vector stdout_data; std::vector stderr_data; buildcc::env::m::CommandExpect_Execute(1, true, &stdout_data, &stderr_data); - reg.RunTest(); + buildcc::Reg::Run(); + buildcc::Reg::Deinit(); } // TestOutput::Type::UserRedirect { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test(stateSuccess, "{executable}", target, - buildcc::TestConfig( - {}, {}, - buildcc::TestOutput(buildcc::TestOutput::Type::UserRedirect, - nullptr, nullptr))); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess) + .Test("{executable}", target, + buildcc::TestConfig( + {}, {}, + buildcc::TestOutput(buildcc::TestOutput::Type::UserRedirect, + nullptr, nullptr))); buildcc::env::m::CommandExpect_Execute(1, true); - reg.RunTest(); + buildcc::Reg::Run(); + buildcc::Reg::Deinit(); } // TestOutput::Type::UserRedirect { - buildcc::Register reg; + buildcc::Reg::Init(); mock().expectNCalls(1, "BuildTask_dummyT"); - reg.Build( - stateSuccess, [](buildcc::BaseTarget &target) { (void)target; }, - target); - reg.Test( - stateSuccess, "{executable}", target, - buildcc::TestConfig( - {}, {}, buildcc::TestOutput(buildcc::TestOutput::Type(65535)))); - CHECK_THROWS(std::exception, reg.RunTest()); + buildcc::Reg::Toolchain(stateSuccess) + .Build([](buildcc::BaseTarget &target) { (void)target; }, target); + buildcc::Reg::Toolchain(stateSuccess) + .Test( + "{executable}", target, + buildcc::TestConfig( + {}, {}, buildcc::TestOutput(buildcc::TestOutput::Type(65535)))); + CHECK_THROWS(std::exception, buildcc::Reg::Run()); + buildcc::Reg::Deinit(); } buildcc::Project::Deinit(); diff --git a/buildexe/buildexe.cpp b/buildexe/buildexe.cpp index 0af85b3f..16549953 100644 --- a/buildexe/buildexe.cpp +++ b/buildexe/buildexe.cpp @@ -53,8 +53,8 @@ int main(int argc, char **argv) { // TODO, Add libraries (git cloned) // TODO, Add extension (git cloned) - Register reg; - reg.Clean(clean_cb); + Reg::Init(); + Reg::Call(Args::Clean()).Func(clean_cb); // Host Toolchain BaseToolchain toolchain = @@ -66,7 +66,7 @@ int main(int argc, char **argv) { } // Build Target - BuildEnvSetup build_setup(reg, toolchain, buildexe_args); + BuildEnvSetup build_setup(toolchain, buildexe_args); build_setup.ConstructTarget(); // Run Target if script mode diff --git a/buildexe/include/buildexe/build_env_setup.h b/buildexe/include/buildexe/build_env_setup.h index d73c9e9c..e36983d4 100644 --- a/buildexe/include/buildexe/build_env_setup.h +++ b/buildexe/include/buildexe/build_env_setup.h @@ -31,9 +31,9 @@ class BuildEnvSetup { static constexpr const char *const kUserTargetName = "UserTarget"; public: - BuildEnvSetup(Register ®, const BaseToolchain &toolchain, + BuildEnvSetup(const BaseToolchain &toolchain, const BuildExeArgs &buildexe_args) - : reg_(reg), toolchain_(toolchain), buildexe_args_(buildexe_args) { + : toolchain_(toolchain), buildexe_args_(buildexe_args) { state_.build = true; } @@ -62,7 +62,6 @@ class BuildEnvSetup { void DepUserTargetOnBuildcc(); private: - Register ®_; const BaseToolchain &toolchain_; const BuildExeArgs &buildexe_args_; diff --git a/buildexe/src/build_env_setup.cpp b/buildexe/src/build_env_setup.cpp index 2bfcac96..72b17fba 100644 --- a/buildexe/src/build_env_setup.cpp +++ b/buildexe/src/build_env_setup.cpp @@ -29,7 +29,7 @@ void BuildEnvSetup::ConstructTarget() { // user target ConstructUserTarget(); } - reg_.RunBuild(); + Reg::Run(); } void BuildEnvSetup::RunUserTarget(const ArgScriptInfo &arg_script_info) { @@ -76,7 +76,7 @@ void BuildEnvSetup::ConstructUserTargetWithBuildcc() { void BuildEnvSetup::BuildccTargetSetup() { const fs::path &buildcc_base = BuildccHome::GetBuildccBaseDir(); auto &buildcc_package = storage_.Add( - kBuildccPackageName, reg_, toolchain_, + kBuildccPackageName, toolchain_, TargetEnv(buildcc_base, buildcc_base / "_build_exe")); buildcc_package.Setup(state_); } @@ -206,12 +206,12 @@ struct BuildExeLibDir {{ } void BuildEnvSetup::UserTargetBuild() { - reg_.Build( - state_, [](BaseTarget &target) { target.Build(); }, GetUserTarget()); + Reg::Toolchain(state_).Build([](BaseTarget &target) { target.Build(); }, + GetUserTarget()); } void BuildEnvSetup::DepUserTargetOnBuildcc() { - reg_.Dep(GetUserTarget(), GetBuildcc()); + Reg::Toolchain(state_).Dep(GetUserTarget(), GetBuildcc()); } } // namespace buildcc diff --git a/docs/source/examples/hybrid.rst b/docs/source/examples/hybrid.rst index abc73c73..38c611a8 100644 --- a/docs/source/examples/hybrid.rst +++ b/docs/source/examples/hybrid.rst @@ -14,20 +14,18 @@ We are only using a single Toolchain - Target pair :linenos: int main(int argc, char ** argv) { - // Args module to get data from the command line or .toml file passed in through --config - Args args; - // Register your [toolchain.{name}] // In this case it will be [toolchain.gcc] ArgToolchain arg_gcc; - args.AddToolchain("gcc", "Generic gcc toolchain", arg_gcc); - // Parse the arguments from the command line - args.Parse(argc, argv); + // Args module to get data from the command line or .toml file passed in through --config + Args::Init() + .AddToolchain("gcc", "Generic gcc toolchain", arg_gcc) + .Parse(argc, argv); // Register module - Register reg(args); - reg.Clean(clean_cb); + Reg::Init(); + Reg::Call(Args::Clean()).Func(clean_cb); // TODO, Write your target builds here // See examples below @@ -75,14 +73,13 @@ Compile a single source with a single GCC compiler. ExecutableTarget_gcc hello_world("hello_world", gcc, ""); // Select your builds and tests using the .toml files - reg.Build(arg_gcc.state, hello_world_build_cb, hello_world); - reg.Test(arg_gcc.state, "{executable}", hello_world); + Reg::Toolchain(arg_gcc.state) + .Func([&]() { gcc.Verify(); }) + .Build(arg_gcc.state, hello_world_build_cb, hello_world) + .Test(arg_gcc.state, "{executable}", hello_world); - // Build Target - reg.RunBuild(); - - // Test Target - reg.RunTest(); + // Build and Test Target + Reg::Run(); } static void hello_world_build_cb(BaseTarget &target) { @@ -100,23 +97,21 @@ We are using multiple Toolchain - Target pairs :linenos: int main(int argc, char ** argv) { - // Args module to get data from the command line or .toml file passed in through --config - Args args; - // Register your [toolchain.{name}] // In this case it will be [toolchain.gcc] and [toolchain.msvc] ArgToolchain arg_gcc; ArgToolchain arg_msvc; - args.AddToolchain("gcc", "Generic gcc toolchain", arg_gcc); - args.AddToolchain("msvc", "Generic msvc toolchain", arg_msvc); - // NOTE, You can add more toolchains here as per your project requirement - // Parse the arguments from the command line - args.Parse(argc, argv); + // Args module to get data from the command line or .toml file passed in through --config + Args::Init() + .AddToolchain("gcc", "Generic gcc toolchain", arg_gcc) + .AddToolchain("msvc", "Generic msvc toolchain", arg_msvc) + .Parse(argc, argv); + // NOTE, You can add more toolchains here as per your project requirement // Register module - Register reg(args); - reg.Clean(clean_cb); + Reg::Init(); + Reg::Call(Args::Clean()).Func(clean_cb); // TODO, Write your target builds here // See examples below @@ -167,30 +162,30 @@ Similar to lowlevel GCC Flags example for both the GCC and MSVC compiler // See Multiple Boilerplate Toolchain_gcc gcc; - Toolchain_msvc msvc; - ExecutableTarget_gcc g_cppflags("cppflags", gcc, "files"); - ExecutableTarget_msvc m_cppflags("cppflags", msvc, "files"); ExecutableTarget_gcc g_cflags("cflags", gcc, "files"); + // Select your builds and tests using the .toml files + Reg::Toolchain(arg_gcc.state) + .Func([&](){ gcc.Verify(); }) + .Build(cppflags_build_cb, g_cppflags) + .Build(cflags_build_cb, g_cflags) + .Test("{executable}", g_cppflags) + .Test("{executable}", g_cflags); + + Toolchain_msvc msvc; + ExecutableTarget_msvc m_cppflags("cppflags", msvc, "files"); ExecutableTarget_msvc m_cflags("cflags", msvc, "files"); + Reg::Toolchain(arg_msvc.state) + .Func([&](){ msvc.Verify(); }) + .Build(cppflags_build_cb, m_cppflags) + .Build(cflags_build_cb, m_cflags) + .Test("{executable}", m_cppflags) + .Test("{executable}", m_cflags); - // Select your builds and tests using the .toml files - reg.Build(arg_gcc.state, cppflags_build_cb, g_cppflags); - reg.Build(arg_msvc.state, cppflags_build_cb, m_cppflags); - reg.Build(arg_gcc.state, cflags_build_cb, g_cflags); - reg.Build(arg_msvc.state, cflags_build_cb, m_cflags); - - // Test steps - reg.Test(arg_gcc.state, "{executable}", g_cppflags); - reg.Test(arg_msvc.state, "{executable}", m_cppflags); - reg.Test(arg_gcc.state, "{executable}", g_cflags); - reg.Test(arg_msvc.state, "{executable}", m_cflags); - - // Build Target - reg.RunBuild(); - - // Test Target - reg.RunTest(); + // Build and Test target + Reg::Run(); + + return 0; } static void cppflags_build_cb(BaseTarget &cppflags) { @@ -301,7 +296,6 @@ For end users consuming third party libraries .. code-block:: cpp :linenos: - :emphasize-lines: 18 #include "build.foo.h" @@ -312,13 +306,16 @@ For end users consuming third party libraries Toolchain_gcc gcc; Toolchain_msvc msvc; - ExecutableTarget_gcc g_foolib("foolib", gcc, ""); - ExecutableTarget_msvc m_foolib("foolib", msvc, ""); + ExecutableTarget_gcc g_foolib("foolib", gcc, TargetEnv("...")); + ExecutableTarget_msvc m_foolib("foolib", msvc, TargetEnv("..."); - reg.Build(arg_gcc.state, foolib_build_cb, g_foolib); - reg.Build(arg_msvc.state, foolib_build_cb, m_foolib); + Reg::Toolchain(arg_gcc.state) + .Build(foolib_build_cb, g_foolib); + + Reg::Toolchain(arg_msvc.state) + .Build(foolib_build_cb, m_foolib); - reg.RunBuild(); + Reg::Run(); } static void foolib_build_cb(BaseTarget &target) { @@ -334,48 +331,43 @@ For super customized targets and toolchains .. code-block:: cpp :linenos: - :emphasize-lines: 12,13,30,34,35,36 int main(int argc, char ** argv) { - Args args; ArgToolchain arg_gcc; ArgToolchain arg_msvc; ArgToolchain toolchain_clang_gnu; ArgTarget target_clang_gnu; - args.AddToolchain("gcc", "Generic gcc toolchain", arg_gcc); - args.AddToolchain("msvc", "Generic msvc toolchain", arg_msvc); - // Add your custom toolchain - target to the command line - args.AddToolchain("clang_gnu", "Clang GNU toolchain", toolchain_clang_gnu); - args.AddTarget("clang_gnu", "Clang GNU target", target_clang_gnu); - - args.Parse(argc, argv); + Args::Init() + .AddToolchain("gcc", "Generic gcc toolchain", arg_gcc) + .AddToolchain("msvc", "Generic msvc toolchain", arg_msvc) + .AddToolchain("clang_gnu", "Clang GNU toolchain", toolchain_clang_gnu) + .AddTarget("clang_gnu", "Clang GNU target", target_clang_gnu) + .Parse(argc, argv); // Additional boilerplate // Supplied at compile time Toolchain_gcc gcc; Toolchain_msvc msvc; - - ExecutableTarget_gcc g_foolib("foolib", gcc, ""); - ExecutableTarget_msvc m_foolib("foolib", msvc, ""); - - reg.Build(arg_gcc.state, foolib_build_cb, g_foolib); - reg.Build(arg_msvc.state, foolib_build_cb, m_foolib); - // Get custom toolchain from the command line, supplied at run time BaseToolchain clang = toolchain_clang_gnu.ConstructToolchain(); + ExecutableTarget_gcc g_foolib("foolib", gcc, ""); + ExecutableTarget_msvc m_foolib("foolib", msvc, ""); // Get compile_command and link_command from the command line - TargetConfig config; - config.compile_command = target_clang_gnu.compile_command; - config.link_command = target_clang_gnu.link_command; - Target_custom c_foolib("CFoolib.exe", TargetType::Executable, clang, "", config); - reg.Build(toolchain_clang_gnu.state, foolib_build_cb, c_foolib); + Target_custom c_foolib("CFoolib.exe", TargetType::Executable, clang, "", target_clang_gnu.GetTargetConfig()); + + Reg::Toolchain(arg_gcc.state) + .Build(foolib_build_cb, g_foolib); + Reg::Toolchain(arg_msvc.state) + .Build(foolib_build_cb, m_foolib); + Reg::Toolchain(toolchain_clang_gnu.state) + .Build( foolib_build_cb, c_foolib); // Build targets - reg.RunBuild(); + Reg::Run(); } static void foolib_build_cb(BaseTarget &target) { @@ -387,7 +379,6 @@ For super customized targets and toolchains .. code-block:: toml :linenos: - :emphasize-lines: 4,18 # See Multiple boilerplate .toml file @@ -418,7 +409,6 @@ Precompile header usage with GCC and MSVC compilers .. code-block:: cpp :linenos: - :emphasize-lines: 8,9,10,36,37,38 // Modified Lowlevel GCC Flags example for PCH @@ -487,7 +477,6 @@ Chain **Generators** and **Targets** using the ``Register`` module .. code-block:: cpp :linenos: - :emphasize-lines: 7,8,17,18 int main(int argc, char ** argv) { // See Multiple Boilerplate @@ -496,17 +485,19 @@ Chain **Generators** and **Targets** using the ``Register`` module Toolchain_msvc msvc; BaseGenerator cpp_generator("cpp_generator", ""); - reg.Build(cpp_generator_cb, cpp_generator); + Reg::Call().Build(cpp_generator_cb, cpp_generator); ExecutableTarget_gcc g_cpptarget("cpptarget", gcc, ""); - reg.Build(arg_gcc.state, cpp_target_cb, g_cpptarget, cpp_generator); + Reg::Toolchain(arg_gcc.state) + .Func([&](){ gcc.Verify(); }) + .Build(cpp_target_cb, g_cpptarget, cpp_generator) + .Dep(g_cpptarget, cpp_generator); ExecutableTarget_msvc m_cpptarget("cpptarget", msvc, ""); - reg.Build(arg_msvc.state, cpp_target_cb, m_cpptarget, cpp_generator); - - // cpp_generator runs before g_cpptarget and m_cpptarget - reg.Dep(g_cpptarget, cpp_generator); - reg.Dep(m_cpptarget, cpp_generator); + Reg::Toolchain(arg_msvc.state) + .Func([&](){ msvc.Verify(); }) + .Build(cpp_target_cb, m_cpptarget, cpp_generator) + .Dep(m_cpptarget, cpp_generator); } // Use a python generator to create main.cpp @@ -537,7 +528,6 @@ Target Info .. code-block:: cpp :linenos: - :emphasize-lines: 8,9 int main(int argc, char ** argv) { // See Multiple boilerplate @@ -546,14 +536,17 @@ Target Info Toolchain_msvc msvc; // TargetInfo - TargetInfo genericadd_ho("files"); - reg.Callback(genericadd_ho_cb, genericadd_ho); - + TargetInfo g_genericadd_ho(gcc, "files"); ExecutableTarget_gcc g_genericadd1("generic_add_1", gcc, "files"); - ExecutableTarget_msvc m_genericadd1("generic_add_1", msvc, "files"); + Reg::Toolchain(arg_gcc.state) + .Func(genericadd_ho_cb, g_genericadd_ho) + .Build(genericadd1_build_cb, g_genericadd1, g_genericadd_ho); - reg.Build(arg_gcc.state, genericadd1_build_cb, g_genericadd1, genericadd_ho); - reg.Build(arg_msvc.state, genericadd1_build_cb, m_genericadd1, genericadd_ho); + TargetInfo m_genericadd_ho(msvc, "files"); + ExecutableTarget_msvc m_genericadd1("generic_add_1", msvc, "files"); + Reg::Toolchain(arg_msvc.state) + .Func(genericadd_ho_cb, m_genericadd_ho) + .Build(genericadd1_build_cb, m_genericadd1, m_genericadd_ho); } // HO library contains include dirs and header files which are copied into executable target diff --git a/docs/source/getting_started/buildexe_package_manager.rst b/docs/source/getting_started/buildexe_package_manager.rst index 161e09ad..5e9493c8 100644 --- a/docs/source/getting_started/buildexe_package_manager.rst +++ b/docs/source/getting_started/buildexe_package_manager.rst @@ -192,7 +192,6 @@ Write your C++ "script" .. code-block:: cpp :linenos: - :emphasize-lines: 4,8,38,39,40,43,44,47,48,52,79 #include "buildcc.h" @@ -210,23 +209,22 @@ Write your C++ "script" static void hello_world_build_cb(BaseTarget &target, BaseTarget &fmt_lib); int main(int argc, char **argv) { - // 1. Get arguments - Args args; + // Get arguments ArgToolchain arg_gcc; - args.AddToolchain("gcc", "Generic gcc toolchain", arg_gcc); - args.Parse(argc, argv); - // 2. Initialize your environment - Register reg(args); + Args::Init() + .AddToolchain("gcc", "Generic gcc toolchain", arg_gcc) + .Parse(argc, argv); - // 3. Pre-build steps - reg.Clean(clean_cb); + // Initialize your environment + Reg::Init(); - // 4. Build steps + // Pre-build steps + Reg::Call(Args::Clean().Func(clean_cb); + + // Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - auto verified_toolchains = gcc.Verify(); - env::assert_fatal(!verified_toolchains.empty(), "GCC Toolchain not found"); // Setup your [Library]Target_[toolchain] fmtlib instance // Update your TargetEnv to point to `BuildExeLibDir::fmt` folder @@ -237,29 +235,24 @@ Write your C++ "script" // We use the build.fmt.h and build.fmt.cpp APIs to define how we build our fmtlib FmtConfig fmt_config; - reg.Build(arg_gcc.state, build_fmt_cb, fmt_lib, fmt_config); // Define our hello world executable ExecutableTarget_gcc hello_world("hello_world", gcc, ""); - reg.Build(arg_gcc.state, hello_world_build_cb, hello_world, fmt_lib); - + // Fmt lib is a dependency to the Hello world executable // This means that fmt lib is guaranteed to be built before the hello world executable - reg.Dep(hello_world, fmt_lib); - - // 5. Test steps i.e Hello world is automatically run - reg.Test(arg_gcc.state, "{executable}", hello_world); + Reg::Toolchain(arg_gcc.state) + .Build(arg_gcc.state, build_fmt_cb, fmt_lib, fmt_config) + .Build(hello_world_build_cb, hello_world, fmt_lib) + .Dep(hello_world, fmt_lib) + .Test("{executable}", hello_world);; + - // 6. Build Target + // Build and Test Target // Builds libfmt.a and ./hello_world - reg.RunBuild(); - - // 7. Test Target - // Executes ./hello_world - // Output -> Hello World - reg.RunTest(); + Reg::Run(); - // 8. Post Build steps + // Post Build steps // - Clang Compile Commands plugin::ClangCompileCommands({&hello_world}).Generate(); // - Graphviz dump diff --git a/docs/source/getting_started/buildexe_script_example.rst b/docs/source/getting_started/buildexe_script_example.rst index 23a3f211..ca229500 100644 --- a/docs/source/getting_started/buildexe_script_example.rst +++ b/docs/source/getting_started/buildexe_script_example.rst @@ -84,7 +84,6 @@ We then setup our main **toolchain**-**target** pairs. Highlighted below .. code-block:: cpp :linenos: - :emphasize-lines: 25,26,27,29,30 :caption: build.helloworld.cpp #include "buildcc.h" @@ -96,32 +95,33 @@ We then setup our main **toolchain**-**target** pairs. Highlighted below void hello_world_build_cb(BaseTarget & target); int main(int argc, char ** argv) { - // Step 1. Setup your args - Args args; + // Setup your args ArgToolchain arg_gcc; - args.AddToolchain("gcc", "GCC toolchain", arg_gcc); - args.Parse(argc, argv); - // Step 2. Register - Register reg(args); + Args::Init() + .AddToolchain("gcc", "GCC toolchain", arg_gcc) + .Parse(argc, argv); - // Step 3. Pre build steps + // Register + Reg::Init(); + + // Pre build steps // for example. clean your environment - reg.Clean(clean_cb); + Reg::Call(Args::Clean()).Func(clean_cb); - // Step 4. Build steps + // Build steps // Main setup Toolchain_gcc gcc; - auto verified_gcc_toolchains = gcc.Verify(); - env::assert_fatal(!verified_gcc_toolchains.empty(), "GCC toolchain not found"); - ExecutableTarget_gcc hello_world("hello_world", gcc, ""); - reg.Build(arg_gcc.state, hello_world_build_cb, hello_world); - // Step 5. Build your targets - reg.RunBuild(); + Reg::Toolchain(arg_gcc.state) + .Func([&](){ gcc.Verify() }) + .Build(hello_world_build_cb, hello_world); + + // Build your targets + Reg::Run(); - // Step 6. Post build steps + // Post build steps // for example. clang compile commands database plugin::ClangCompileCommands({&hello_world}).Generate(); diff --git a/docs/source/user_api/args.rst b/docs/source/user_api/args.rst index a0c8d482..e21db691 100644 --- a/docs/source/user_api/args.rst +++ b/docs/source/user_api/args.rst @@ -6,42 +6,55 @@ args.h .. doxygenclass:: buildcc::Args -.. doxygenclass:: buildcc::Args::Instance +.. doxygenstruct:: buildcc::ArgCustom .. doxygenstruct:: buildcc::ArgToolchainState .. doxygenstruct:: buildcc::ArgToolchain +.. doxygenstruct:: buildcc::ArgTarget + Example --------- .. code-block:: cpp :linenos: + using namespace buildcc; + + struct CustomData : ArgCustom { + void Add(CLI::App & app) override { + // setup your app from data1, data2, data3, data... + // NOTE: The Add method should not be invoked by the user + // NOTE: The Add method is only expected to be invoked once, not multiple times. + } + + std::string data1; + int data2; + float data3; + // etc + }; + int main(int argc, char ** argv) { - Args args; ArgToolchain arg_gcc_toolchain; - args.AddToolchain("gcc", "Generic GCC toolchain", arg_gcc_toolchain); - - // TODO, Add ArgTarget example (Currently incomplete) - args.Parse(argc, argv); + ArgCustomData custom_data; + Args::Init() + .AddToolchain("gcc", "Generic GCC toolchain", arg_gcc_toolchain) + .AddCustomCallback([](CLI::App &app) {}); + .AddCustomData(custom_data); + .Parse(argc, argv); // Root - args.GetProjectRootDir(); // Contains ``root_dir`` value - args.GetProjectBuildDir(); // Contains ``build_dir`` value - args.GetLogLevel(); // Contains ``loglevel`` enum - args.Clean(); // Contains ``clean`` value + Args::GetProjectRootDir(); // Contains ``root_dir`` value + Args::GetProjectBuildDir(); // Contains ``build_dir`` value + Args::GetLogLevel(); // Contains ``loglevel`` enum + Args::Clean(); // Contains ``clean`` value // Toolchain // .build, .test arg_gcc_toolchain.state; // .id, .name, .asm_compiler, .c_compiler, .cpp_compiler, .archiver, .linker -> BaseToolchain BaseToolchain gcc_toolchain = arg_gcc_toolchain.ConstructToolchain(); - - // Underlying CLI11 library - auto & app = args.Ref(); - const auto & app = args.ConstRef(); - return 0; } diff --git a/docs/source/user_api/register.rst b/docs/source/user_api/register.rst index 77033451..4d8d5795 100644 --- a/docs/source/user_api/register.rst +++ b/docs/source/user_api/register.rst @@ -4,9 +4,7 @@ Register register.h ----------- -.. doxygenclass:: buildcc::Register - :members: Register, Clean, Callback, CallbackIf, Build, Dep, Test, RunBuild, RunTest - +.. doxygenclass:: buildcc::Reg test_info.h ------------- @@ -26,19 +24,20 @@ Example static void callback_usage_func(const BigObj & cobj, BigObj & obj); int main(int argc, char ** argv) { - Args args; - args.Parse(argc, argv); + Args::Init() + .Parse(argc, argv); + + Reg::Init(); + Reg::Call(Args::Clean()).Func([](){ + fs::remove_all(Project::GetBuildDir()); + }) - Register reg(args); - reg.Clean([](){ - fs::remove_all(env::get_project_build_dir()); - }); BigObj obj; - reg.Callback(callback_usage_func, BigObj(), obj); + Reg::Call().Func(callback_usage_func, BigObj(), obj) bool expression = true; // false - reg.CallbackIf(expression, callback_usage_func, BigObj(), obj); + Reg::Call(expression).Func(callback_usage_func, BigObj(), obj) // Example snippets of these given in Target API // Build diff --git a/example/buildexe/libs/build.main.cpp b/example/buildexe/libs/build.main.cpp index c051e83b..64301e32 100644 --- a/example/buildexe/libs/build.main.cpp +++ b/example/buildexe/libs/build.main.cpp @@ -16,49 +16,42 @@ static void clean_cb(); static void hello_world_build_cb(BaseTarget &target, BaseTarget &fmt_lib); int main(int argc, char **argv) { - // 1. Get arguments - Args::Init(); + // Get arguments ArgToolchain arg_gcc; - Args::AddToolchain("gcc", "Generic gcc toolchain", arg_gcc); - Args::Parse(argc, argv); + Args::Init() + .AddToolchain("gcc", "Generic gcc toolchain", arg_gcc) + .Parse(argc, argv); - // 2. Initialize your environment - Register reg; + // Initialize your environment + Reg::Init(); - // 3. Pre-build steps - reg.Clean(clean_cb); + // Pre-build steps + Reg::Call(Args::Clean()).Func(clean_cb); - // 4. Build steps + // Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - auto verified_toolchains = gcc.Verify(); - env::assert_fatal(!verified_toolchains.empty(), "GCC Toolchain not found"); StaticTarget_gcc fmt_lib( "libfmt", gcc, TargetEnv(BuildExeLibDir::fmt, Project::GetBuildDir() / "fmt")); FmtConfig fmt_config; - reg.Build(arg_gcc.state, build_fmt_cb, fmt_lib, fmt_config); - ExecutableTarget_gcc hello_world("hello_world", gcc, ""); - reg.Build(arg_gcc.state, hello_world_build_cb, hello_world, fmt_lib); - - reg.Dep(hello_world, fmt_lib); - - // 5. Test steps - reg.Test(arg_gcc.state, "{executable}", hello_world); - - // 6. Build Target - reg.RunBuild(); + Reg::Toolchain(arg_gcc.state) + .Func([&]() { gcc.Verify(); }) + .Build(build_fmt_cb, fmt_lib, fmt_config) + .Build(hello_world_build_cb, hello_world, fmt_lib) + .Dep(hello_world, fmt_lib) + .Test("{executable}", hello_world); - // 7. Test Target - reg.RunTest(); + // Build Target + Reg::Run(); - // 8. Post Build steps + // Post Build steps // - Clang Compile Commands plugin::ClangCompileCommands({&hello_world}).Generate(); // - Graphviz dump - std::cout << reg.GetTaskflow().dump() << std::endl; + std::cout << Reg::GetTaskflow().dump() << std::endl; return 0; } diff --git a/example/hybrid/custom_target/build.main.cpp b/example/hybrid/custom_target/build.main.cpp index 6b0829c0..c93b618c 100644 --- a/example/hybrid/custom_target/build.main.cpp +++ b/example/hybrid/custom_target/build.main.cpp @@ -8,49 +8,44 @@ static void foolib_build_cb(BaseTarget &target); static constexpr std::string_view EXE = "build"; int main(int argc, char **argv) { - // 1. Get arguments + // Get arguments ArgToolchain arg_gcc; ArgToolchain arg_msvc; - ArgToolchain toolchain_clang_gnu; - ArgTarget target_clang_gnu; + ArgToolchain arg_toolchain_clang_gnu; + ArgTarget arg_target_clang_gnu; Args::Init() .AddToolchain("gcc", "Generic gcc toolchain", arg_gcc) .AddToolchain("msvc", "Generic msvc toolchain", arg_msvc) - .AddToolchain("clang_gnu", "Clang GNU toolchain", toolchain_clang_gnu) - .AddTarget("clang_gnu", "Clang GNU target", target_clang_gnu) + .AddToolchain("clang_gnu", "Clang GNU toolchain", arg_toolchain_clang_gnu) + .AddTarget("clang_gnu", "Clang GNU target", arg_target_clang_gnu) .Parse(argc, argv); - // 2. Initialize your environment - Register reg; + // Initialize your environment + Reg::Init(); - // 3. Pre-build steps - reg.Clean(clean_cb); + // Pre-build steps + Reg::Call(Args::Clean()).Func(clean_cb); - // 4. Build steps + // Build steps Toolchain_gcc gcc; - Toolchain_msvc msvc; - ExecutableTarget_gcc g_foolib("foolib", gcc, ""); - ExecutableTarget_msvc m_foolib("foolib", msvc, ""); + Reg::Toolchain(arg_gcc.state).Build(foolib_build_cb, g_foolib); - reg.Build(arg_gcc.state, foolib_build_cb, g_foolib); - reg.Build(arg_msvc.state, foolib_build_cb, m_foolib); + Toolchain_msvc msvc; + ExecutableTarget_msvc m_foolib("foolib", msvc, ""); + Reg::Toolchain(arg_msvc.state).Build(foolib_build_cb, m_foolib); // * NOTE, This is how we add our custom toolchain - BaseToolchain clang = toolchain_clang_gnu.ConstructToolchain(); - - // * M2, Get from Args (see build_linux.toml or build_win.toml files) - TargetConfig config; - config.compile_command = target_clang_gnu.compile_command; - config.link_command = target_clang_gnu.link_command; + BaseToolchain clang = arg_toolchain_clang_gnu.ConstructToolchain(); Target_custom c_foolib("CFoolib.exe", TargetType::Executable, clang, "", - config); - reg.Build(toolchain_clang_gnu.state, foolib_build_cb, c_foolib); + arg_target_clang_gnu.GetTargetConfig()); + Reg::Toolchain(arg_toolchain_clang_gnu.state) + .Build(foolib_build_cb, c_foolib); - // 5. - reg.RunBuild(); + // + Reg::Run(); - // 6. + // plugin::ClangCompileCommands({&g_foolib, &m_foolib, &c_foolib}).Generate(); return 0; diff --git a/example/hybrid/dep_chaining/build.cpp b/example/hybrid/dep_chaining/build.cpp index 49722ad4..3baddfe0 100644 --- a/example/hybrid/dep_chaining/build.cpp +++ b/example/hybrid/dep_chaining/build.cpp @@ -15,7 +15,7 @@ static void cpp_generator_cb(BaseGenerator &generator); static void c_generator_cb(BaseGenerator &generator); int main(int argc, char **argv) { - // 1. Get arguments + // Get arguments ArgToolchain arg_gcc; ArgToolchain arg_msvc; Args::Init() @@ -23,54 +23,45 @@ int main(int argc, char **argv) { .AddToolchain("msvc", "Generic msvc toolchain", arg_msvc) .Parse(argc, argv); - // 2. Initialize your environment - Register reg; + // Initialize your environment + Reg::Init(); - // 3. Pre-build steps - reg.Clean(clean_cb); + // Pre-build steps + Reg::Call(Args::Clean()).Func(clean_cb); - // 4. Build steps - // Explicit toolchain - target pairs - Toolchain_gcc gcc; - Toolchain_msvc msvc; - - // CPP + // Generator BaseGenerator cpp_generator("cpp_generator", ""); - reg.Build(cpp_generator_cb, cpp_generator); - - ExecutableTarget_gcc g_cpptarget("cpptarget", gcc, ""); - reg.Build(arg_gcc.state, cpp_target_cb, g_cpptarget, cpp_generator); - - ExecutableTarget_msvc m_cpptarget("cpptarget", msvc, ""); - reg.Build(arg_msvc.state, cpp_target_cb, m_cpptarget, cpp_generator); - - reg.Dep(g_cpptarget, cpp_generator); - reg.Dep(m_cpptarget, cpp_generator); - - // C BaseGenerator c_generator("c_generator", ""); - reg.Build(c_generator_cb, c_generator); + Reg::Call() + .Build(cpp_generator_cb, cpp_generator) + .Build(c_generator_cb, c_generator); + // Build steps + // Explicit toolchain - target pairs + Toolchain_gcc gcc; + ExecutableTarget_gcc g_cpptarget("cpptarget", gcc, ""); ExecutableTarget_gcc g_ctarget("ctarget", gcc, ""); - reg.Build(arg_gcc.state, c_target_cb, g_ctarget, c_generator); + Reg::Toolchain(arg_gcc.state) + .Build(cpp_target_cb, g_cpptarget, cpp_generator) + .Build(c_target_cb, g_ctarget, c_generator) + .Dep(g_cpptarget, cpp_generator) + .Dep(g_ctarget, c_generator) + .Test("{executable}", g_cpptarget) + .Test("{executable}", g_ctarget); + Toolchain_msvc msvc; + ExecutableTarget_msvc m_cpptarget("cpptarget", msvc, ""); ExecutableTarget_msvc m_ctarget("ctarget", msvc, ""); - reg.Build(arg_msvc.state, c_target_cb, m_ctarget, c_generator); - - reg.Dep(g_ctarget, c_generator); - reg.Dep(m_ctarget, c_generator); - - // Tests - reg.Test(arg_gcc.state, "{executable}", g_cpptarget); - reg.Test(arg_gcc.state, "{executable}", g_ctarget); - reg.Test(arg_msvc.state, "{executable}", m_cpptarget); - reg.Test(arg_msvc.state, "{executable}", m_ctarget); - - // 6. Build Target - reg.RunBuild(); + Reg::Toolchain(arg_msvc.state) + .Build(cpp_target_cb, m_cpptarget, cpp_generator) + .Build(c_target_cb, m_ctarget, c_generator) + .Dep(m_cpptarget, cpp_generator) + .Dep(m_ctarget, c_generator) + .Test("{executable}", m_cpptarget) + .Test("{executable}", m_ctarget); - // 7. Test Target - reg.RunTest(); + // Build and Test + Reg::Run(); // - Clang Compile Commands plugin::ClangCompileCommands( @@ -78,7 +69,7 @@ int main(int argc, char **argv) { .Generate(); // - Plugin Graph - std::string output = reg.GetTaskflow().dump(); + std::string output = Reg::GetTaskflow().dump(); const bool saved = env::save_file("graph.dot", output, false); env::assert_fatal(saved, "Could not save graph.dot file"); diff --git a/example/hybrid/external_lib/build.main.cpp b/example/hybrid/external_lib/build.main.cpp index b181281b..d74b63ef 100644 --- a/example/hybrid/external_lib/build.main.cpp +++ b/example/hybrid/external_lib/build.main.cpp @@ -19,23 +19,22 @@ int main(int argc, char **argv) { .Parse(argc, argv); // 2. Initialize your environment - Register reg; + Reg::Init(); // 3. Pre-build steps - reg.Clean(clean_cb); + Reg::Call(Args::Clean()).Func(clean_cb); // 4. Build steps Toolchain_gcc gcc; - Toolchain_msvc msvc; - ExecutableTarget_gcc g_foolib("cppflags", gcc, ""); - ExecutableTarget_msvc m_foolib("cppflags", msvc, ""); + Reg::Toolchain(arg_gcc.state).Build(foolib_build_cb, g_foolib); - reg.Build(arg_gcc.state, foolib_build_cb, g_foolib); - reg.Build(arg_msvc.state, foolib_build_cb, m_foolib); + Toolchain_msvc msvc; + ExecutableTarget_msvc m_foolib("cppflags", msvc, ""); + Reg::Toolchain(arg_msvc.state).Build(foolib_build_cb, m_foolib); // 5. - reg.RunBuild(); + Reg::Run(); // 6. plugin::ClangCompileCommands({&g_foolib, &m_foolib}).Generate(); diff --git a/example/hybrid/foolib/build.main.cpp b/example/hybrid/foolib/build.main.cpp index dc723d7b..aa005469 100644 --- a/example/hybrid/foolib/build.main.cpp +++ b/example/hybrid/foolib/build.main.cpp @@ -19,23 +19,22 @@ int main(int argc, char **argv) { .Parse(argc, argv); // 2. Initialize your environment - Register reg; + Reg::Init(); // 3. Pre-build steps - reg.Clean(clean_cb); + Reg::Call(Args::Clean()).Func(clean_cb); // 4. Build steps Toolchain_gcc gcc; - Toolchain_msvc msvc; - ExecutableTarget_gcc g_foolib("foolib", gcc, ""); - ExecutableTarget_msvc m_foolib("foolib", msvc, ""); + Reg::Toolchain(arg_gcc.state).Build(foolib_build_cb, g_foolib); - reg.Build(arg_gcc.state, foolib_build_cb, g_foolib); - reg.Build(arg_msvc.state, foolib_build_cb, m_foolib); + Toolchain_msvc msvc; + ExecutableTarget_msvc m_foolib("foolib", msvc, ""); + Reg::Toolchain(arg_msvc.state).Build(foolib_build_cb, m_foolib); // 5. - reg.RunBuild(); + Reg::Run(); // 6. plugin::ClangCompileCommands({&g_foolib, &m_foolib}).Generate(); diff --git a/example/hybrid/generic/build.cpp b/example/hybrid/generic/build.cpp index 3b9dcaa3..f5631b03 100644 --- a/example/hybrid/generic/build.cpp +++ b/example/hybrid/generic/build.cpp @@ -20,8 +20,11 @@ static void foolib_build_cb(BaseTarget &foolib_target); static void generic_build_cb(BaseTarget &generic_target, BaseTarget &foolib_target); +static void post_build_cb(BaseTarget &generic_target, + BaseTarget &foolib_target); + int main(int argc, char **argv) { - // 1. Get arguments + // Get arguments ArgToolchain custom_toolchain; TargetType default_lib_type{TargetType::StaticLibrary}; Args::Init() @@ -30,70 +33,33 @@ int main(int argc, char **argv) { [&](CLI::App &app) { args_lib_type_cb(app, default_lib_type); }) .Parse(argc, argv); - // 2. Initialize your environment - Register reg; + // Initialize your environment + Reg::Init(); - // 3. Pre-build steps - reg.Clean(clean_cb); + // Pre-build steps + Reg::Call(Args::Clean()).Func(clean_cb); - // 4. Build steps + // Build steps // Toolchain + Generic Target BaseToolchain toolchain = custom_toolchain.ConstructToolchain(); Target_generic foolib_target("libfoo", default_lib_type, toolchain, ""); - reg.Build(custom_toolchain.state, foolib_build_cb, foolib_target); - - // Target specific settings Target_generic generic_target("generic", TargetType::Executable, toolchain, "src"); - reg.Build(custom_toolchain.state, generic_build_cb, generic_target, - foolib_target); - reg.Dep(generic_target, foolib_target); - - // 5. Test steps - reg.Test(custom_toolchain.state, "{executable}", generic_target); - - // 6. Build Target - reg.RunBuild(); - - // 7. Post Build steps - // For Static Lib do nothing - // For Dynamic Lib we need to handle special cases - // - MSVC behaviour - // - Copy to executable location - if (default_lib_type == TargetType::DynamicLibrary) { - - // MSVC special case - fs::path copy_from_path; - fs::path copy_to_path; - if (toolchain.GetId() == ToolchainId::Msvc) { - copy_from_path = - fmt::format("{}.dll", path_as_string(foolib_target.GetTargetPath())); - copy_to_path = - generic_target.GetTargetBuildDir() / - fmt::format("{}.dll", - foolib_target.GetTargetPath().filename().string()); - } else { - copy_from_path = foolib_target.GetTargetPath(); - copy_to_path = - generic_target.GetTargetBuildDir() / - (foolib_target.GetName() + foolib_target.GetConfig().target_ext); - } - - // Copy case - if (generic_target.IsBuilt()) { - fs::remove(copy_to_path); - fs::copy(copy_from_path, copy_to_path); - } - } + Reg::Toolchain(custom_toolchain.state) + .Func([&]() { toolchain.Verify(); }) + .Build(foolib_build_cb, foolib_target) + .Build(generic_build_cb, generic_target, foolib_target) + .Dep(generic_target, foolib_target) + .Test("{executable}", generic_target); - // 8. Test Target - reg.RunTest(); + // Build Target + Reg::Run([&]() { post_build_cb(generic_target, foolib_target); }); // - Clang Compile Commands plugin::ClangCompileCommands({&foolib_target, &generic_target}).Generate(); // - Plugin Graph - std::string output = reg.GetTaskflow().dump(); + std::string output = Reg::GetTaskflow().dump(); const bool saved = env::save_file("graph.dot", output, false); env::assert_fatal(saved, "Could not save graph.dot file"); @@ -131,3 +97,35 @@ static void generic_build_cb(BaseTarget &generic_target, generic_target.AddSource("main.cpp"); generic_target.Build(); } + +void post_build_cb(BaseTarget &generic_target, BaseTarget &foolib_target) { + // For Static Lib do nothing + // For Dynamic Lib we need to handle special cases + // - MSVC behaviour + // - Copy to executable location + if (foolib_target.GetType() == TargetType::DynamicLibrary) { + // MSVC special case + fs::path copy_from_path; + fs::path copy_to_path; + if (foolib_target.GetToolchain().GetId() == ToolchainId::Msvc) { + copy_from_path = + fmt::format("{}.dll", path_as_string(foolib_target.GetTargetPath())); + copy_to_path = + generic_target.GetTargetBuildDir() / + fmt::format("{}.dll", + foolib_target.GetTargetPath().filename().string()); + } else { + copy_from_path = foolib_target.GetTargetPath(); + copy_to_path = + generic_target.GetTargetBuildDir() / + (foolib_target.GetName() + foolib_target.GetConfig().target_ext); + } + + // Copy case + // TODO, This should be baked into the `Target` API + if (generic_target.IsBuilt()) { + fs::remove(copy_to_path); + fs::copy(copy_from_path, copy_to_path); + } + } +} diff --git a/example/hybrid/pch/build.cpp b/example/hybrid/pch/build.cpp index a305367d..88bfc426 100644 --- a/example/hybrid/pch/build.cpp +++ b/example/hybrid/pch/build.cpp @@ -21,39 +21,33 @@ int main(int argc, char **argv) { .Parse(argc, argv); // 2. Initialize your environment - Register reg; + Reg::Init(); // 3. Pre-build steps - reg.Clean(clean_cb); + Reg::Call(Args::Clean()).Func(clean_cb); // 4. Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - Toolchain_msvc msvc; - ExecutableTarget_gcc g_cppflags("cppflags", gcc, "files"); ExecutableTarget_gcc g_cflags("cflags", gcc, "files"); - ExecutableTarget_msvc m_cppflags("cppflags", msvc, "files"); - ExecutableTarget_msvc m_cflags("cflags", msvc, "files"); - // Select your builds and tests using the .toml files - reg.Build(arg_gcc.state, cppflags_build_cb, g_cppflags); - reg.Build(arg_msvc.state, cppflags_build_cb, m_cppflags); - reg.Build(arg_gcc.state, cflags_build_cb, g_cflags); - reg.Build(arg_msvc.state, cflags_build_cb, m_cflags); + Reg::Toolchain(arg_gcc.state) + .Build(cppflags_build_cb, g_cppflags) + .Build(cflags_build_cb, g_cflags) + .Test("{executable}", g_cppflags) + .Test("{executable}", g_cflags); - // 5. Test steps - // NOTE, For now they are just dummy callbacks - reg.Test(arg_gcc.state, "{executable}", g_cppflags); - reg.Test(arg_msvc.state, "{executable}", m_cppflags); - reg.Test(arg_gcc.state, "{executable}", g_cflags); - reg.Test(arg_msvc.state, "{executable}", m_cflags); - - // 6. Build Target - reg.RunBuild(); + Toolchain_msvc msvc; + ExecutableTarget_msvc m_cppflags("cppflags", msvc, "files"); + ExecutableTarget_msvc m_cflags("cflags", msvc, "files"); + Reg::Toolchain(arg_msvc.state) + .Build(cppflags_build_cb, m_cppflags) + .Build(cflags_build_cb, m_cflags) + .Test("{executable}", m_cppflags) + .Test("{executable}", m_cflags); - // 7. Test Target - reg.RunTest(); + Reg::Run(); // 8. Post Build steps @@ -61,7 +55,7 @@ int main(int argc, char **argv) { plugin::ClangCompileCommands({&g_cflags, &g_cppflags}).Generate(); // - Plugin Graph - std::string output = reg.GetTaskflow().dump(); + std::string output = Reg::GetTaskflow().dump(); const bool saved = env::save_file("graph.dot", output, false); env::assert_fatal(saved, "Could not save graph.dot file"); diff --git a/example/hybrid/simple/build.cpp b/example/hybrid/simple/build.cpp index 94c447f7..229f4f97 100644 --- a/example/hybrid/simple/build.cpp +++ b/example/hybrid/simple/build.cpp @@ -21,38 +21,34 @@ int main(int argc, char **argv) { .Parse(argc, argv); // 2. Initialize your environment - Register reg; + Reg::Init(); // 3. Pre-build steps - reg.Clean(clean_cb); + Reg::Call(Args::Clean()).Func(clean_cb); // 4. Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - Toolchain_msvc msvc; - ExecutableTarget_gcc g_cppflags("cppflags", gcc, "files"); - ExecutableTarget_msvc m_cppflags("cppflags", msvc, "files"); ExecutableTarget_gcc g_cflags("cflags", gcc, "files"); - ExecutableTarget_msvc m_cflags("cflags", msvc, "files"); - - // Select your builds and tests using the .toml files - reg.Build(arg_gcc.state, cppflags_build_cb, g_cppflags); - reg.Build(arg_msvc.state, cppflags_build_cb, m_cppflags); - reg.Build(arg_gcc.state, cflags_build_cb, g_cflags); - reg.Build(arg_msvc.state, cflags_build_cb, m_cflags); + Reg::Toolchain(arg_gcc.state) + .Func([&]() { gcc.Verify(); }) + .Build(cppflags_build_cb, g_cppflags) + .Build(cflags_build_cb, g_cflags) + .Test("{executable}", g_cppflags) + .Test("{executable}", g_cflags); - // 5. Test steps - reg.Test(arg_gcc.state, "{executable}", g_cppflags); - reg.Test(arg_msvc.state, "{executable}", m_cppflags); - reg.Test(arg_gcc.state, "{executable}", g_cflags); - reg.Test(arg_msvc.state, "{executable}", m_cflags); - - // 6. Build Target - reg.RunBuild(); + Toolchain_msvc msvc; + ExecutableTarget_msvc m_cppflags("cppflags", msvc, "files"); + ExecutableTarget_msvc m_cflags("cflags", msvc, "files"); + Reg::Toolchain(arg_msvc.state) + .Func([&]() { msvc.Verify(); }) + .Build(cppflags_build_cb, m_cppflags) + .Build(cflags_build_cb, m_cflags) + .Test("{executable}", m_cppflags) + .Test("{executable}", m_cflags); - // 7. Test Target - reg.RunTest(); + Reg::Run(); // 8. Post Build steps @@ -61,7 +57,7 @@ int main(int argc, char **argv) { .Generate(); // - Plugin Graph - std::string output = reg.GetTaskflow().dump(); + std::string output = Reg::GetTaskflow().dump(); const bool saved = env::save_file("graph.dot", output, false); env::assert_fatal(saved, "Could not save graph.dot file"); diff --git a/example/hybrid/single/build.cpp b/example/hybrid/single/build.cpp index 491c8fc2..a6e59996 100644 --- a/example/hybrid/single/build.cpp +++ b/example/hybrid/single/build.cpp @@ -16,29 +16,24 @@ int main(int argc, char **argv) { .Parse(argc, argv); // 2. Initialize your environment - Register reg; + Reg::Init(); // 3. Pre-build steps - reg.Clean(clean_cb); + Reg::Call(Args::Clean()).Func(clean_cb); // 4. Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - gcc.Verify(); - ExecutableTarget_gcc hello_world("hello_world", gcc, ""); // Select your builds and tests using the .toml files - reg.Build(arg_gcc.state, hello_world_build_cb, hello_world); - - // 5. Test steps - reg.Test(arg_gcc.state, "{executable}", hello_world); - - // 6. Build Target - reg.RunBuild(); + Reg::Toolchain(arg_gcc.state) + .Func([&]() { gcc.Verify(); }) + .Build(hello_world_build_cb, hello_world) + .Test("{executable}", hello_world); - // 7. Test Target - reg.RunTest(); + // 6. Build and Test Target + Reg::Run(); // 8. Post Build steps // - Clang Compile Commands diff --git a/example/hybrid/target_info/build.cpp b/example/hybrid/target_info/build.cpp index 600a8c71..e2684d0f 100644 --- a/example/hybrid/target_info/build.cpp +++ b/example/hybrid/target_info/build.cpp @@ -13,7 +13,7 @@ static void genericadd2_build_cb(BaseTarget &genericadd, const TargetInfo &genericadd_ho); int main(int argc, char **argv) { - // 1. Get arguments + // Get arguments ArgToolchain arg_gcc; ArgToolchain arg_msvc; Args::Init() @@ -21,61 +21,47 @@ int main(int argc, char **argv) { .AddToolchain("msvc", "Generic msvc toolchain", arg_msvc) .Parse(argc, argv); - // 2. Initialize your environment - Register reg; + // Initialize your environment + Reg::Init(); - // 3. Pre-build steps - reg.Clean(clean_cb); + // Pre-build steps + Reg::Call(Args::Clean()).Func(clean_cb); - // 4. Build steps + // Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - Toolchain_msvc msvc; - - // TargetInfo TargetInfo gcc_genericadd_ho(gcc, "files"); - TargetInfo msvc_genericadd_ho(msvc, "files"); - reg.Callback(genericadd_ho_cb, gcc_genericadd_ho); - reg.Callback(genericadd_ho_cb, msvc_genericadd_ho); - ExecutableTarget_gcc g_genericadd1("generic_add_1", gcc, "files"); - ExecutableTarget_msvc m_genericadd1("generic_add_1", msvc, "files"); - ExecutableTarget_gcc g_genericadd2("generic_add_2", gcc, "files"); - ExecutableTarget_msvc m_genericadd2("generic_add_2", msvc, "files"); - - // Select your builds and tests using the .toml files - reg.Build(arg_gcc.state, genericadd1_build_cb, g_genericadd1, - gcc_genericadd_ho); - reg.Build(arg_gcc.state, genericadd2_build_cb, g_genericadd2, - gcc_genericadd_ho); - - reg.Build(arg_msvc.state, genericadd1_build_cb, m_genericadd1, - msvc_genericadd_ho); - reg.Build(arg_msvc.state, genericadd2_build_cb, m_genericadd2, - msvc_genericadd_ho); - - // 5. Test steps - // NOTE, For now they are just dummy callbacks - reg.Test(arg_gcc.state, "{executable}", g_genericadd1); - reg.Test(arg_msvc.state, "{executable}", m_genericadd1); - - reg.Test(arg_gcc.state, "{executable}", g_genericadd2); - reg.Test(arg_msvc.state, "{executable}", m_genericadd2); - - // 6. Build Target - reg.RunBuild(); - - // 7. Test Target - reg.RunTest(); - - // 8. Post Build steps + Reg::Toolchain(arg_gcc.state) + .Func([&]() { gcc.Verify(); }) + .Func(genericadd_ho_cb, gcc_genericadd_ho) + .Build(genericadd1_build_cb, g_genericadd1, gcc_genericadd_ho) + .Build(genericadd2_build_cb, g_genericadd2, gcc_genericadd_ho) + .Test("{executable}", g_genericadd1) + .Test("{executable}", g_genericadd2); + Toolchain_msvc msvc; + TargetInfo msvc_genericadd_ho(msvc, "files"); + ExecutableTarget_msvc m_genericadd1("generic_add_1", msvc, "files"); + ExecutableTarget_msvc m_genericadd2("generic_add_2", msvc, "files"); + Reg::Toolchain(arg_msvc.state) + .Func([&]() { msvc.Verify(); }) + .Func(genericadd_ho_cb, msvc_genericadd_ho) + .Build(genericadd1_build_cb, m_genericadd1, msvc_genericadd_ho) + .Build(genericadd2_build_cb, m_genericadd2, msvc_genericadd_ho) + .Test("{executable}", m_genericadd1) + .Test("{executable}", m_genericadd2); + + // Run + Reg::Run(); + + // Post Build steps // - Clang Compile Commands plugin::ClangCompileCommands({&g_genericadd1, &m_genericadd1}).Generate(); // - Plugin Graph - std::string output = reg.GetTaskflow().dump(); + std::string output = Reg::GetTaskflow().dump(); const bool saved = env::save_file("graph.dot", output, false); env::assert_fatal(saved, "Could not save graph.dot file");