diff --git a/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h b/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h index d6d8023f..35e006bc 100644 --- a/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h +++ b/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h @@ -18,6 +18,7 @@ #define TOOLCHAIN_TOOLCHAIN_VERIFY_H_ #include +#include #include #include "env/logging.h" @@ -42,6 +43,13 @@ namespace buildcc::base { struct VerifyToolchainConfig { std::vector absolute_search_paths; std::vector env_vars{"PATH"}; + + std::optional compiler_version; + std::optional target_arch; + + // Updates the toolchain with absolute paths once verified + // If multiple toolchains are found, uses the first in the list + bool update{true}; }; /** @@ -60,8 +68,21 @@ struct VerifiedToolchain { template class ToolchainVerify { public: + /** + * @brief Verify your toolchain executables by searching your operating system + * paths + * Only add the verified path IF all toolchain executables are matched + * + * @param config Search paths to find toolchains + * @return std::vector Operating system can contain + * multiple toolchains of similar names with different versions. Collect all + * of them + */ std::vector Verify(const VerifyToolchainConfig &config = VerifyToolchainConfig()); + +protected: + VerifiedToolchain verified_toolchain_; }; } // namespace buildcc::base diff --git a/buildcc/lib/toolchain/include/toolchain/toolchain.h b/buildcc/lib/toolchain/include/toolchain/toolchain.h index 17d292e1..9eeb278c 100644 --- a/buildcc/lib/toolchain/include/toolchain/toolchain.h +++ b/buildcc/lib/toolchain/include/toolchain/toolchain.h @@ -58,6 +58,9 @@ class Toolchain : public ToolchainVerify { const std::string &GetArchiver() const { return archiver_; } const std::string &GetLinker() const { return linker_; } +private: + friend class ToolchainVerify; + private: Id id_; std::string name_; diff --git a/buildcc/lib/toolchain/src/api/toolchain_verify.cpp b/buildcc/lib/toolchain/src/api/toolchain_verify.cpp index 1afcf998..289c13bf 100644 --- a/buildcc/lib/toolchain/src/api/toolchain_verify.cpp +++ b/buildcc/lib/toolchain/src/api/toolchain_verify.cpp @@ -197,7 +197,7 @@ ToolchainVerify::Verify(const VerifyToolchainConfig &config) { } std::vector verified_toolchains; - const T &t = static_cast(*this); + T &t = static_cast(*this); ToolchainMatcher matcher(t); matcher.FillWithToolchainFilenames(); @@ -233,13 +233,53 @@ ToolchainVerify::Verify(const VerifyToolchainConfig &config) { vt.path = p; vt.compiler_version = env::trim(GetCompilerVersion(p, t).value_or("")); vt.target_arch = env::trim(GetCompilerArchitecture(p, t).value_or("")); - verified_toolchains.push_back(vt); + + // Check add + bool add{true}; + if (config.compiler_version.has_value()) { + add = add && (config.compiler_version.value() == vt.compiler_version); + } + if (config.target_arch.has_value()) { + add = add && (config.target_arch.value() == vt.target_arch); + } + if (add) { + verified_toolchains.push_back(vt); + } } // Reset matcher.FillWithToolchainFilenames(); } + if (config.update && !verified_toolchains.empty()) { + constexpr const char *os_executable_ext = + buildcc::env::get_os_executable_extension(); + buildcc::env::assert_fatal( + "OS not supported"); + + verified_toolchain_ = verified_toolchains[0]; + t.asm_compiler_ = (verified_toolchain_.path / + fmt::format("{}{}", t.asm_compiler_, os_executable_ext)) + .make_preferred() + .string(); + t.c_compiler_ = (verified_toolchain_.path / + fmt::format("{}{}", t.c_compiler_, os_executable_ext)) + .make_preferred() + .string(); + t.cpp_compiler_ = (verified_toolchain_.path / + fmt::format("{}{}", t.cpp_compiler_, os_executable_ext)) + .make_preferred() + .string(); + t.archiver_ = (verified_toolchain_.path / + fmt::format("{}{}", t.archiver_, os_executable_ext)) + .make_preferred() + .string(); + t.linker_ = (verified_toolchain_.path / + fmt::format("{}{}", t.linker_, os_executable_ext)) + .make_preferred() + .string(); + } + return verified_toolchains; } diff --git a/buildcc/lib/toolchain/test/test_toolchain_verify.cpp b/buildcc/lib/toolchain/test/test_toolchain_verify.cpp index 451bcc54..d6b26da5 100644 --- a/buildcc/lib/toolchain/test/test_toolchain_verify.cpp +++ b/buildcc/lib/toolchain/test/test_toolchain_verify.cpp @@ -204,6 +204,136 @@ TEST(ToolchainTestGroup, VerifyToolchain_LockedFolder) { } } +TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_CompilerVersion) { + buildcc::base::Toolchain gcc(buildcc::base::Toolchain::Id::Gcc, "gcc", "as", + "gcc", "g++", "ar", "ld"); + + buildcc::base::VerifyToolchainConfig config; + config.env_vars.clear(); + config.absolute_search_paths.push_back( + (fs::current_path() / "toolchains" / "gcc").string()); + config.compiler_version = "10.2.1"; + + std::vector compiler_version{"10.2.1"}; + std::vector arch{"none"}; + buildcc::env::m::CommandExpect_Execute(1, true, &compiler_version, nullptr); + buildcc::env::m::CommandExpect_Execute(1, true, &arch, nullptr); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_EQUAL(verified_toolchains.size(), 1); +} + +TEST(ToolchainTestGroup, + VerifyToolchain_ConditionalAdd_CompilerVersionFailure) { + buildcc::base::Toolchain gcc(buildcc::base::Toolchain::Id::Gcc, "gcc", "as", + "gcc", "g++", "ar", "ld"); + + buildcc::base::VerifyToolchainConfig config; + config.env_vars.clear(); + config.absolute_search_paths.push_back( + (fs::current_path() / "toolchains" / "gcc").string()); + config.compiler_version = "11.0.0"; + + std::vector compiler_version{"10.2.1"}; + std::vector arch{"none"}; + buildcc::env::m::CommandExpect_Execute(1, true, &compiler_version, nullptr); + buildcc::env::m::CommandExpect_Execute(1, true, &arch, nullptr); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_EQUAL(verified_toolchains.size(), 0); +} + +TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_TargetArch) { + buildcc::base::Toolchain gcc(buildcc::base::Toolchain::Id::Gcc, "gcc", "as", + "gcc", "g++", "ar", "ld"); + + buildcc::base::VerifyToolchainConfig config; + config.env_vars.clear(); + config.absolute_search_paths.push_back( + (fs::current_path() / "toolchains" / "gcc").string()); + config.target_arch = "arm-none-eabi"; + + std::vector compiler_version{"10.2.1"}; + std::vector arch{"arm-none-eabi"}; + buildcc::env::m::CommandExpect_Execute(1, true, &compiler_version, nullptr); + buildcc::env::m::CommandExpect_Execute(1, true, &arch, nullptr); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_EQUAL(verified_toolchains.size(), 1); +} + +TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_TargetArchFailure) { + buildcc::base::Toolchain gcc(buildcc::base::Toolchain::Id::Gcc, "gcc", "as", + "gcc", "g++", "ar", "ld"); + + buildcc::base::VerifyToolchainConfig config; + config.env_vars.clear(); + config.absolute_search_paths.push_back( + (fs::current_path() / "toolchains" / "gcc").string()); + config.target_arch = "none"; + + std::vector compiler_version{"10.2.1"}; + std::vector arch{"arm-none-eabi"}; + buildcc::env::m::CommandExpect_Execute(1, true, &compiler_version, nullptr); + buildcc::env::m::CommandExpect_Execute(1, true, &arch, nullptr); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_EQUAL(verified_toolchains.size(), 0); +} + +TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_BothFailure) { + buildcc::base::Toolchain gcc(buildcc::base::Toolchain::Id::Gcc, "gcc", "as", + "gcc", "g++", "ar", "ld"); + + buildcc::base::VerifyToolchainConfig config; + config.env_vars.clear(); + config.absolute_search_paths.push_back( + (fs::current_path() / "toolchains" / "gcc").string()); + config.compiler_version = "none"; + config.target_arch = "none"; + + std::vector compiler_version{"10.2.1"}; + std::vector arch{"arm-none-eabi"}; + buildcc::env::m::CommandExpect_Execute(1, true, &compiler_version, nullptr); + buildcc::env::m::CommandExpect_Execute(1, true, &arch, nullptr); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_EQUAL(verified_toolchains.size(), 0); +} + +TEST(ToolchainTestGroup, VerifyToolchain_UpdateFalse) { + buildcc::base::Toolchain gcc(buildcc::base::Toolchain::Id::Gcc, "gcc", "as", + "gcc", "g++", "ar", "ld"); + + buildcc::base::VerifyToolchainConfig config; + config.env_vars.clear(); + config.absolute_search_paths.push_back( + (fs::current_path() / "toolchains" / "gcc").string()); + // config.compiler_version = "none"; + // config.target_arch = "none"; + config.update = false; + + std::vector compiler_version{"10.2.1"}; + std::vector arch{"arm-none-eabi"}; + buildcc::env::m::CommandExpect_Execute(1, true, &compiler_version, nullptr); + buildcc::env::m::CommandExpect_Execute(1, true, &arch, nullptr); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_EQUAL(verified_toolchains.size(), 1); +} + int main(int ac, char **av) { buildcc::env::m::VectorStringCopier copier; mock().installCopier(TEST_VECTOR_STRING_TYPE, copier);