diff --git a/.github/workflows/linux_gcc_cmake_build.yml b/.github/workflows/linux_gcc_cmake_build.yml index 5d327756..4b25ca9c 100644 --- a/.github/workflows/linux_gcc_cmake_build.yml +++ b/.github/workflows/linux_gcc_cmake_build.yml @@ -162,7 +162,7 @@ jobs: - name: System Packages run: | - sudo apt-get install ninja-build doxygen graphviz gcovr cppcheck clang-tidy + sudo apt-get install ninja-build doxygen graphviz cppcheck clang-tidy - name: Install LCOV run: | @@ -179,7 +179,6 @@ jobs: clang --version ninja --version doxygen --version - gcovr --version cppcheck --version clang-tidy --version diff --git a/TODO.md b/TODO.md index aee3c6f6..580db67f 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,71 @@ +# Versions + +# 0.1.1 + +Complete working proof of concept of the following + +- BuildCC library +- BuildCC bootstrap "script" files (Basic) +- BuildExe executable (Standalone) + +Contains the following working features + +**BuildCC** +- Supported plugin + - Clang Compile Commands +- Toolchain, Generator, TargetInfo and Target interfaces +- Specialized Toolchain for GCC, MSVC and MINGW +- Specialized Target for GCC, MSVC and MINGW + +**BuildExe** +- Immediate mode +- Script mode +- Local Package Manager with git + +## 0.1.2 + +- Serialization Interface +- Namespace changes + - Remove ``buildcc::base`` + - Remove ``buildcc::env`` + - We should only have 3 namespaces ``buildcc``, ``buildcc::plugin`` and ``buildcc::internal`` +- Environment updates + - Remove ``buildcc::env`` + - Refactor free / static functions and variables into classes with static members and variables. For example. ``buildcc::env::init`` should become ``buildcc::Environment::Init`` +- Args and Register module updates + - Pch command from command line + - Make Register functions static. ``Register::Build`` + - Update ``CallbackIf``, ``Build`` and ``Test`` APIs for the ``state`` variable usage +- Unit testing and mocking for BuildExe + +## 0.1.3 + +- Make a common interface / internal library which contains all utility functions and libraries +- New generators + - Currently we only have a simple Generator which is similar to our FileIOGenerator (input -> subprocess commands -> outputs) + - Read the ``faq`` generators to make more varied and robust generators. + +## 0.1.4 + +- Config options updates as per Target requirements + - Update configs to use ``fmt::format`` with format specifiers for "{prefix}{value}{suffix}" for customizability. For example: `/D{preprocessor}` for msvc or `-D{preprocessor}` for gcc etc +- Target specialized clang + - Clang behaves differently depending on its backend + - Option 1: Consider adding more options to ``ToolchainId`` and different Clang specializations. For example: ``Target_gcc_clang`` or ``Target_msvc_clang`` or ``Target_mingw_clang`` etc + - Option 2: Consider making a ``Target_clang`` that changes behaviour as per the ``target_triple_architecture`` present in the ``toolchain`` + - What other flavours of clang are present? + +## 0.2.x + +- `Append*` APIs +- `Add*WithFormat` or `Append*WithFormat` APIs + +## Long Term goals + +- [Discussion] Supported plugin requirements by users +- [Discussion] Customizability requirements by users +- [Discussion] Target and Generator interfaces for standardization by compilers. (White paper) +- [Community Support] MacOS testing and CI/CD # Feature diff --git a/buildcc/lib/args/include/args/args.h b/buildcc/lib/args/include/args/args.h index 4f461707..b57e2a6a 100644 --- a/buildcc/lib/args/include/args/args.h +++ b/buildcc/lib/args/include/args/args.h @@ -57,6 +57,10 @@ struct ArgToolchain { c_compiler(initial_c_compiler), cpp_compiler(initial_cpp_compiler), archiver(initial_archiver), linker(initial_linker) {} + /** + * @brief Construct a BaseToolchain from the arguments supplied through the + * command line information + */ BaseToolchain ConstructToolchain() const { BaseToolchain toolchain(id, name, asm_compiler, c_compiler, cpp_compiler, archiver, linker); @@ -88,10 +92,22 @@ class Args { Args() { Initialize(); } Args(const Args &) = delete; + /** + * @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) + */ void Parse(int argc, const char *const *argv); - // TODO, Check if these are necessary + /** + * @brief Modifiable reference to CLI::App (CLI11) + */ CLI::App &Ref() { return app_; } + + /** + * @brief Constant reference to CLI::App (CLI11) + */ const CLI::App &ConstRef() const { return app_; } // Setters @@ -106,8 +122,14 @@ class Args { ArgToolchain &out, const ArgToolchain &initial = ArgToolchain()); - // NOTE, Incomplete TargetArg - // TODO, Update for pch_compile_command + /** + * @brief Add Target config commands with a unique name and description + * + * @param out Receive the target command information through the CLI + * @param initial Set the default target command information as a fallback + * + * TODO, Update with other options for TargetConfig + */ void AddTarget(const std::string &name, const std::string &description, ArgTarget &out, const ArgTarget &initial = ArgTarget()); diff --git a/buildcc/lib/args/include/args/register.h b/buildcc/lib/args/include/args/register.h index 906641d5..b34b4ce1 100644 --- a/buildcc/lib/args/include/args/register.h +++ b/buildcc/lib/args/include/args/register.h @@ -46,8 +46,20 @@ class Register { * Can be used to organize code into functional chunks */ template - void Callback(const C &build_cb, Params &...params) { - build_cb(std::forward(params)...); + void Callback(const C &build_cb, Params &&...params) { + build_cb(std::forward(params)...); + } + + /** + * @brief Generic register callback that is run when `expression == + * true` + * Can be used to add Toolchain-Target specific information + */ + template + void CallbackIf(bool expression, const C &build_cb, Params &&...params) { + if (expression) { + Callback(build_cb, std::forward(params)...); + } } /** @@ -57,10 +69,9 @@ class Register { */ template void CallbackIf(const ArgToolchainState &toolchain_state, const C &build_cb, - Params &...params) { - if (toolchain_state.build) { - Callback(build_cb, std::forward(params)...); - } + Params &&...params) { + CallbackIf(toolchain_state.build, build_cb, + std::forward(params)...); } /** @@ -68,15 +79,15 @@ class Register { */ template void Build(const ArgToolchainState &toolchain_state, const C &build_cb, - base::Target &target, Params &...params) { + BaseTarget &target, Params &&...params) { tf::Task task; CallbackIf( toolchain_state, - [&](base::Target <arget, Params &...lparams) { - build_cb(ltarget, std::forward(lparams)...); + [&](BaseTarget <arget, Params &&...lparams) { + build_cb(ltarget, std::forward(lparams)...); task = BuildTargetTask(ltarget); }, - target, std::forward(params)...); + target, std::forward(params)...); BuildStoreTask(target.GetUniqueId(), task); } @@ -84,8 +95,8 @@ class Register { * @brief Register the generator to be built */ template - void Build(const C &build_cb, base::Generator &generator, Params &...params) { - build_cb(generator, std::forward(params)...); + void Build(const C &build_cb, BaseGenerator &generator, Params &&...params) { + build_cb(generator, std::forward(params)...); tf::Task task = BuildGeneratorTask(generator); BuildStoreTask(generator.GetUniqueId(), task); } @@ -102,12 +113,15 @@ class Register { /** * @brief Register the Target to be run * PreReq: Call `Register::Build` before calling `Register::Test` - * PreReq: Requires toolchain_state.build && test to be true + * PreReq: Requires ArgToolchainState::build && ArgToolchainState::test to be + * true * - * Target is added as the `{executable}` argument + * Target is added as the `{executable}` argument. + * We can add more fmt::format arguments using the TestConfig arguments + * parameter */ void Test(const ArgToolchainState &toolchain_state, - const std::string &command, const base::Target &target, + const std::string &command, const BaseTarget &target, const TestConfig &config = TestConfig()); /** @@ -135,8 +149,8 @@ class Register { void Env(); // BuildTasks - tf::Task BuildTargetTask(base::Target &target); - tf::Task BuildGeneratorTask(base::Generator &generator); + tf::Task BuildTargetTask(BaseTarget &target); + tf::Task BuildGeneratorTask(BaseGenerator &generator); void BuildStoreTask(const std::string &unique_id, const tf::Task &task); private: diff --git a/buildcc/lib/args/include/args/register/test_info.h b/buildcc/lib/args/include/args/register/test_info.h index 033a8f1c..50d61f41 100644 --- a/buildcc/lib/args/include/args/register/test_info.h +++ b/buildcc/lib/args/include/args/register/test_info.h @@ -26,14 +26,21 @@ namespace buildcc { struct TestOutput { enum class Type { - DefaultBehaviour, // Do not redirect to user or tests, default printed on - // console - TestPrintOnStderr, // Test only redirects stderr and prints - TestPrintOnStdout, // Test only redirects stdout and prints - TestPrintOnStderrAndStdout, // Test redirects both and prints - UserRedirect, // Redirects to user + DefaultBehaviour, ///< Do not redirect to user or tests, default printed on + ///< console + TestPrintOnStderr, ///< Test only redirects stderr and prints + TestPrintOnStdout, ///< Test only redirects stdout and prints + TestPrintOnStderrAndStdout, ///< Test redirects both and prints + UserRedirect, ///< Redirects to user variables }; + /** + * @brief Configure your Register::Test to get test output + * + * @param output_type Select your output type (behaviour) + * @param redirect_stdout User stdout redirection + * @param redirect_stderr User stderr redirection + */ TestOutput(Type output_type = Type::TestPrintOnStderrAndStdout, std::vector *redirect_stdout = nullptr, std::vector *redirect_stderr = nullptr) @@ -56,6 +63,13 @@ struct TestOutput { struct TestConfig { public: + /** + * @brief Configure your Register::Test using TestConfig + * + * @param arguments fmt::format args passed to test commands + * @param working_directory Working directory from which the test runs + * @param output Output from tests + */ TestConfig( const std::unordered_map &arguments = {}, const std::optional &working_directory = {}, @@ -77,6 +91,8 @@ struct TestConfig { TestOutput output_; }; +// PRIVATE + struct TestInfo { TestInfo(const BaseTarget &target, const std::string &command, const TestConfig &config = TestConfig()) diff --git a/docs/source/user_api/args.rst b/docs/source/user_api/args.rst index 1e37cf41..383268c7 100644 --- a/docs/source/user_api/args.rst +++ b/docs/source/user_api/args.rst @@ -4,3 +4,65 @@ Args args.h ------- +.. doxygenclass:: buildcc::Args + :members: Args, Parse, Ref, ConstRef, AddToolchain, Clean, GetLogLevel, GetProjectRootDir, GetProjectBuildDir + +.. doxygenstruct:: buildcc::ArgToolchainState + +.. doxygenstruct:: buildcc::ArgToolchain + +Example +--------- + +.. code-block:: cpp + :linenos: + + 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); + + // Root + 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; + } + +.. code-block:: toml + :linenos: + + # Root + root_dir = "" + build_dir = "_build" + loglevel = "trace" + clean = true + + # Toolchain + [toolchain.gcc] + build = true + test = true + + id = "gcc" + name = "x86_64-linux-gnu" + asm_compiler = "as" + c_compiler = "gcc" + cpp_compiler = "g++" + archiver = "ar" + linker = "ld" + diff --git a/docs/source/user_api/register.rst b/docs/source/user_api/register.rst index 75c7f497..77033451 100644 --- a/docs/source/user_api/register.rst +++ b/docs/source/user_api/register.rst @@ -1,6 +1,50 @@ Register ========= - register.h ----------- + +.. doxygenclass:: buildcc::Register + :members: Register, Clean, Callback, CallbackIf, Build, Dep, Test, RunBuild, RunTest + + +test_info.h +------------- + +.. doxygenstruct:: buildcc::TestConfig + +.. doxygenstruct:: buildcc::TestOutput + +Example +-------- + +.. code-block:: cpp + :linenos: + + class BigObj {}; + + static void callback_usage_func(const BigObj & cobj, BigObj & obj); + + int main(int argc, char ** argv) { + Args args; + args.Parse(argc, argv); + + Register reg(args); + reg.Clean([](){ + fs::remove_all(env::get_project_build_dir()); + }); + + BigObj obj; + reg.Callback(callback_usage_func, BigObj(), obj); + + bool expression = true; // false + reg.CallbackIf(expression, callback_usage_func, BigObj(), obj); + + // Example snippets of these given in Target API + // Build + // Dep + // Test + // RunBuild + // RunTest + return 0; + } diff --git a/docs/source/user_api/supported_plugins.rst b/docs/source/user_api/supported_plugins.rst index 4f178a0c..87204809 100644 --- a/docs/source/user_api/supported_plugins.rst +++ b/docs/source/user_api/supported_plugins.rst @@ -3,3 +3,19 @@ Supported Plugins clang_compile_commands.h ------------------------ + +.. doxygenclass:: buildcc::plugin::ClangCompileCommands + +Example +-------- + +.. code-block:: cpp + :linenos: + + using namespace buildcc; + + Target foolib; + Target hello_world; + + // Foolib and Hello world targets are both added to a single "compile_commands.json" file + plugin::ClangCompileCommands({&foolib, &hello_world}).Generate(); diff --git a/docs/source/user_api/toc.rst b/docs/source/user_api/toc.rst index 21859ffa..a9c70857 100644 --- a/docs/source/user_api/toc.rst +++ b/docs/source/user_api/toc.rst @@ -4,10 +4,10 @@ User API .. toctree:: - environment + args + register toolchain generator target - args - register supported_plugins + environment