diff --git a/buildcc/lib/args/include/args/args.h b/buildcc/lib/args/include/args/args.h index 05311272..c687df92 100644 --- a/buildcc/lib/args/include/args/args.h +++ b/buildcc/lib/args/include/args/args.h @@ -48,8 +48,8 @@ struct ArgToolchainState { struct ArgToolchain { ArgToolchain(){}; ArgToolchain(ToolchainId initial_id, const std::string &initial_name, - const ToolchainBinaries &initial_binaries) - : id(initial_id), name(initial_name), binaries(initial_binaries) {} + const ToolchainExecutables &initial_executables) + : id(initial_id), name(initial_name), executables(initial_executables) {} ArgToolchain(ToolchainId initial_id, const std::string &initial_name, const std::string &initial_assembler, const std::string &initial_c_compiler, @@ -57,9 +57,9 @@ struct ArgToolchain { const std::string &initial_archiver, const std::string &initial_linker) : ArgToolchain(initial_id, initial_name, - ToolchainBinaries(initial_assembler, initial_c_compiler, - initial_cpp_compiler, initial_archiver, - initial_linker)) {} + ToolchainExecutables(initial_assembler, initial_c_compiler, + initial_cpp_compiler, + initial_archiver, initial_linker)) {} /** * @brief Construct a BaseToolchain from the arguments supplied through the @@ -67,13 +67,13 @@ struct ArgToolchain { */ // TODO, Update this for lock and ToolchainConfig BaseToolchain ConstructToolchain() const { - return BaseToolchain(id, name, binaries); + return BaseToolchain(id, name, executables); } ArgToolchainState state; ToolchainId id{ToolchainId::Undefined}; std::string name{""}; - ToolchainBinaries binaries; + ToolchainExecutables executables; }; // NOTE, Incomplete without pch_compile_command diff --git a/buildcc/lib/args/src/args.cpp b/buildcc/lib/args/src/args.cpp index 9c95eb5c..e6cd76a1 100644 --- a/buildcc/lib/args/src/args.cpp +++ b/buildcc/lib/args/src/args.cpp @@ -99,16 +99,16 @@ void Args::AddToolchain(const std::string &name, const std::string &description, ->transform(CLI::CheckedTransformer(kToolchainIdMap, CLI::ignore_case)) ->default_val(initial.id); t_user->add_option(kToolchainNameParam, out.name)->default_val(initial.name); - t_user->add_option(kToolchainAsmCompilerParam, out.binaries.assembler) - ->default_val(initial.binaries.assembler); - t_user->add_option(kToolchainCCompilerParam, out.binaries.c_compiler) - ->default_val(initial.binaries.c_compiler); - t_user->add_option(kToolchainCppCompilerParam, out.binaries.cpp_compiler) - ->default_val(initial.binaries.cpp_compiler); - t_user->add_option(kToolchainArchiverParam, out.binaries.archiver) - ->default_val(initial.binaries.archiver); - t_user->add_option(kToolchainLinkerParam, out.binaries.linker) - ->default_val(initial.binaries.linker); + t_user->add_option(kToolchainAsmCompilerParam, out.executables.assembler) + ->default_val(initial.executables.assembler); + t_user->add_option(kToolchainCCompilerParam, out.executables.c_compiler) + ->default_val(initial.executables.c_compiler); + t_user->add_option(kToolchainCppCompilerParam, out.executables.cpp_compiler) + ->default_val(initial.executables.cpp_compiler); + t_user->add_option(kToolchainArchiverParam, out.executables.archiver) + ->default_val(initial.executables.archiver); + t_user->add_option(kToolchainLinkerParam, out.executables.linker) + ->default_val(initial.executables.linker); } void Args::AddTarget(const std::string &name, const std::string &description, diff --git a/buildcc/lib/args/test/test_args.cpp b/buildcc/lib/args/test/test_args.cpp index b52179cf..acaa82b7 100644 --- a/buildcc/lib/args/test/test_args.cpp +++ b/buildcc/lib/args/test/test_args.cpp @@ -68,11 +68,11 @@ TEST(ArgsTestGroup, Args_CustomToolchain) { CHECK_FALSE(gcc_toolchain.state.test); CHECK(gcc_toolchain.id == buildcc::ToolchainId::Gcc); STRCMP_EQUAL(gcc_toolchain.name.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.assembler.c_str(), "as"); - STRCMP_EQUAL(gcc_toolchain.binaries.c_compiler.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.cpp_compiler.c_str(), "g++"); - STRCMP_EQUAL(gcc_toolchain.binaries.archiver.c_str(), "ar"); - STRCMP_EQUAL(gcc_toolchain.binaries.linker.c_str(), "ld"); + STRCMP_EQUAL(gcc_toolchain.executables.assembler.c_str(), "as"); + STRCMP_EQUAL(gcc_toolchain.executables.c_compiler.c_str(), "gcc"); + STRCMP_EQUAL(gcc_toolchain.executables.cpp_compiler.c_str(), "g++"); + STRCMP_EQUAL(gcc_toolchain.executables.archiver.c_str(), "ar"); + STRCMP_EQUAL(gcc_toolchain.executables.linker.c_str(), "ld"); } TEST(ArgsTestGroup, Args_MultipleCustomToolchain) { @@ -106,22 +106,22 @@ TEST(ArgsTestGroup, Args_MultipleCustomToolchain) { CHECK_FALSE(gcc_toolchain.state.test); CHECK(gcc_toolchain.id == buildcc::ToolchainId::Gcc); STRCMP_EQUAL(gcc_toolchain.name.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.assembler.c_str(), "as"); - STRCMP_EQUAL(gcc_toolchain.binaries.c_compiler.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.cpp_compiler.c_str(), "g++"); - STRCMP_EQUAL(gcc_toolchain.binaries.archiver.c_str(), "ar"); - STRCMP_EQUAL(gcc_toolchain.binaries.linker.c_str(), "ld"); + STRCMP_EQUAL(gcc_toolchain.executables.assembler.c_str(), "as"); + STRCMP_EQUAL(gcc_toolchain.executables.c_compiler.c_str(), "gcc"); + STRCMP_EQUAL(gcc_toolchain.executables.cpp_compiler.c_str(), "g++"); + STRCMP_EQUAL(gcc_toolchain.executables.archiver.c_str(), "ar"); + STRCMP_EQUAL(gcc_toolchain.executables.linker.c_str(), "ld"); // MSVC CHECK_TRUE(msvc_toolchain.state.build); CHECK_TRUE(msvc_toolchain.state.test); CHECK(msvc_toolchain.id == buildcc::ToolchainId::Msvc); STRCMP_EQUAL(msvc_toolchain.name.c_str(), "msvc"); - STRCMP_EQUAL(msvc_toolchain.binaries.assembler.c_str(), "cl"); - STRCMP_EQUAL(msvc_toolchain.binaries.c_compiler.c_str(), "cl"); - STRCMP_EQUAL(msvc_toolchain.binaries.cpp_compiler.c_str(), "cl"); - STRCMP_EQUAL(msvc_toolchain.binaries.archiver.c_str(), "lib"); - STRCMP_EQUAL(msvc_toolchain.binaries.linker.c_str(), "link"); + STRCMP_EQUAL(msvc_toolchain.executables.assembler.c_str(), "cl"); + STRCMP_EQUAL(msvc_toolchain.executables.c_compiler.c_str(), "cl"); + STRCMP_EQUAL(msvc_toolchain.executables.cpp_compiler.c_str(), "cl"); + STRCMP_EQUAL(msvc_toolchain.executables.archiver.c_str(), "lib"); + STRCMP_EQUAL(msvc_toolchain.executables.linker.c_str(), "link"); } TEST(ArgsTestGroup, Args_DuplicateCustomToolchain) { @@ -167,11 +167,11 @@ TEST(ArgsTestGroup, Args_CustomTarget) { CHECK_FALSE(gcc_toolchain.state.test); CHECK(gcc_toolchain.id == buildcc::ToolchainId::Gcc); STRCMP_EQUAL(gcc_toolchain.name.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.assembler.c_str(), "as"); - STRCMP_EQUAL(gcc_toolchain.binaries.c_compiler.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.cpp_compiler.c_str(), "g++"); - STRCMP_EQUAL(gcc_toolchain.binaries.archiver.c_str(), "ar"); - STRCMP_EQUAL(gcc_toolchain.binaries.linker.c_str(), "ld"); + STRCMP_EQUAL(gcc_toolchain.executables.assembler.c_str(), "as"); + STRCMP_EQUAL(gcc_toolchain.executables.c_compiler.c_str(), "gcc"); + STRCMP_EQUAL(gcc_toolchain.executables.cpp_compiler.c_str(), "g++"); + STRCMP_EQUAL(gcc_toolchain.executables.archiver.c_str(), "ar"); + STRCMP_EQUAL(gcc_toolchain.executables.linker.c_str(), "ld"); // Target STRCMP_EQUAL(gcc_target.compile_command.c_str(), @@ -221,11 +221,11 @@ TEST(ArgsTestGroup, Args_MultipleCustomTarget) { CHECK_FALSE(gcc_toolchain.state.test); CHECK(gcc_toolchain.id == buildcc::ToolchainId::Gcc); STRCMP_EQUAL(gcc_toolchain.name.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.assembler.c_str(), "as"); - STRCMP_EQUAL(gcc_toolchain.binaries.c_compiler.c_str(), "gcc"); - STRCMP_EQUAL(gcc_toolchain.binaries.cpp_compiler.c_str(), "g++"); - STRCMP_EQUAL(gcc_toolchain.binaries.archiver.c_str(), "ar"); - STRCMP_EQUAL(gcc_toolchain.binaries.linker.c_str(), "ld"); + STRCMP_EQUAL(gcc_toolchain.executables.assembler.c_str(), "as"); + STRCMP_EQUAL(gcc_toolchain.executables.c_compiler.c_str(), "gcc"); + STRCMP_EQUAL(gcc_toolchain.executables.cpp_compiler.c_str(), "g++"); + STRCMP_EQUAL(gcc_toolchain.executables.archiver.c_str(), "ar"); + STRCMP_EQUAL(gcc_toolchain.executables.linker.c_str(), "ld"); // Target STRCMP_EQUAL(gcc_target.compile_command.c_str(), @@ -242,11 +242,11 @@ TEST(ArgsTestGroup, Args_MultipleCustomTarget) { CHECK_TRUE(msvc_toolchain.state.test); CHECK(msvc_toolchain.id == buildcc::ToolchainId::Msvc); STRCMP_EQUAL(msvc_toolchain.name.c_str(), "msvc"); - STRCMP_EQUAL(msvc_toolchain.binaries.assembler.c_str(), "cl"); - STRCMP_EQUAL(msvc_toolchain.binaries.c_compiler.c_str(), "cl"); - STRCMP_EQUAL(msvc_toolchain.binaries.cpp_compiler.c_str(), "cl"); - STRCMP_EQUAL(msvc_toolchain.binaries.archiver.c_str(), "lib"); - STRCMP_EQUAL(msvc_toolchain.binaries.linker.c_str(), "link"); + STRCMP_EQUAL(msvc_toolchain.executables.assembler.c_str(), "cl"); + STRCMP_EQUAL(msvc_toolchain.executables.c_compiler.c_str(), "cl"); + STRCMP_EQUAL(msvc_toolchain.executables.cpp_compiler.c_str(), "cl"); + STRCMP_EQUAL(msvc_toolchain.executables.archiver.c_str(), "lib"); + STRCMP_EQUAL(msvc_toolchain.executables.linker.c_str(), "link"); // Target STRCMP_EQUAL(msvc_target.compile_command.c_str(), diff --git a/buildcc/lib/target/test/target/test_toolchain_flag_api.cpp b/buildcc/lib/target/test/target/test_toolchain_flag_api.cpp index 3d698891..dc5aa0f7 100644 --- a/buildcc/lib/target/test/target/test_toolchain_flag_api.cpp +++ b/buildcc/lib/target/test/target/test_toolchain_flag_api.cpp @@ -85,5 +85,6 @@ TEST(ToolchainFlagApiTestGroup, BasicTargetTest) { } int main(int ac, char **av) { + MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); return CommandLineTestRunner::RunAllTests(ac, av); } diff --git a/buildcc/lib/toolchain/CMakeLists.txt b/buildcc/lib/toolchain/CMakeLists.txt index 91570b7d..ce4f6ac0 100644 --- a/buildcc/lib/toolchain/CMakeLists.txt +++ b/buildcc/lib/toolchain/CMakeLists.txt @@ -6,14 +6,14 @@ set(TOOLCHAIN_SRCS include/toolchain/common/function_lock.h # API + src/api/toolchain_find.cpp + src/api/toolchain_verify.cpp + include/toolchain/api/toolchain_find.h + include/toolchain/api/toolchain_verify.h include/toolchain/api/flag_api.h src/toolchain/toolchain.cpp include/toolchain/toolchain.h - - # Features - src/api/toolchain_verify.cpp - include/toolchain/api/toolchain_verify.h ) if (${TESTING}) add_library(mock_toolchain @@ -32,10 +32,10 @@ if (${TESTING}) ${TEST_LINK_LIBS} ) - add_executable(test_toolchain_verify - test/test_toolchain_verify.cpp + add_executable(test_toolchain_id + test/test_toolchain_id.cpp ) - target_link_libraries(test_toolchain_verify PRIVATE + target_link_libraries(test_toolchain_id PRIVATE mock_toolchain ) @@ -46,10 +46,28 @@ if (${TESTING}) mock_toolchain ) + add_executable(test_toolchain_find + test/test_toolchain_find.cpp + ) + target_link_libraries(test_toolchain_find PRIVATE + mock_toolchain + ) + + add_executable(test_toolchain_verify + test/test_toolchain_verify.cpp + ) + target_link_libraries(test_toolchain_verify PRIVATE + mock_toolchain + ) + + add_test(NAME test_toolchain_id COMMAND test_toolchain_id) + add_test(NAME test_toolchain_config COMMAND test_toolchain_config) + add_test(NAME test_toolchain_find COMMAND test_toolchain_find + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test + ) add_test(NAME test_toolchain_verify COMMAND test_toolchain_verify WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test ) - add_test(NAME test_toolchain_config COMMAND test_toolchain_config) endif() if(${BUILDCC_BUILD_AS_SINGLE_LIB}) diff --git a/buildcc/lib/toolchain/include/toolchain/api/toolchain_find.h b/buildcc/lib/toolchain/include/toolchain/api/toolchain_find.h new file mode 100644 index 00000000..4929bc5e --- /dev/null +++ b/buildcc/lib/toolchain/include/toolchain/api/toolchain_find.h @@ -0,0 +1,62 @@ +/* + * Copyright 2021-2022 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TOOLCHAIN_TOOLCHAIN_FIND_H_ +#define TOOLCHAIN_TOOLCHAIN_FIND_H_ + +#include +#include +#include +#include + +#include "schema/path.h" + +namespace fs = std::filesystem; + +namespace buildcc { + +/** + * @brief Configure the behaviour of Toolchain::Find API. By default searches + * the directories mentioned in the ENV{PATH} variable to find the toolchain. + * @param absolute_search_paths absolute_search_paths expect directories that + * are iterated for exact toolchain matches + * @param env_vars env_vars contain paths that are seperated by OS delimiter. + * These are converted to paths and searched similarly to absolute_search_paths + *
+ * NOTE: env_vars must contain single absolute paths or multiple absolute + * paths seperated by OS delimiter
+ * Example: [Windows] "absolute_path_1;absolute_path_2;..."
+ * Example: [Linux] "absolute_path_1:absolute_path_2:..."
+ */ +struct ToolchainFindConfig { + ToolchainFindConfig( + const std::unordered_set &env_vars = {"PATH"}, + const fs_unordered_set &absolute_search_paths = {}) + : env_vars(env_vars), absolute_search_paths(absolute_search_paths) {} + + std::unordered_set env_vars; + fs_unordered_set absolute_search_paths; +}; + +template class ToolchainFind { +public: + std::vector + Find(const ToolchainFindConfig &config = ToolchainFindConfig()) const; +}; + +} // namespace buildcc + +#endif diff --git a/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h b/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h index a22277da..1318aefd 100644 --- a/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h +++ b/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h @@ -21,51 +21,21 @@ #include #include +#include "fmt/format.h" + #include "env/logging.h" -#include "fmt/format.h" +#include "toolchain/common/toolchain_executables.h" +#include "toolchain/common/toolchain_id.h" + +#include "toolchain/api/toolchain_find.h" namespace fs = std::filesystem; namespace buildcc { -/** - * @brief Configure the behaviour of Toolchain::Verify API. By default searches - * the directories mentioned in the ENV{PATH} variable to find the toolchain. - * @param absolute_search_paths absolute_search_paths expect directories that - * are iterated for exact toolchain matches - * @param env_vars env_vars contain paths that are seperated by OS delimiter. - * These are converted to paths and searched similarly to absolute_search_paths - *
- * NOTE: env_vars must contain single absolute paths or multiple absolute - * paths seperated by OS delimiter
- * Example: [Windows] "absolute_path_1;absolute_path_2;..."
- * Example: [Linux] "absolute_path_1:absolute_path_2:..."
- * @param compiler_version Optionally supply a compiler version if multiple - * toolchains of the same family/id are installed
- * Example: [GCC/MinGW/Clang] {compiler} -dumpversion
- * Example: [MSVC] getenv(VSCMD_VER)
- * For [MSVC] make sure to use `vcvarsall.bat {flavour}` to activate your - * toolchain - * @param target_arch Optionally supply a target architecture if multiple - * toolchains of the same family/id are installed but target different platforms - *
- * Example: [GCC/MinGW/Clang] {compiler} -dumpmachine
- * Example: [MSVC] getenv(VSCMD_ARG_HOST_ARCH) + - * getenv(VSCMD_ARG_TGT_ARCH)
- * For [MSVC] make sure to use `vcvarsall.bat {flavour}` to activate your - * toolchain - * @param update Updates the toolchain with absolute paths once verified
- * If multiple toolchains are found, uses the first in the list - */ -struct VerifyToolchainConfig { - std::vector absolute_search_paths; - std::vector env_vars{"PATH"}; - - std::optional compiler_version; - std::optional target_arch; - - bool update{true}; +struct ToolchainVerifyConfig : public ToolchainFindConfig { + std::optional verification_identifier; }; /** @@ -76,16 +46,34 @@ struct VerifyToolchainConfig { * @param compiler_version Compiler version of the verified toolchain * @param target_arch Target architecture of the verified toolchain */ -struct VerifiedToolchain { +struct ToolchainCompilerInfo { + std::string ToString() const { return fmt::format("{}", *this); } + fs::path path; std::string compiler_version; std::string target_arch; - - std::string ToString() const { return fmt::format("{}", *this); } }; +typedef std::function( + const ToolchainExecutables &)> + ToolchainVerificationFunc; + template class ToolchainVerify { public: + ToolchainVerify() { Initialize(); } + + /** + * @brief + * + * @param id + * @param verification_func + * @param identifier Only read when ToolchainId::Custom is passed in + */ + static void + AddVerificationFunc(ToolchainId id, + const ToolchainVerificationFunc &verification_func, + const std::optional &op_identifier = {}); + /** * @brief Verify your toolchain executables by searching your operating system * paths @@ -96,11 +84,18 @@ template class ToolchainVerify { * multiple toolchains of similar names with different versions. Collect all * of them */ - std::vector - Verify(const VerifyToolchainConfig &config = VerifyToolchainConfig()); + ToolchainCompilerInfo + Verify(const ToolchainVerifyConfig &config = ToolchainVerifyConfig()); protected: - VerifiedToolchain verified_toolchain_; + ToolchainCompilerInfo verified_toolchain_; + +private: + void Initialize(); + static const ToolchainVerificationFunc & + GetVerificationFunc(const std::string &identifier); + static std::unordered_map & + GetStatic(); }; } // namespace buildcc @@ -112,9 +107,9 @@ constexpr const char *const kVerifiedToolchainFormat = R"({{ }})"; template <> -struct fmt::formatter : formatter { +struct fmt::formatter : formatter { template - auto format(const buildcc::VerifiedToolchain &vt, FormatContext &ctx) { + auto format(const buildcc::ToolchainCompilerInfo &vt, FormatContext &ctx) { std::string verified_toolchain_info = fmt::format(kVerifiedToolchainFormat, vt.path.string(), vt.compiler_version, vt.target_arch); diff --git a/buildcc/lib/toolchain/include/toolchain/common/toolchain_executables.h b/buildcc/lib/toolchain/include/toolchain/common/toolchain_executables.h new file mode 100644 index 00000000..b8862200 --- /dev/null +++ b/buildcc/lib/toolchain/include/toolchain/common/toolchain_executables.h @@ -0,0 +1,41 @@ +/* + * Copyright 2021-2022 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TOOLCHAIN_COMMON_TOOLCHAIN_EXECUTABLES_H_ +#define TOOLCHAIN_COMMON_TOOLCHAIN_EXECUTABLES_H_ + +#include +#include + +namespace buildcc { + +struct ToolchainExecutables { + explicit ToolchainExecutables() = default; + explicit ToolchainExecutables(std::string_view as, std::string_view c, + std::string_view cpp, std::string_view ar, + std::string_view link) + : assembler(as), c_compiler(c), cpp_compiler(cpp), archiver(ar), + linker(link) {} + std::string assembler; + std::string c_compiler; + std::string cpp_compiler; + std::string archiver; + std::string linker; +}; + +} // namespace buildcc + +#endif diff --git a/buildcc/lib/toolchain/include/toolchain/common/toolchain_id.h b/buildcc/lib/toolchain/include/toolchain/common/toolchain_id.h new file mode 100644 index 00000000..d19ea6d6 --- /dev/null +++ b/buildcc/lib/toolchain/include/toolchain/common/toolchain_id.h @@ -0,0 +1,65 @@ +/* + * Copyright 2021-2022 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TOOLCHAIN_COMMON_TOOLCHAIN_ID_H_ +#define TOOLCHAIN_COMMON_TOOLCHAIN_ID_H_ + +#include "fmt/format.h" + +namespace buildcc { + +enum class ToolchainId { + Gcc = 0, ///< GCC Toolchain + Msvc, ///< MSVC Toolchain + Clang, ///< Clang Toolchain + MinGW, ///< MinGW Toolchain (Similar to GCC, but for Windows) + Custom, ///< Custom Toolchain not defined in this list + Undefined, ///< Default value when unknown +}; + +} // namespace buildcc + +template <> +struct fmt::formatter : formatter { + template + auto format(buildcc::ToolchainId id, FormatContext &ctx) { + std::string id_name; + switch (id) { + case buildcc::ToolchainId::Gcc: + id_name = "Gcc"; + break; + case buildcc::ToolchainId::Msvc: + id_name = "Msvc"; + break; + case buildcc::ToolchainId::Clang: + id_name = "Clang"; + break; + case buildcc::ToolchainId::MinGW: + id_name = "MinGW"; + break; + case buildcc::ToolchainId::Custom: + id_name = "Custom"; + break; + case buildcc::ToolchainId::Undefined: + default: + id_name = "Undefined"; + break; + } + return formatter::format(id_name, ctx); + } +}; + +#endif diff --git a/buildcc/lib/toolchain/include/toolchain/toolchain.h b/buildcc/lib/toolchain/include/toolchain/toolchain.h index f46cc2ad..7ae3e959 100644 --- a/buildcc/lib/toolchain/include/toolchain/toolchain.h +++ b/buildcc/lib/toolchain/include/toolchain/toolchain.h @@ -23,44 +23,25 @@ #include "toolchain/common/function_lock.h" #include "toolchain/common/toolchain_config.h" +#include "toolchain/common/toolchain_executables.h" +#include "toolchain/common/toolchain_id.h" #include "toolchain/api/flag_api.h" +#include "toolchain/api/toolchain_find.h" #include "toolchain/api/toolchain_verify.h" namespace buildcc { -enum class ToolchainId { - Gcc = 0, ///< GCC Toolchain - Msvc, ///< MSVC Toolchain - Clang, ///< Clang Toolchain - MinGW, ///< MinGW Toolchain (Similar to GCC, but for Windows) - Custom, ///< Custom Toolchain not defined in this list - Undefined, ///< Default value when unknown -}; - -struct ToolchainBinaries { - explicit ToolchainBinaries() = default; - explicit ToolchainBinaries(std::string_view as, std::string_view c, - std::string_view cpp, std::string_view ar, - std::string_view link) - : assembler(as), c_compiler(c), cpp_compiler(cpp), archiver(ar), - linker(link) {} - std::string assembler; - std::string c_compiler; - std::string cpp_compiler; - std::string archiver; - std::string linker; -}; - // Base toolchain class class Toolchain : public internal::FlagApi, + public ToolchainFind, public ToolchainVerify { public: public: Toolchain(ToolchainId id, std::string_view name, - const ToolchainBinaries &binaries, bool lock = true, + const ToolchainExecutables &executables, bool lock = true, const ToolchainConfig &config = ToolchainConfig()) - : id_(id), name_(name), binaries_(binaries), lock_(lock), + : id_(id), name_(name), executables_(executables), lock_(lock), config_(config) { Initialize(); } @@ -69,8 +50,8 @@ class Toolchain : public internal::FlagApi, std::string_view archiver, std::string_view linker, bool lock = true, const ToolchainConfig &config = ToolchainConfig()) : Toolchain(id, name, - ToolchainBinaries(assembler, c_compiler, cpp_compiler, - archiver, linker), + ToolchainExecutables(assembler, c_compiler, cpp_compiler, + archiver, linker), lock, config) {} Toolchain(Toolchain &&) = default; @@ -83,12 +64,16 @@ class Toolchain : public internal::FlagApi, // Getters ToolchainId GetId() const { return id_; } const std::string &GetName() const { return name_; } - const std::string &GetAssembler() const { return binaries_.assembler; } - const std::string &GetCCompiler() const { return binaries_.c_compiler; } - const std::string &GetCppCompiler() const { return binaries_.cpp_compiler; } - const std::string &GetArchiver() const { return binaries_.archiver; } - const std::string &GetLinker() const { return binaries_.linker; } - const ToolchainBinaries &GetToolchainBinaries() const { return binaries_; } + const std::string &GetAssembler() const { return executables_.assembler; } + const std::string &GetCCompiler() const { return executables_.c_compiler; } + const std::string &GetCppCompiler() const { + return executables_.cpp_compiler; + } + const std::string &GetArchiver() const { return executables_.archiver; } + const std::string &GetLinker() const { return executables_.linker; } + const ToolchainExecutables &GetToolchainExecutables() const { + return executables_; + } const FunctionLock &GetLockInfo() const { return lock_; } const ToolchainConfig &GetConfig() const { return config_; } @@ -106,9 +91,10 @@ class Toolchain : public internal::FlagApi, }; private: - virtual void UpdateConfig(ToolchainConfig &config) { (void)config; } void Initialize(); + virtual void UpdateConfig(ToolchainConfig &config); + private: friend class internal::FlagApi; friend class ToolchainVerify; @@ -116,7 +102,7 @@ class Toolchain : public internal::FlagApi, private: ToolchainId id_; std::string name_; - ToolchainBinaries binaries_; + ToolchainExecutables executables_; FunctionLock lock_; ToolchainConfig config_; diff --git a/buildcc/lib/toolchain/src/api/toolchain_find.cpp b/buildcc/lib/toolchain/src/api/toolchain_find.cpp new file mode 100644 index 00000000..bdef49b3 --- /dev/null +++ b/buildcc/lib/toolchain/src/api/toolchain_find.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2021-2022 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "toolchain/api/toolchain_find.h" + +#include "env/assert_fatal.h" +#include "env/host_os.h" +#include "env/host_os_util.h" +#include "env/util.h" + +#include "toolchain/toolchain.h" + +namespace { + +std::vector ParseEnvVarToPaths(const std::string &env_var) { + const char *path_env = getenv(env_var.c_str()); + buildcc::env::assert_fatal( + path_env != nullptr, + fmt::format("Environment variable '{}' not present", env_var)); + + constexpr const char *os_env_delim = buildcc::env::get_os_envvar_delim(); + buildcc::env::assert_fatal("OS not supported"); + std::vector paths = + buildcc::env::split(path_env, os_env_delim[0]); + + return paths; +} + +bool ContainsToolchainExecutables( + const fs::directory_iterator &directory_iterator, + const buildcc::ToolchainExecutables &executables) { + std::unordered_set exes( + {executables.assembler, executables.c_compiler, executables.cpp_compiler, + executables.archiver, executables.linker}); + std::error_code ec; + for (const auto &dir_iter : directory_iterator) { + bool is_regular_file = dir_iter.is_regular_file(ec); + if (!is_regular_file || ec) { + continue; + } + const auto &filename_without_ext = dir_iter.path().stem().string(); + // NOTE, Must match the entire filename + exes.erase(filename_without_ext); + } + return exes.empty(); +} + +} // namespace + +namespace buildcc { + +template +std::vector +ToolchainFind::Find(const ToolchainFindConfig &config) const { + // Initialization + const T &t = static_cast(*this); + std::vector found_toolchains; + fs_unordered_set absolute_search_paths(config.absolute_search_paths); + + // Parse config envs and add it to absolute search paths + for (const std::string &env_var : config.env_vars) { + std::vector paths = ParseEnvVarToPaths(env_var); + absolute_search_paths.insert(paths.begin(), paths.end()); + } + + // Over the absolute search paths + // - Check if directory exists + // - Iterate over directory + // - Find ALL Toolchain binaries in ONE directory + // - If matched, store that path + for (const auto &search_path : absolute_search_paths) { + if (!fs::exists(search_path)) { + continue; + } + + std::error_code ec; + auto directory_iterator = fs::directory_iterator(search_path, ec); + if (ec) { + continue; + } + + bool toolchains_matched = ContainsToolchainExecutables( + directory_iterator, t.GetToolchainExecutables()); + if (toolchains_matched) { + found_toolchains.push_back(search_path); + } + } + + return found_toolchains; +} + +template class ToolchainFind; + +} // namespace buildcc diff --git a/buildcc/lib/toolchain/src/api/toolchain_verify.cpp b/buildcc/lib/toolchain/src/api/toolchain_verify.cpp index 157a7c1e..1d60b80f 100644 --- a/buildcc/lib/toolchain/src/api/toolchain_verify.cpp +++ b/buildcc/lib/toolchain/src/api/toolchain_verify.cpp @@ -22,7 +22,7 @@ #include -#include "toolchain/toolchain.h" +#include "schema/path.h" #include "env/assert_fatal.h" #include "env/host_os.h" @@ -31,261 +31,238 @@ #include "env/command.h" -namespace { -// Constants - -// Functions -std::vector ParseEnvVarToPaths(const std::string &env_var) { - const char *path_env = getenv(env_var.c_str()); - buildcc::env::assert_fatal( - path_env != nullptr, - fmt::format("Environment variable '{}' not present", env_var)); - - constexpr const char *os_env_delim = buildcc::env::get_os_envvar_delim(); - buildcc::env::assert_fatal("OS not supported"); - std::vector paths = - buildcc::env::split(path_env, os_env_delim[0]); +#include "toolchain/toolchain.h" - return paths; -} +namespace { -std::string GetGccCompilerVersion(const buildcc::env::Command &command) { +std::optional +GetGccCompilerVersion(const buildcc::env::Command &command) { std::vector stdout_data; bool executed = buildcc::env::Command::Execute( command.Construct("{compiler} -dumpversion"), {}, &stdout_data); - buildcc::env::assert_fatal( - executed, "GetCompilerVersion command not executed successfully"); - return stdout_data.at(0); + if (!executed || stdout_data.empty()) { + return {}; + } + return stdout_data[0]; } -std::string GetMsvcCompilerVersion() { - // Done VSCMD_VER - const char *vscmd_version = getenv("VSCMD_VER"); - buildcc::env::assert_fatal( - vscmd_version != nullptr, - "Setup Visual Studio build tools. Call `vcvarsall.bat {platform}` to " - "setup your target and host"); - return vscmd_version; +std::optional +GetGccTargetArchitecture(const buildcc::env::Command &command) { + std::vector stdout_data; + bool executed = buildcc::env::Command::Execute( + command.Construct("{compiler} -dumpmachine"), {}, &stdout_data); + if (!executed || stdout_data.empty()) { + return {}; + } + return stdout_data[0]; } -std::optional -GetCompilerVersion(const fs::path &absolute_path, - const buildcc::Toolchain &toolchain) { +std::optional +GccVerificationFunc(const buildcc::ToolchainExecutables &executables) { buildcc::env::Command command; - command.AddDefaultArgument( - "compiler", - (absolute_path / toolchain.GetCppCompiler()).make_preferred().string()); + command.AddDefaultArgument("compiler", executables.cpp_compiler); - std::optional compiler_version; - switch (toolchain.GetId()) { - case buildcc::ToolchainId::Gcc: - case buildcc::ToolchainId::MinGW: - case buildcc::ToolchainId::Clang: - compiler_version = GetGccCompilerVersion(command); - break; - case buildcc::ToolchainId::Msvc: - compiler_version = GetMsvcCompilerVersion(); - break; - default: - buildcc::env::log_warning(__FUNCTION__, - "Operation not supported on this compiler"); - compiler_version = {}; - break; + auto op_compiler_version = GetGccCompilerVersion(command); + auto op_target_arch = GetGccTargetArchitecture(command); + if (!op_compiler_version.has_value() || !op_target_arch.has_value()) { + return {}; } - return compiler_version; + + buildcc::ToolchainCompilerInfo compiler_info; + compiler_info.compiler_version = op_compiler_version.value(); + compiler_info.target_arch = op_target_arch.value(); + return compiler_info; } -std::string GetGccTargetArchitecture(const buildcc::env::Command &command) { - std::vector stdout_data; - bool executed = buildcc::env::Command::Execute( - command.Construct("{compiler} -dumpmachine"), {}, &stdout_data); - buildcc::env::assert_fatal( - executed, "GetCompilerArchitecture command not executed successfully"); - return stdout_data.at(0); +std::optional GetMsvcCompilerVersion() { + const char *vscmd_version = getenv("VSCMD_VER"); + if (vscmd_version == nullptr) { + return {}; + } + return vscmd_version; } -std::string GetMsvcTargetArchitecture() { +std::optional GetMsvcTargetArchitecture() { // DONE, Read `VSCMD_ARG_HOST_ARCH` from env path // DONE, Read `VSCMD_ARG_TGT_ARCH` from env path const char *vs_host_arch = getenv("VSCMD_ARG_HOST_ARCH"); const char *vs_target_arch = getenv("VSCMD_ARG_TGT_ARCH"); - buildcc::env::assert_fatal( - (vs_host_arch != nullptr) && (vs_target_arch != nullptr), - "Setup Visual Studio build tools. Call `vcvarsall.bat {platform}` to " - "setup your target and host"); + if (vs_host_arch == nullptr || vs_target_arch == nullptr) { + return {}; + } - // DONE, Concat them! + // DONE, Concat them return fmt::format("{}_{}", vs_host_arch, vs_target_arch); } -std::optional -GetCompilerArchitecture(const fs::path &absolute_path, - const buildcc::Toolchain &toolchain) { - buildcc::env::Command command; - command.AddDefaultArgument( - "compiler", - (absolute_path / toolchain.GetCppCompiler()).make_preferred().string()); - std::optional target_arch; - switch (toolchain.GetId()) { - case buildcc::ToolchainId::Gcc: - case buildcc::ToolchainId::MinGW: - case buildcc::ToolchainId::Clang: - target_arch = GetGccTargetArchitecture(command); +std::optional +MsvcVerificationFunc(const buildcc::ToolchainExecutables &executables) { + (void)executables; + auto op_compiler_version = GetMsvcCompilerVersion(); + auto op_target_arch = GetMsvcTargetArchitecture(); + if (!op_compiler_version.has_value() || !op_target_arch.has_value()) { + return {}; + } + + buildcc::ToolchainCompilerInfo compiler_info; + compiler_info.compiler_version = op_compiler_version.value(); + compiler_info.target_arch = op_target_arch.value(); + return compiler_info; +} + +// + +buildcc::ToolchainExecutables CreateToolchainExecutables( + const fs::path &absolute_path, + const buildcc::ToolchainExecutables ¤t_executables) { + constexpr const char *const executable_ext = + buildcc::env::get_os_executable_extension(); + buildcc::env::assert_fatal( + "Host executable extension not supported"); + + std::string assembler_path = + (absolute_path / + fmt::format("{}{}", current_executables.assembler, executable_ext)) + .string(); + std::string c_compiler_path = + (absolute_path / + fmt::format("{}{}", current_executables.c_compiler, executable_ext)) + .string(); + std::string cpp_compiler_path = + (absolute_path / + fmt::format("{}{}", current_executables.cpp_compiler, executable_ext)) + .string(); + std::string archiver_path = + (absolute_path / + fmt::format("{}{}", current_executables.archiver, executable_ext)) + .string(); + std::string linker_path = + (absolute_path / + fmt::format("{}{}", current_executables.linker, executable_ext)) + .string(); + + return buildcc::ToolchainExecutables(assembler_path, c_compiler_path, + cpp_compiler_path, archiver_path, + linker_path); +} + +std::string +GetToolchainVerifyIdentifier(buildcc::ToolchainId id, + const std::optional &op_identifier) { + std::string identifier; + switch (id) { + case buildcc::ToolchainId::Custom: + buildcc::env::assert_fatal( + op_identifier.has_value(), + "Requires verification_identifier value in ToolchainVerifyConfig"); + identifier = op_identifier.value(); break; + case buildcc::ToolchainId::Gcc: case buildcc::ToolchainId::Msvc: - target_arch = GetMsvcTargetArchitecture(); + case buildcc::ToolchainId::Clang: + case buildcc::ToolchainId::MinGW: + identifier = fmt::format("{}", id); break; + case buildcc::ToolchainId::Undefined: default: - buildcc::env::log_warning(__FUNCTION__, - "Operation not supported on this compiler"); - target_arch = {}; + buildcc::env::assert_fatal( + "Undefined toolchain. Use valid ToolchainId"); break; } - return target_arch; + return identifier; } -class ToolchainMatcher { -public: - explicit ToolchainMatcher(const buildcc::Toolchain &toolchain) - : toolchain_(toolchain) {} - - void FillWithToolchainFilenames() { - constexpr const char *os_executable_ext = - buildcc::env::get_os_executable_extension(); - buildcc::env::assert_fatal( - "OS not supported"); - - matcher_.clear(); - matcher_.insert( - fmt::format("{}{}", toolchain_.GetAssembler(), os_executable_ext)); - matcher_.insert( - fmt::format("{}{}", toolchain_.GetCCompiler(), os_executable_ext)); - matcher_.insert( - fmt::format("{}{}", toolchain_.GetCppCompiler(), os_executable_ext)); - matcher_.insert( - fmt::format("{}{}", toolchain_.GetArchiver(), os_executable_ext)); - matcher_.insert( - fmt::format("{}{}", toolchain_.GetLinker(), os_executable_ext)); - } - - void Check(const std::string &filename) { matcher_.erase(filename); } - bool Found() { return matcher_.empty(); } - -private: - const buildcc::Toolchain &toolchain_; - - std::unordered_set matcher_; -}; - } // namespace namespace buildcc { template -std::vector -ToolchainVerify::Verify(const VerifyToolchainConfig &config) { - // TODO, Convert this to fs::path eventually - std::unordered_set absolute_search_paths{ - config.absolute_search_paths.begin(), config.absolute_search_paths.end()}; - - // Parse config envs - for (const std::string &env_var : config.env_vars) { - std::vector paths = ParseEnvVarToPaths(env_var); - for (const auto &p : paths) { - absolute_search_paths.insert(p); - } +void ToolchainVerify::AddVerificationFunc( + ToolchainId id, const ToolchainVerificationFunc &verification_func, + const std::optional &op_identifier) { + std::string identifier; + switch (id) { + case ToolchainId::Gcc: + case ToolchainId::Msvc: + case ToolchainId::MinGW: + case ToolchainId::Clang: + identifier = fmt::format("{}", id); + break; + case ToolchainId::Custom: + env::assert_fatal(op_identifier.has_value(), + "Requires optional identifier parameter when " + "ToolchainId::Custom is defined"); + identifier = op_identifier.value(); + break; + default: + env::assert_fatal("Invalid ToolchainId parameter"); + break; } - std::vector verified_toolchains; + env::assert_fatal( + ToolchainVerify::GetStatic().count(identifier) == 0, + fmt::format("Already registered VerificationFunction for identifier '{}'", + identifier)); + ToolchainVerify::GetStatic()[identifier] = verification_func; +} + +template +ToolchainCompilerInfo +ToolchainVerify::Verify(const ToolchainVerifyConfig &config) { T &t = static_cast(*this); + std::vector toolchain_paths = t.Find(config); + env::assert_fatal(!toolchain_paths.empty(), "No toolchains found"); - ToolchainMatcher matcher(t); - matcher.FillWithToolchainFilenames(); - // Iterate over absolute search paths - // [Verification] Match ALL toolchains PER directory - for (const std::string &pstr : absolute_search_paths) { - fs::path p{pstr}; - if (!fs::exists(p)) { - continue; - } - - std::error_code ec; - auto directory_iterator = fs::directory_iterator(p, ec); - if (ec) { - continue; - } - - // For each directory, Check if ALL toolchain filenames are found - for (const auto &dir_iter : directory_iterator) { - bool is_regular_file = dir_iter.is_regular_file(ec); - if (!is_regular_file || ec) { - continue; - } - const auto &filename = dir_iter.path().filename().string(); - matcher.Check(filename); - } - - // Store verified toolchain path if found - if (matcher.Found()) { - env::log_info(__FUNCTION__, fmt::format("Found: {}", p.string())); - - VerifiedToolchain vt; - vt.path = p; - vt.compiler_version = env::trim(GetCompilerVersion(p, t).value_or("")); - vt.target_arch = env::trim(GetCompilerArchitecture(p, t).value_or("")); - - // 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(); - } + ToolchainExecutables exes = + CreateToolchainExecutables(toolchain_paths[0], t.executables_); + + std::string toolchain_id_identifier = + GetToolchainVerifyIdentifier(t.GetId(), config.verification_identifier); + + const auto &verification_func = + T::GetVerificationFunc(toolchain_id_identifier); + auto op_toolchain_compiler_info = verification_func(exes); + env::assert_fatal(op_toolchain_compiler_info.has_value(), + "Could not verify toolchain"); + + ToolchainCompilerInfo toolchain_compiler_info = + op_toolchain_compiler_info.value(); + toolchain_compiler_info.path = toolchain_paths[0]; - 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.binaries_.assembler = - (verified_toolchain_.path / - fmt::format("{}{}", t.binaries_.assembler, os_executable_ext)) - .make_preferred() - .string(); - t.binaries_.c_compiler = - (verified_toolchain_.path / - fmt::format("{}{}", t.binaries_.c_compiler, os_executable_ext)) - .make_preferred() - .string(); - t.binaries_.cpp_compiler = - (verified_toolchain_.path / - fmt::format("{}{}", t.binaries_.cpp_compiler, os_executable_ext)) - .make_preferred() - .string(); - t.binaries_.archiver = - (verified_toolchain_.path / - fmt::format("{}{}", t.binaries_.archiver, os_executable_ext)) - .make_preferred() - .string(); - t.binaries_.linker = - (verified_toolchain_.path / - fmt::format("{}{}", t.binaries_.linker, os_executable_ext)) - .make_preferred() - .string(); + // Update the compilers + t.executables_ = exes; + return toolchain_compiler_info; +} + +// PRIVATE +template void ToolchainVerify::Initialize() { + static bool do_once = true; + + if (do_once) { + do_once = false; + AddVerificationFunc(ToolchainId::Gcc, GccVerificationFunc); + AddVerificationFunc(ToolchainId::Msvc, MsvcVerificationFunc); + AddVerificationFunc(ToolchainId::Clang, GccVerificationFunc); + AddVerificationFunc(ToolchainId::MinGW, GccVerificationFunc); } +} - return verified_toolchains; +template +const ToolchainVerificationFunc & +ToolchainVerify::GetVerificationFunc(const std::string &identifier) { + const auto &verification_map = T::GetStatic(); + env::assert_fatal(verification_map.count(identifier) == 1, + "Add verification for custom toolchain through " + "Toolchain::AddVerificationFunc API"); + return verification_map.at(identifier); +} + +template +std::unordered_map & +ToolchainVerify::GetStatic() { + static std::unordered_map + verification_func_map; + return verification_func_map; } template class ToolchainVerify; diff --git a/buildcc/lib/toolchain/src/toolchain/toolchain.cpp b/buildcc/lib/toolchain/src/toolchain/toolchain.cpp index 3a3ae354..53bee71c 100644 --- a/buildcc/lib/toolchain/src/toolchain/toolchain.cpp +++ b/buildcc/lib/toolchain/src/toolchain/toolchain.cpp @@ -22,4 +22,7 @@ void Toolchain::Initialize() { UpdateConfig(config_); } void Toolchain::Lock() { lock_.Lock(); } +// PRIVATE +void Toolchain::UpdateConfig(ToolchainConfig &config) { (void)config; } + } // namespace buildcc diff --git a/buildcc/lib/toolchain/test/test_toolchain_find.cpp b/buildcc/lib/toolchain/test/test_toolchain_find.cpp new file mode 100644 index 00000000..3867b8ac --- /dev/null +++ b/buildcc/lib/toolchain/test/test_toolchain_find.cpp @@ -0,0 +1,102 @@ +#include + +#include "toolchain/toolchain.h" + +#include "env/host_os.h" + +#include "expect_command.h" + +#include "mock_command_copier.h" + +// NOTE, Make sure all these includes are AFTER the system and header includes +#include "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/MemoryLeakDetectorNewMacros.h" +#include "CppUTest/TestHarness.h" +#include "CppUTest/Utest.h" +#include "CppUTestExt/MockSupport.h" + +// clang-format off +TEST_GROUP(ToolchainFindTestGroup) +{ + void teardown() { + mock().checkExpectations(); + mock().clear(); + } +}; +// clang-format on + +TEST(ToolchainFindTestGroup, FindToolchain_ThroughEnvVar) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); + + std::string putenv_str = fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", + fs::current_path().string()); + int put = putenv(putenv_str.data()); + CHECK_TRUE(put == 0); + const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); + CHECK_TRUE(custom_buildcc_path != nullptr); + UT_PRINT(custom_buildcc_path); + + buildcc::ToolchainFindConfig config; + config.env_vars.clear(); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + std::vector found_toolchains = gcc.Find(config); + CHECK_TRUE(!found_toolchains.empty()); +} + +TEST(ToolchainFindTestGroup, FindToolchain_ThroughAbsolutePath) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); + + buildcc::ToolchainFindConfig config; + config.absolute_search_paths.insert(fs::current_path() / "toolchains" / + "gcc"); + config.env_vars.clear(); + + std::vector found_toolchains = gcc.Find(config); + CHECK_TRUE(!found_toolchains.empty()); +} + +TEST(ToolchainFindTestGroup, FindToolchain_DirectoryDoesntExist) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); + + buildcc::ToolchainFindConfig config; + config.absolute_search_paths.insert(fs::current_path() / "toolchains" / + "directory_doesnt_exist"); + config.env_vars.clear(); + + std::vector found_toolchains = gcc.Find(config); + CHECK_TRUE(found_toolchains.empty()); +} + +TEST(ToolchainFindTestGroup, FindToolchain_NoDirectoryFound) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); + + buildcc::ToolchainFindConfig config; + config.absolute_search_paths.insert(fs::current_path() / "toolchains" / + "gcc" / "ar"); + config.env_vars.clear(); + + std::vector found_toolchains = gcc.Find(config); + CHECK_TRUE(found_toolchains.empty()); +} + +TEST(ToolchainFindTestGroup, FindToolchain_NoToolchainFound) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); + + buildcc::ToolchainFindConfig config; + config.absolute_search_paths.insert(fs::current_path() / "toolchains"); + config.env_vars.clear(); + + std::vector found_toolchains = gcc.Find(config); + CHECK_TRUE(found_toolchains.empty()); +} + +int main(int ac, char **av) { + MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); + return CommandLineTestRunner::RunAllTests(ac, av); +} diff --git a/buildcc/lib/toolchain/test/test_toolchain_id.cpp b/buildcc/lib/toolchain/test/test_toolchain_id.cpp new file mode 100644 index 00000000..6cb77e6b --- /dev/null +++ b/buildcc/lib/toolchain/test/test_toolchain_id.cpp @@ -0,0 +1,50 @@ +#include + +#include "toolchain/common/toolchain_id.h" + +// NOTE, Make sure all these includes are AFTER the system and header includes +#include "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/MemoryLeakDetectorNewMacros.h" +#include "CppUTest/TestHarness.h" +#include "CppUTest/Utest.h" +#include "CppUTestExt/MockSupport.h" + +// clang-format off +TEST_GROUP(ToolchainIdTestGroup) +{ + void teardown() { + mock().checkExpectations(); + mock().clear(); + } +}; +// clang-format on + +TEST(ToolchainIdTestGroup, ToolchainIdAsString) { + std::string compiler; + + compiler = fmt::format("{}", buildcc::ToolchainId::Gcc); + STRCMP_EQUAL(compiler.c_str(), "Gcc"); + + compiler = fmt::format("{}", buildcc::ToolchainId::Msvc); + STRCMP_EQUAL(compiler.c_str(), "Msvc"); + + compiler = fmt::format("{}", buildcc::ToolchainId::Clang); + STRCMP_EQUAL(compiler.c_str(), "Clang"); + + compiler = fmt::format("{}", buildcc::ToolchainId::MinGW); + STRCMP_EQUAL(compiler.c_str(), "MinGW"); + + compiler = fmt::format("{}", buildcc::ToolchainId::Custom); + STRCMP_EQUAL(compiler.c_str(), "Custom"); + + compiler = fmt::format("{}", buildcc::ToolchainId::Undefined); + STRCMP_EQUAL(compiler.c_str(), "Undefined"); + + compiler = fmt::format("{}", (buildcc::ToolchainId)65535); + STRCMP_EQUAL(compiler.c_str(), "Undefined"); +} + +int main(int ac, char **av) { + MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); + return CommandLineTestRunner::RunAllTests(ac, av); +} diff --git a/buildcc/lib/toolchain/test/test_toolchain_verify.cpp b/buildcc/lib/toolchain/test/test_toolchain_verify.cpp index 0fce266c..5854191d 100644 --- a/buildcc/lib/toolchain/test/test_toolchain_verify.cpp +++ b/buildcc/lib/toolchain/test/test_toolchain_verify.cpp @@ -16,7 +16,7 @@ #include "CppUTestExt/MockSupport.h" // clang-format off -TEST_GROUP(ToolchainTestGroup) +TEST_GROUP(ToolchainVerifyTestGroup) { void teardown() { mock().checkExpectations(); @@ -26,7 +26,7 @@ TEST_GROUP(ToolchainTestGroup) // clang-format on // NOTE, We are mocking the environment instead of actually querying it -TEST(ToolchainTestGroup, VerifyToolchain_Gcc) { +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Gcc) { buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", "ar", "ld"); @@ -35,279 +35,333 @@ TEST(ToolchainTestGroup, VerifyToolchain_Gcc) { buildcc::env::m::CommandExpect_Execute(1, true, &version_stdout_data); buildcc::env::m::CommandExpect_Execute(1, true, &arch_stdout_data); - std::string putenv_str = fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", - fs::current_path().string()); + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", fs::current_path()); int put = putenv(putenv_str.data()); CHECK_TRUE(put == 0); const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); CHECK_TRUE(custom_buildcc_path != nullptr); UT_PRINT(custom_buildcc_path); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.env_vars.push_back("CUSTOM_BUILDCC_PATH"); - - std::vector verified_toolchains = - gcc.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(!verified_toolchains.empty()); - STRCMP_EQUAL(verified_toolchains[0].compiler_version.c_str(), "version"); - STRCMP_EQUAL(verified_toolchains[0].target_arch.c_str(), "arch"); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + buildcc::ToolchainCompilerInfo compiler_info = gcc.Verify(config); + + STRCMP_EQUAL(compiler_info.compiler_version.c_str(), "version"); + STRCMP_EQUAL(compiler_info.target_arch.c_str(), "arch"); } -TEST(ToolchainTestGroup, VerifyToolchain_Clang) { - buildcc::Toolchain clang(buildcc::ToolchainId::Clang, "clang", "llvm-as", - "clang", "clang++", "llvm-ar", "lld"); +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Gcc_CompilerVersionFailure) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); std::vector version_stdout_data{"version"}; std::vector arch_stdout_data{"arch"}; - buildcc::env::m::CommandExpect_Execute(1, true, &version_stdout_data); + buildcc::env::m::CommandExpect_Execute(1, false, &version_stdout_data); buildcc::env::m::CommandExpect_Execute(1, true, &arch_stdout_data); - std::string putenv_str = fmt::format( - "CUSTOM_BUILDCC_PATH={}/toolchains/clang", fs::current_path().string()); + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", fs::current_path()); int put = putenv(putenv_str.data()); CHECK_TRUE(put == 0); const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); CHECK_TRUE(custom_buildcc_path != nullptr); UT_PRINT(custom_buildcc_path); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.env_vars.push_back("CUSTOM_BUILDCC_PATH"); - - std::vector verified_toolchains = - clang.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(!verified_toolchains.empty()); - STRCMP_EQUAL(verified_toolchains[0].compiler_version.c_str(), "version"); - STRCMP_EQUAL(verified_toolchains[0].target_arch.c_str(), "arch"); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + CHECK_THROWS(std::exception, gcc.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_Msvc) { - buildcc::Toolchain msvc(buildcc::ToolchainId::Msvc, "msvc", "cl", "cl", "cl", - "lib", "link"); - // Setup ENV - // VSCMD_VER - std::string vscmd_ver = std::string("VSCMD_VER=version"); - // VSCMD_ARG_HOST_ARCH - std::string host_arch = std::string("VSCMD_ARG_HOST_ARCH=host_arch"); - // VSCMD_ARG_TGT_ARCH - std::string tgt_arch = std::string("VSCMD_ARG_TGT_ARCH=tgt_arch"); +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Gcc_CompilerVersionEmpty) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); - CHECK_TRUE(putenv(vscmd_ver.data()) == 0); - CHECK_TRUE(putenv(host_arch.data()) == 0); - CHECK_TRUE(putenv(tgt_arch.data()) == 0); + std::vector version_stdout_data; + std::vector arch_stdout_data{"arch"}; + buildcc::env::m::CommandExpect_Execute(1, true, &version_stdout_data); + buildcc::env::m::CommandExpect_Execute(1, true, &arch_stdout_data); - // MSVC Compiler - std::string putenv_str = fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/msvc", - fs::current_path().string()); + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", fs::current_path()); int put = putenv(putenv_str.data()); CHECK_TRUE(put == 0); const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); CHECK_TRUE(custom_buildcc_path != nullptr); UT_PRINT(custom_buildcc_path); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.env_vars.push_back("CUSTOM_BUILDCC_PATH"); - - std::vector verified_toolchains = - msvc.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(!verified_toolchains.empty()); - STRCMP_EQUAL(verified_toolchains[0].compiler_version.c_str(), "version"); - STRCMP_EQUAL(verified_toolchains[0].target_arch.c_str(), - "host_arch_tgt_arch"); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + CHECK_THROWS(std::exception, gcc.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_BadCompilerId) { - buildcc::Toolchain gcc((buildcc::ToolchainId)65535, "gcc", "as", "gcc", "g++", +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Gcc_TargetArchFailure) { + buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", "ar", "ld"); - std::string putenv_str = fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", - fs::current_path().string()); + std::vector version_stdout_data{"version"}; + std::vector arch_stdout_data{"arch"}; + buildcc::env::m::CommandExpect_Execute(1, true, &version_stdout_data); + buildcc::env::m::CommandExpect_Execute(1, false, &arch_stdout_data); + + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", fs::current_path()); int put = putenv(putenv_str.data()); CHECK_TRUE(put == 0); const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); CHECK_TRUE(custom_buildcc_path != nullptr); UT_PRINT(custom_buildcc_path); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.env_vars.push_back("CUSTOM_BUILDCC_PATH"); - - std::vector verified_toolchains = - gcc.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(!verified_toolchains.empty()); - STRCMP_EQUAL(verified_toolchains[0].compiler_version.c_str(), ""); - STRCMP_EQUAL(verified_toolchains[0].target_arch.c_str(), ""); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + CHECK_THROWS(std::exception, gcc.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_BadAbsolutePath) { +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Gcc_TargetArchEmpty) { buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", "ar", "ld"); - buildcc::VerifyToolchainConfig config; + std::vector version_stdout_data{"version"}; + std::vector arch_stdout_data; + buildcc::env::m::CommandExpect_Execute(1, true, &version_stdout_data); + buildcc::env::m::CommandExpect_Execute(1, true, &arch_stdout_data); + + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", fs::current_path()); + int put = putenv(putenv_str.data()); + CHECK_TRUE(put == 0); + const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); + CHECK_TRUE(custom_buildcc_path != nullptr); + UT_PRINT(custom_buildcc_path); + + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.absolute_search_paths.push_back( - (fs::current_path() / "does_not_exist").string()); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); - std::vector verified_toolchains = - gcc.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(verified_toolchains.empty()); + CHECK_THROWS(std::exception, gcc.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_PathContainsDir) { - buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", - "ar", "ld"); +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Clang) { + buildcc::Toolchain clang(buildcc::ToolchainId::Clang, "clang", "llvm-as", + "clang", "clang++", "llvm-ar", "lld"); + + std::vector version_stdout_data{"version"}; + std::vector arch_stdout_data{"arch"}; + buildcc::env::m::CommandExpect_Execute(1, true, &version_stdout_data); + buildcc::env::m::CommandExpect_Execute(1, true, &arch_stdout_data); - buildcc::VerifyToolchainConfig config; + std::string putenv_str = fmt::format( + "CUSTOM_BUILDCC_PATH={}/toolchains/clang", fs::current_path()); + int put = putenv(putenv_str.data()); + CHECK_TRUE(put == 0); + const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); + CHECK_TRUE(custom_buildcc_path != nullptr); + UT_PRINT(custom_buildcc_path); + + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.absolute_search_paths.push_back( - (fs::current_path() / "toolchains").string()); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + buildcc::ToolchainCompilerInfo compiler_info = clang.Verify(config); - std::vector verified_toolchains = - gcc.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(verified_toolchains.empty()); + STRCMP_EQUAL(compiler_info.compiler_version.c_str(), "version"); + STRCMP_EQUAL(compiler_info.target_arch.c_str(), "arch"); } -TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_CompilerVersion) { - buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", - "ar", "ld"); +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Msvc) { + buildcc::Toolchain msvc(buildcc::ToolchainId::Msvc, "msvc", "cl", "cl", "cl", + "lib", "link"); + // Setup ENV + // VSCMD_VER + std::string vscmd_ver = std::string("VSCMD_VER=version"); + // VSCMD_ARG_HOST_ARCH + std::string host_arch = std::string("VSCMD_ARG_HOST_ARCH=host_arch"); + // VSCMD_ARG_TGT_ARCH + std::string tgt_arch = std::string("VSCMD_ARG_TGT_ARCH=tgt_arch"); - buildcc::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); -} + CHECK_TRUE(putenv(vscmd_ver.data()) == 0); + CHECK_TRUE(putenv(host_arch.data()) == 0); + CHECK_TRUE(putenv(tgt_arch.data()) == 0); -TEST(ToolchainTestGroup, - VerifyToolchain_ConditionalAdd_CompilerVersionFailure) { - buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", - "ar", "ld"); + // MSVC Compiler + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/msvc", fs::current_path()); + int put = putenv(putenv_str.data()); + CHECK_TRUE(put == 0); + const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); + CHECK_TRUE(custom_buildcc_path != nullptr); + UT_PRINT(custom_buildcc_path); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig 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); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + buildcc::ToolchainCompilerInfo compiler_info = msvc.Verify(config); + + STRCMP_EQUAL(compiler_info.compiler_version.c_str(), "version"); + STRCMP_EQUAL(compiler_info.target_arch.c_str(), "host_arch_tgt_arch"); } -TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_TargetArch) { - buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", - "ar", "ld"); +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Custom_VerificationSuccess) { + buildcc::Toolchain::AddVerificationFunc( + buildcc::ToolchainId::Custom, + [](const buildcc::ToolchainExecutables &executables) + -> std::optional { + (void)executables; + buildcc::ToolchainCompilerInfo compiler_info; + compiler_info.compiler_version = "custom_compiler_version"; + compiler_info.target_arch = "custom_target_arch"; + return compiler_info; + }, + "success_verification_func"); + buildcc::Toolchain custom(buildcc::ToolchainId::Custom, "custom", "assembler", + "c_compiler", "cpp_compiler", "archiver", "linker"); + buildcc::ToolchainVerifyConfig config; + config.env_vars.clear(); + config.absolute_search_paths.insert( + (fs::current_path() / "toolchains" / "custom")); + config.verification_identifier = "success_verification_func"; + auto compiler_info = custom.Verify(config); + STRCMP_EQUAL(compiler_info.compiler_version.c_str(), + "custom_compiler_version"); + STRCMP_EQUAL(compiler_info.target_arch.c_str(), "custom_target_arch"); +} - buildcc::VerifyToolchainConfig config; +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Custom_VerificationFailure) { + buildcc::Toolchain::AddVerificationFunc( + buildcc::ToolchainId::Custom, + [](const buildcc::ToolchainExecutables &executables) + -> std::optional { + (void)executables; + return {}; + }, + "failure_verification_func"); + + // Adding verification function with the same identifier throws an exception + CHECK_THROWS(std::exception, + (buildcc::Toolchain::AddVerificationFunc( + buildcc::ToolchainId::Custom, + [](const buildcc::ToolchainExecutables &executables) + -> std::optional { + (void)executables; + return {}; + }, + "failure_verification_func"))); + buildcc::Toolchain custom(buildcc::ToolchainId::Custom, "custom", "assembler", + "c_compiler", "cpp_compiler", "archiver", "linker"); + + buildcc::ToolchainVerifyConfig 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); + config.absolute_search_paths.insert( + (fs::current_path() / "toolchains" / "custom")); + // Fails since ToolchainId::Custom expects a verification_identifier + CHECK_THROWS(std::exception, custom.Verify(config)); + + // Fails since we do not get valid ToolchainCompilerInfo + config.verification_identifier = "failure_verification_func"; + CHECK_THROWS(std::exception, custom.Verify(config)); + + // Fails since we have not registered a verification function with this id + config.verification_identifier = "unregistered_verification_func"; + CHECK_THROWS(std::exception, custom.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_TargetArchFailure) { - buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", +TEST(ToolchainVerifyTestGroup, VerifyToolchain_Undefined_AddVerificationFunc) { + CHECK_THROWS(std::exception, + (buildcc::Toolchain::AddVerificationFunc( + buildcc::ToolchainId::Undefined, + [](const buildcc::ToolchainExecutables &executables) + -> std::optional { + (void)executables; + return {}; + }, + "undefined_verification_func"))); +} + +TEST(ToolchainVerifyTestGroup, VerifyToolchain_BadCompilerId) { + buildcc::Toolchain gcc((buildcc::ToolchainId)65535, "gcc", "as", "gcc", "g++", "ar", "ld"); - buildcc::VerifyToolchainConfig config; + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/gcc", fs::current_path()); + int put = putenv(putenv_str.data()); + CHECK_TRUE(put == 0); + const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); + CHECK_TRUE(custom_buildcc_path != nullptr); + UT_PRINT(custom_buildcc_path); + + buildcc::ToolchainVerifyConfig 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); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + CHECK_THROWS(std::exception, gcc.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_ConditionalAdd_BothFailure) { +TEST(ToolchainVerifyTestGroup, VerifyToolchain_BadAbsolutePath) { buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", "ar", "ld"); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig 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); + config.absolute_search_paths.insert((fs::current_path() / "does_not_exist")); + + CHECK_THROWS(std::exception, gcc.Verify(config)); } -TEST(ToolchainTestGroup, VerifyToolchain_UpdateFalse) { +TEST(ToolchainVerifyTestGroup, VerifyToolchain_PathContainsDir) { buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", "ar", "ld"); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig 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); + config.absolute_search_paths.insert((fs::current_path() / "toolchains")); + + CHECK_THROWS(std::exception, gcc.Verify(config)); } #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__MINGW64__) -TEST(ToolchainTestGroup, VerifyToolchain_LockedFolder) { +TEST(ToolchainVerifyTestGroup, + VerifyToolchain_Msvc_CompilerVersionAndTargetArchFailure) { + buildcc::Toolchain msvc(buildcc::ToolchainId::Msvc, "msvc", "cl", "cl", "cl", + "lib", "link"); + // Setup ENV + // VSCMD_VER + // std::string vscmd_ver = std::string("VSCMD_VER=version"); + // // VSCMD_ARG_HOST_ARCH + // std::string host_arch = std::string("VSCMD_ARG_HOST_ARCH=host_arch"); + // // VSCMD_ARG_TGT_ARCH + // std::string tgt_arch = std::string("VSCMD_ARG_TGT_ARCH=tgt_arch"); + + // CHECK_TRUE(putenv(vscmd_ver.data()) == 0); + // CHECK_TRUE(putenv(host_arch.data()) == 0); + // CHECK_TRUE(putenv(tgt_arch.data()) == 0); + + // MSVC Compiler + std::string putenv_str = + fmt::format("CUSTOM_BUILDCC_PATH={}/toolchains/msvc", fs::current_path()); + int put = putenv(putenv_str.data()); + CHECK_TRUE(put == 0); + const char *custom_buildcc_path = getenv("CUSTOM_BUILDCC_PATH"); + CHECK_TRUE(custom_buildcc_path != nullptr); + UT_PRINT(custom_buildcc_path); + + buildcc::ToolchainVerifyConfig config; + config.env_vars.clear(); + config.env_vars.insert("CUSTOM_BUILDCC_PATH"); + + CHECK_THROWS(std::exception, msvc.Verify(config)); +} + +TEST(ToolchainVerifyTestGroup, VerifyToolchain_LockedFolder) { std::error_code err; fs::permissions(fs::current_path() / "toolchains" / "gcc", fs::perms::none, err); @@ -318,15 +372,12 @@ TEST(ToolchainTestGroup, VerifyToolchain_LockedFolder) { buildcc::Toolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", "ar", "ld"); - buildcc::VerifyToolchainConfig config; + buildcc::ToolchainVerifyConfig config; config.env_vars.clear(); - config.absolute_search_paths.push_back( - (fs::current_path() / "toolchains" / "gcc").string()); + config.absolute_search_paths.insert( + (fs::current_path() / "toolchains" / "gcc")); - std::vector verified_toolchains = - gcc.Verify(config); - UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); - CHECK_TRUE(verified_toolchains.empty()); + CHECK_THROWS(std::exception, gcc.Verify(config)); fs::permissions(fs::current_path() / "toolchains" / "gcc", fs::perms::all, err); @@ -351,6 +402,6 @@ int main(int ac, char **av) { // toolchains/msvc // toolchains/mingw // TODO, Check executables used in clang - + MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); return CommandLineTestRunner::RunAllTests(ac, av); } diff --git a/buildcc/lib/toolchain/test/toolchains/custom/archiver b/buildcc/lib/toolchain/test/toolchains/custom/archiver new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/archiver.exe b/buildcc/lib/toolchain/test/toolchains/custom/archiver.exe new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/assembler b/buildcc/lib/toolchain/test/toolchains/custom/assembler new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/assembler.exe b/buildcc/lib/toolchain/test/toolchains/custom/assembler.exe new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/c_compiler b/buildcc/lib/toolchain/test/toolchains/custom/c_compiler new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/c_compiler.exe b/buildcc/lib/toolchain/test/toolchains/custom/c_compiler.exe new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/cpp_compiler b/buildcc/lib/toolchain/test/toolchains/custom/cpp_compiler new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/cpp_compiler.exe b/buildcc/lib/toolchain/test/toolchains/custom/cpp_compiler.exe new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/linker b/buildcc/lib/toolchain/test/toolchains/custom/linker new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/lib/toolchain/test/toolchains/custom/linker.exe b/buildcc/lib/toolchain/test/toolchains/custom/linker.exe new file mode 100644 index 00000000..e69de29b diff --git a/buildcc/toolchains/include/toolchains/toolchain_mingw.h b/buildcc/toolchains/include/toolchains/toolchain_mingw.h index 05bef7ca..d0e76824 100644 --- a/buildcc/toolchains/include/toolchains/toolchain_mingw.h +++ b/buildcc/toolchains/include/toolchains/toolchain_mingw.h @@ -19,6 +19,8 @@ #include "toolchain/toolchain.h" +#include "toolchain_gcc.h" + namespace buildcc { constexpr const char *const kMingwObjExt = ".o"; diff --git a/buildexe/buildexe.cpp b/buildexe/buildexe.cpp index faa7ede4..5b0cc000 100644 --- a/buildexe/buildexe.cpp +++ b/buildexe/buildexe.cpp @@ -60,7 +60,8 @@ int main(int argc, char **argv) { // Host Toolchain BaseToolchain toolchain = buildexe_args.GetHostToolchainArg().ConstructToolchain(); - find_toolchain_verify(toolchain); + toolchain.Verify(); + if (buildexe_args.GetBuildMode() == BuildExeMode::Script) { host_toolchain_verify(toolchain); } diff --git a/buildexe/include/buildexe/toolchain_setup.h b/buildexe/include/buildexe/toolchain_setup.h index 423bbbf4..2f87b9f3 100644 --- a/buildexe/include/buildexe/toolchain_setup.h +++ b/buildexe/include/buildexe/toolchain_setup.h @@ -21,7 +21,6 @@ namespace buildcc { -void find_toolchain_verify(BaseToolchain &toolchain); void host_toolchain_verify(const BaseToolchain &toolchain); } // namespace buildcc diff --git a/buildexe/src/toolchain_setup.cpp b/buildexe/src/toolchain_setup.cpp index 198bf40d..b007f51b 100644 --- a/buildexe/src/toolchain_setup.cpp +++ b/buildexe/src/toolchain_setup.cpp @@ -24,31 +24,6 @@ constexpr const char *const kTag = "BuildExe"; namespace buildcc { -void find_toolchain_verify(BaseToolchain &toolchain) { - auto verified_toolchains = toolchain.Verify(); - env::assert_fatal(!verified_toolchains.empty(), - "Toolchain could not be verified. Please input correct " - "Gcc, Msvc, Clang or MinGW toolchain executable names"); - if (verified_toolchains.size() > 1) { - env::log_info( - kTag, - fmt::format( - "Found {} toolchains. By default using the first added" - "toolchain. Modify your environment `PATH` information if you " - "would like compiler precedence when similar compilers are " - "detected in different folders", - verified_toolchains.size())); - } - - // Print - int counter = 1; - for (const auto &vt : verified_toolchains) { - std::string info = fmt::format("{}. : {}", counter, vt.ToString()); - env::log_info("Host Toolchain", info); - counter++; - } -} - void host_toolchain_verify(const BaseToolchain &toolchain) { env::log_info(kTag, "*** Starting Toolchain verification ***"); diff --git a/example/hybrid/single/build.cpp b/example/hybrid/single/build.cpp index 3abace55..b8b104d5 100644 --- a/example/hybrid/single/build.cpp +++ b/example/hybrid/single/build.cpp @@ -24,8 +24,7 @@ int main(int argc, char **argv) { // 4. Build steps // Explicit toolchain - target pairs Toolchain_gcc gcc; - auto verified_toolchains = gcc.Verify(); - env::assert_fatal(!verified_toolchains.empty(), "GCC Toolchain not found"); + gcc.Verify(); ExecutableTarget_gcc hello_world("hello_world", gcc, "");