diff --git a/.github/workflows/linux_gcc_cmake_build.yml b/.github/workflows/linux_gcc_cmake_build.yml index 0d339a6f..a9ff625c 100644 --- a/.github/workflows/linux_gcc_cmake_build.yml +++ b/.github/workflows/linux_gcc_cmake_build.yml @@ -71,7 +71,7 @@ jobs: - name: BuildExe IM example tiny-process-library working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_ALL}} run: | - cmake --build . --target run_buildexe_im_tpl_linux_gcc + cmake --build . --target run_buildexe_im_tpl_gcc_linux - name: Install working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_ALL}} @@ -192,7 +192,15 @@ jobs: - name: BuildExe IM example tiny-process-library working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_SINGLE}} run: | - cmake --build . --target run_buildexe_im_tpl_linux_gcc + cmake --build . --target run_buildexe_im_tpl_gcc_linux + + # - name: TODO, BuildExe SM simple hyrid example + + - name: Upload BuildExe + uses: actions/upload-artifact@v2 + with: + name: "BuildExe_Linux" + path: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_SINGLE}}/buildexe/buildexe - name: Install working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_SINGLE}} diff --git a/.github/workflows/win_cmake_build.yml b/.github/workflows/win_cmake_build.yml index cb7fd826..32987a40 100644 --- a/.github/workflows/win_cmake_build.yml +++ b/.github/workflows/win_cmake_build.yml @@ -58,7 +58,15 @@ jobs: - name: BuildExe IM example tiny-process-library working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_buildexe_im_tpl_win_msvc + cmake --build . --config Release --target run_buildexe_im_tpl_msvc_win + + # - name: TODO, BuildExe SM simple hyrid example + + - name: Upload BuildExe + uses: actions/upload-artifact@v2 + with: + name: "BuildExe_Win" + path: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}}/buildexe/Release/buildexe.exe - name: Install working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} diff --git a/bootstrap/include/bootstrap/build_buildcc.h b/bootstrap/include/bootstrap/build_buildcc.h index a0c37e09..2bbbfbc6 100644 --- a/bootstrap/include/bootstrap/build_buildcc.h +++ b/bootstrap/include/bootstrap/build_buildcc.h @@ -19,6 +19,13 @@ #include "buildcc.h" +#include "build_cli11.h" +#include "build_flatbuffers.h" +#include "build_fmtlib.h" +#include "build_spdlog.h" +#include "build_taskflow.h" +#include "build_tpl.h" + namespace buildcc { void schema_gen_cb(BaseGenerator &generator, const BaseTarget &flatc_exe); @@ -28,6 +35,53 @@ void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen, const TargetInfo &spdlog_ho, const TargetInfo &cli11_ho, const TargetInfo &taskflow_ho, const BaseTarget &tpl); +/** + * @brief + * + */ +class BuildBuildCC { +public: + // TargetInfo / Header Only + static constexpr const char *const kFlatbuffersHoName = "flatbuffers_ho"; + static constexpr const char *const kCli11HoName = "cli11_ho"; + static constexpr const char *const kFmtHoName = "fmtlib_ho"; + static constexpr const char *const kSpdlogHoName = "spdlog_ho"; + static constexpr const char *const kTaskflowHoName = "taskflow_ho"; + + // Executable + static constexpr const char *const kFlatcExeName = "flatc"; + + // Generator + static constexpr const char *const kSchemaGenName = "schema_gen"; + + // Libraries + static constexpr const char *const kTplLibName = "libtpl"; + static constexpr const char *const kBuildccLibName = "libbuildcc"; + +public: + BuildBuildCC(Register ®, const BaseToolchain &toolchain, + const TargetEnv &env) + : reg_(reg), toolchain_(toolchain), env_(env) {} + BuildBuildCC(const BuildBuildCC &) = delete; + + void Setup(const ArgToolchainState &state); + + // Getters + StaticTarget_generic &GetTpl() { + return storage_.Ref(kTplLibName); + } + StaticTarget_generic &GetBuildcc() { + return storage_.Ref(kBuildccLibName); + } + +private: + Register ®_; + const BaseToolchain &toolchain_; + TargetEnv env_; + + PersistentStorage storage_; +}; + } // namespace buildcc #endif diff --git a/bootstrap/main.buildcc.cpp b/bootstrap/main.buildcc.cpp index 6f92455f..ee26e955 100644 --- a/bootstrap/main.buildcc.cpp +++ b/bootstrap/main.buildcc.cpp @@ -28,12 +28,6 @@ using namespace buildcc; static void clean_cb(); -static void global_flags_cb(TargetInfo &global_info, - const BaseToolchain &toolchain); - -static void setup_buildcc_cb(PersistentStorage &storage, Register ®, - const ArgToolchain &custom_toolchain_arg, - const BaseToolchain &toolchain); static void hybrid_simple_example_cb(BaseTarget &target, const BaseTarget &libbuildcc); @@ -50,11 +44,12 @@ int main(int argc, char **argv) { BaseToolchain toolchain = custom_toolchain_arg.ConstructToolchain(); PersistentStorage storage; - setup_buildcc_cb(storage, reg, custom_toolchain_arg, toolchain); - - const StaticTarget_generic &buildcc_lib = - storage.ConstRef("libbuildcc"); + BuildBuildCC buildcc( + reg, toolchain, + TargetEnv(env::get_project_root_dir(), env::get_project_build_dir())); + buildcc.Setup(custom_toolchain_arg.state); + const auto &buildcc_lib = buildcc.GetBuildcc(); ExecutableTarget_generic buildcc_hybrid_simple_example( "buildcc_hybrid_simple_example", toolchain, "example/hybrid/simple"); reg.Build(custom_toolchain_arg.state, hybrid_simple_example_cb, @@ -78,92 +73,9 @@ int main(int argc, char **argv) { static void clean_cb() {} -static void global_flags_cb(TargetInfo &global_info, - const BaseToolchain &toolchain) { - // TODO, Clang - switch (toolchain.GetId()) { - case ToolchainId::Gcc: - case ToolchainId::MinGW: - global_info.AddCppCompileFlag("-std=c++17"); - global_info.AddCppCompileFlag("-Os"); - global_info.AddCppCompileFlag("-Wall"); - global_info.AddCppCompileFlag("-Wextra"); - global_info.AddCppCompileFlag("-Werror"); - break; - case ToolchainId::Msvc: - global_info.AddPreprocessorFlag("/D_CRT_SECURE_NO_WARNINGS"); - global_info.AddCppCompileFlag("/std:c++17"); - global_info.AddCppCompileFlag("/Ot"); - global_info.AddCppCompileFlag("/W4"); - global_info.AddCppCompileFlag("/WX"); - default: - break; - } -} - -static void setup_buildcc_cb(PersistentStorage &storage, Register ®, - const ArgToolchain &custom_toolchain_arg, - const BaseToolchain &toolchain) { - - // Flatc Executable - ExecutableTarget_generic &flatc_exe = storage.Add( - "flatc", "flatc", toolchain, "third_party/flatbuffers"); - reg.CallbackIf(custom_toolchain_arg.state, global_flags_cb, flatc_exe, - toolchain); - reg.Build(custom_toolchain_arg.state, build_flatc_exe_cb, flatc_exe); - - // Schema - BaseGenerator &schema_gen = - storage.Add("schema_gen", "schema_gen", "buildcc/schema"); - reg.Build(schema_gen_cb, schema_gen, flatc_exe); - reg.Dep(schema_gen, flatc_exe); - - // Flatbuffers HO lib - TargetInfo &flatbuffers_ho_lib = - storage.Add("flatbuffers_ho", "third_party/flatbuffers"); - reg.Callback(flatbuffers_ho_cb, flatbuffers_ho_lib); - - // CLI11 HO lib - TargetInfo &cli11_ho_lib = - storage.Add("cli11_ho", "third_party/CLI11"); - reg.Callback(cli11_ho_cb, cli11_ho_lib); - - // fmt HO lib - TargetInfo &fmt_ho_lib = storage.Add("fmt_ho", "third_party/fmt"); - reg.Callback(fmt_ho_cb, fmt_ho_lib); - - // spdlog HO lib - TargetInfo &spdlog_ho_lib = - storage.Add("spdlog_ho", "third_party/spdlog"); - reg.Callback(spdlog_ho_cb, spdlog_ho_lib); - - // taskflow HO lib - TargetInfo &taskflow_ho_lib = - storage.Add("taskflow_ho", "third_party/taskflow"); - reg.Callback(taskflow_ho_cb, taskflow_ho_lib); - - // Tiny-process-library lib - // TODO, Make this a generic selection between StaticTarget and DynamicTarget - StaticTarget_generic &tpl_lib = storage.Add( - "libtpl", "libtpl", toolchain, "third_party/tiny-process-library"); - reg.CallbackIf(custom_toolchain_arg.state, global_flags_cb, tpl_lib, - toolchain); - reg.Build(custom_toolchain_arg.state, tpl_cb, tpl_lib); - - // TODO, Make this a generic selection between StaticTarget and DynamicTarget - StaticTarget_generic &buildcc_lib = storage.Add( - "libbuildcc", "libbuildcc", toolchain, "buildcc"); - reg.CallbackIf(custom_toolchain_arg.state, global_flags_cb, buildcc_lib, - toolchain); - reg.Build(custom_toolchain_arg.state, buildcc_cb, buildcc_lib, schema_gen, - flatbuffers_ho_lib, fmt_ho_lib, spdlog_ho_lib, cli11_ho_lib, - taskflow_ho_lib, tpl_lib); - reg.Dep(buildcc_lib, schema_gen); - reg.Dep(buildcc_lib, tpl_lib); -} - static void hybrid_simple_example_cb(BaseTarget &target, const BaseTarget &libbuildcc) { + target.AddLibDep(libbuildcc); target.Insert(libbuildcc, { SyncOption::PreprocessorFlags, SyncOption::CppCompileFlags, @@ -174,6 +86,5 @@ static void hybrid_simple_example_cb(BaseTarget &target, SyncOption::ExternalLibDeps, }); target.AddSource("build.cpp"); - target.AddLibDep(libbuildcc); target.Build(); } diff --git a/bootstrap/src/build_buildcc.cpp b/bootstrap/src/build_buildcc.cpp index f8ae45e5..ec40da1b 100644 --- a/bootstrap/src/build_buildcc.cpp +++ b/bootstrap/src/build_buildcc.cpp @@ -154,4 +154,102 @@ void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen, target.Build(); } +// TODO, Shift this inside BuildBuildcc class if required +// TODO, Add this to options +static void global_flags_cb(TargetInfo &global_info, + const BaseToolchain &toolchain) { + // TODO, Clang + switch (toolchain.GetId()) { + case ToolchainId::Gcc: + case ToolchainId::MinGW: + global_info.AddCppCompileFlag("-std=c++17"); + global_info.AddCppCompileFlag("-Os"); + global_info.AddCppCompileFlag("-Wall"); + global_info.AddCppCompileFlag("-Wextra"); + global_info.AddCppCompileFlag("-Werror"); + break; + case ToolchainId::Msvc: + global_info.AddPreprocessorFlag("/D_CRT_SECURE_NO_WARNINGS"); + global_info.AddCppCompileFlag("/std:c++17"); + global_info.AddCppCompileFlag("/Ot"); + global_info.AddCppCompileFlag("/W4"); + global_info.AddCppCompileFlag("/WX"); + default: + break; + } +} + +void BuildBuildCC::Setup(const ArgToolchainState &state) { + auto &flatc_exe = storage_.Add( + kFlatcExeName, kFlatcExeName, toolchain_, + TargetEnv(env_.GetTargetRootDir() / "third_party" / "flatbuffers", + env_.GetTargetBuildDir())); + + reg_.CallbackIf(state, global_flags_cb, flatc_exe, toolchain_); + reg_.Build(state, build_flatc_exe_cb, flatc_exe); + + // Schema + auto &schema_gen = storage_.Add( + kSchemaGenName, kSchemaGenName, + TargetEnv(env_.GetTargetRootDir() / "buildcc" / "schema", + env_.GetTargetBuildDir() / toolchain_.GetName())); + reg_.Build(schema_gen_cb, schema_gen, flatc_exe); + reg_.Dep(schema_gen, flatc_exe); + + // Flatbuffers HO lib + auto &flatbuffers_ho_lib = storage_.Add( + kFlatbuffersHoName, + TargetEnv(env_.GetTargetRootDir() / "third_party" / "flatbuffers", + env_.GetTargetBuildDir())); + reg_.CallbackIf(state, flatbuffers_ho_cb, flatbuffers_ho_lib); + + // CLI11 HO lib + auto &cli11_ho_lib = storage_.Add( + kCli11HoName, TargetEnv(env_.GetTargetRootDir() / "third_party" / "CLI11", + env_.GetTargetBuildDir())); + reg_.CallbackIf(state, cli11_ho_cb, cli11_ho_lib); + + // fmt HO lib + auto &fmt_ho_lib = storage_.Add( + kFmtHoName, TargetEnv(env_.GetTargetRootDir() / "third_party" / "fmt", + env_.GetTargetBuildDir())); + reg_.CallbackIf(state, fmt_ho_cb, fmt_ho_lib); + + // spdlog HO lib + auto &spdlog_ho_lib = storage_.Add( + kSpdlogHoName, + TargetEnv(env_.GetTargetRootDir() / "third_party" / "spdlog", + env_.GetTargetBuildDir())); + reg_.CallbackIf(state, spdlog_ho_cb, spdlog_ho_lib); + + // taskflow HO lib + auto &taskflow_ho_lib = storage_.Add( + kTaskflowHoName, + TargetEnv(env_.GetTargetRootDir() / "third_party" / "taskflow", + env_.GetTargetBuildDir())); + reg_.CallbackIf(state, taskflow_ho_cb, taskflow_ho_lib); + + // Tiny-process-library lib + // TODO, Make this a generic selection between StaticTarget and + // DynamicTarget + auto &tpl_lib = storage_.Add( + kTplLibName, kTplLibName, toolchain_, + TargetEnv(env_.GetTargetRootDir() / "third_party" / + "tiny-process-library", + env_.GetTargetBuildDir())); + reg_.CallbackIf(state, global_flags_cb, tpl_lib, toolchain_); + reg_.Build(state, tpl_cb, tpl_lib); + + // TODO, Make this a generic selection between StaticTarget and + // DynamicTarget + auto &buildcc_lib = storage_.Add( + kBuildccLibName, kBuildccLibName, toolchain_, + TargetEnv(env_.GetTargetRootDir() / "buildcc", env_.GetTargetBuildDir())); + reg_.CallbackIf(state, global_flags_cb, buildcc_lib, toolchain_); + reg_.Build(state, buildcc_cb, buildcc_lib, schema_gen, flatbuffers_ho_lib, + fmt_ho_lib, spdlog_ho_lib, cli11_ho_lib, taskflow_ho_lib, tpl_lib); + reg_.Dep(buildcc_lib, schema_gen); + reg_.Dep(buildcc_lib, tpl_lib); +} + } // namespace buildcc diff --git a/buildcc/lib/env/include/env/util.h b/buildcc/lib/env/include/env/util.h index 391b5743..7300af04 100644 --- a/buildcc/lib/env/include/env/util.h +++ b/buildcc/lib/env/include/env/util.h @@ -33,6 +33,7 @@ #ifndef ENV_UTIL_H_ #define ENV_UTIL_H_ +#include #include #include #include @@ -120,6 +121,38 @@ inline std::vector split(const std::string &s, char delim) { return result; } +// https://stackoverflow.com/questions/44973435/stdptr-fun-replacement-for-c17/44973498#44973498 +inline std::string ltrim(const std::string &s) { + std::string tr{s}; + // Checks from left (beginning) and finds the `end point` where no `isspace` + // char is detected + auto l_tr_end = std::find_if(tr.begin(), tr.end(), + [](char c) { return !std::isspace(c); }); + tr.erase(tr.begin(), l_tr_end); + return tr; +} + +inline std::string rtrim(const std::string &s) { + std::string tr{s}; + // Checks from right (ending) and finds the `start point` where no `isspace` + // char is detected + // Gets the base iterator (which is forward in nature) + auto r_tr_begin = std::find_if(tr.rbegin(), tr.rend(), [](char c) { + return !std::isspace(c); + }).base(); + tr.erase(r_tr_begin, tr.end()); + return tr; +} + +/** + * @brief Trims both left and right part of the string + */ +inline std::string trim(const std::string &s) { + std::string tr = ltrim(s); + tr = rtrim(tr); + return tr; +} + } // namespace buildcc::env #endif diff --git a/buildcc/lib/target/include/target/api/target_info_getter.h b/buildcc/lib/target/include/target/api/target_info_getter.h index aa4be8e0..6e3b6b52 100644 --- a/buildcc/lib/target/include/target/api/target_info_getter.h +++ b/buildcc/lib/target/include/target/api/target_info_getter.h @@ -47,8 +47,8 @@ template class TargetInfoGetter { const internal::fs_unordered_set &GetCurrentSourceFiles() const; const internal::fs_unordered_set &GetCurrentHeaderFiles() const; const internal::fs_unordered_set &GetCurrentPchFiles() const; - const internal::fs_unordered_set &GetTargetLibDeps() const; - const std::unordered_set &GetCurrentExternalLibDeps() const; + const std::vector &GetTargetLibDeps() const; + const std::vector &GetCurrentExternalLibDeps() const; const internal::fs_unordered_set &GetCurrentIncludeDirs() const; const internal::fs_unordered_set &GetCurrentLibDirs() const; const std::unordered_set &GetCurrentPreprocessorFlags() const; diff --git a/buildcc/lib/target/include/target/base/target_storer.h b/buildcc/lib/target/include/target/base/target_storer.h index d6ff3996..b12f5dde 100644 --- a/buildcc/lib/target/include/target/base/target_storer.h +++ b/buildcc/lib/target/include/target/base/target_storer.h @@ -27,12 +27,17 @@ struct TargetStorer { internal::RelationalPathFiles current_source_files; internal::RelationalPathFiles current_header_files; internal::RelationalPathFiles current_pch_files; - internal::RelationalPathFiles current_lib_deps; + + // NOTE, Order matters (BuildCC takes care of the order here) + std::vector current_user_lib_deps; + internal::path_unordered_set current_internal_lib_deps; internal::fs_unordered_set current_include_dirs; internal::fs_unordered_set current_lib_dirs; - std::unordered_set current_external_lib_deps; + // NOTE, Order matters (user takes care of the order here) + std::vector current_user_external_lib_deps; + std::unordered_set current_internal_external_lib_deps; std::unordered_set current_preprocessor_flags; std::unordered_set current_common_compile_flags; diff --git a/buildcc/lib/target/include/target/generator.h b/buildcc/lib/target/include/target/generator.h index 0436d128..349c34b5 100644 --- a/buildcc/lib/target/include/target/generator.h +++ b/buildcc/lib/target/include/target/generator.h @@ -33,17 +33,18 @@ #include "target/interface/builder_interface.h" #include "target/base/generator_loader.h" + #include "target/common/path.h" +#include "target/common/target_env.h" namespace buildcc::base { class Generator : public BuilderInterface { public: - Generator(const std::string &name, - const fs::path &target_path_relative_to_root, bool parallel = false) - : name_(name), generator_root_dir_(env::get_project_root_dir() / - target_path_relative_to_root), - generator_build_dir_(env::get_project_build_dir() / name), + Generator(const std::string &name, const TargetEnv &env, + bool parallel = false) + : name_(name), generator_root_dir_(env.GetTargetRootDir()), + generator_build_dir_(env.GetTargetBuildDir() / name), loader_(name, generator_build_dir_), parallel_(parallel) { Initialize(); } diff --git a/buildcc/lib/target/src/api/lib_api.cpp b/buildcc/lib/target/src/api/lib_api.cpp index 5fcd05d5..55eca4b1 100644 --- a/buildcc/lib/target/src/api/lib_api.cpp +++ b/buildcc/lib/target/src/api/lib_api.cpp @@ -41,14 +41,14 @@ template void LibApi::AddLibDep(const Target &lib_dep) { T &t = static_cast(*this); t.state_.ExpectsUnlock(); - t.storer_.current_lib_deps.user.insert(lib_dep.GetTargetPath()); + t.storer_.current_user_lib_deps.push_back(lib_dep.GetTargetPath()); } template void LibApi::AddLibDep(const std::string &lib_dep) { T &t = static_cast(*this); t.state_.ExpectsUnlock(); - t.storer_.current_external_lib_deps.insert(lib_dep); + t.storer_.current_user_external_lib_deps.push_back(lib_dep); } template class LibApi; diff --git a/buildcc/lib/target/src/api/sync_api.cpp b/buildcc/lib/target/src/api/sync_api.cpp index 99b06407..80746dd0 100644 --- a/buildcc/lib/target/src/api/sync_api.cpp +++ b/buildcc/lib/target/src/api/sync_api.cpp @@ -97,8 +97,8 @@ void SyncApi::SpecializedCopy(TargetType target, std::move(target.storer_.current_pch_files.user); break; case SyncOption::LibDeps: - t.storer_.current_lib_deps.user = - std::move(target.storer_.current_lib_deps.user); + t.storer_.current_user_lib_deps = + std::move(target.storer_.current_user_lib_deps); break; case SyncOption::IncludeDirs: t.storer_.current_include_dirs = @@ -108,8 +108,8 @@ void SyncApi::SpecializedCopy(TargetType target, t.storer_.current_lib_dirs = std::move(target.storer_.current_lib_dirs); break; case SyncOption::ExternalLibDeps: - t.storer_.current_external_lib_deps = - std::move(target.storer_.current_external_lib_deps); + t.storer_.current_user_external_lib_deps = + std::move(target.storer_.current_user_external_lib_deps); break; default: env::assert_fatal("Invalid Option added"); @@ -228,9 +228,10 @@ void SyncApi::SpecializedInsert(TargetType target, std::make_move_iterator(target.storer_.current_pch_files.user.end())); break; case SyncOption::LibDeps: - t.storer_.current_lib_deps.user.insert( - std::make_move_iterator(target.storer_.current_lib_deps.user.begin()), - std::make_move_iterator(target.storer_.current_lib_deps.user.end())); + t.storer_.current_user_lib_deps.insert( + t.storer_.current_user_lib_deps.end(), + std::make_move_iterator(target.storer_.current_user_lib_deps.begin()), + std::make_move_iterator(target.storer_.current_user_lib_deps.end())); break; case SyncOption::IncludeDirs: t.storer_.current_include_dirs.insert( @@ -243,11 +244,12 @@ void SyncApi::SpecializedInsert(TargetType target, std::make_move_iterator(target.storer_.current_lib_dirs.end())); break; case SyncOption::ExternalLibDeps: - t.storer_.current_external_lib_deps.insert( + t.storer_.current_user_external_lib_deps.insert( + t.storer_.current_user_external_lib_deps.end(), std::make_move_iterator( - target.storer_.current_external_lib_deps.begin()), + target.storer_.current_user_external_lib_deps.begin()), std::make_move_iterator( - target.storer_.current_external_lib_deps.end())); + target.storer_.current_user_external_lib_deps.end())); break; default: env::assert_fatal("Invalid Option added"); diff --git a/buildcc/lib/target/src/api/target_info_getter.cpp b/buildcc/lib/target/src/api/target_info_getter.cpp index 2d413cf8..4383401b 100644 --- a/buildcc/lib/target/src/api/target_info_getter.cpp +++ b/buildcc/lib/target/src/api/target_info_getter.cpp @@ -88,19 +88,18 @@ TargetInfoGetter::GetCurrentPchFiles() const { } template -const internal::fs_unordered_set & -TargetInfoGetter::GetTargetLibDeps() const { +const std::vector &TargetInfoGetter::GetTargetLibDeps() const { const T &t = static_cast(*this); - return t.storer_.current_lib_deps.user; + return t.storer_.current_user_lib_deps; } template -const std::unordered_set & +const std::vector & TargetInfoGetter::GetCurrentExternalLibDeps() const { const T &t = static_cast(*this); - return t.storer_.current_external_lib_deps; + return t.storer_.current_user_external_lib_deps; } template diff --git a/buildcc/lib/target/src/target/friend/link_target.cpp b/buildcc/lib/target/src/target/friend/link_target.cpp index ec935194..d3f7908c 100644 --- a/buildcc/lib/target/src/target/friend/link_target.cpp +++ b/buildcc/lib/target/src/target/friend/link_target.cpp @@ -41,10 +41,11 @@ void LinkTarget::CacheLinkCommand() { { {kOutput, output_target}, {kCompiledSources, aggregated_compiled_sources}, + // NOTE, This needs to be ORDERED {kLibDeps, - fmt::format("{} {}", - internal::aggregate(storer.current_external_lib_deps), - internal::aggregate(storer.current_lib_deps.user))}, + fmt::format( + "{} {}", internal::aggregate(storer.current_user_lib_deps), + internal::aggregate(storer.current_user_external_lib_deps))}, }); } @@ -61,7 +62,14 @@ fs::path LinkTarget::ConstructOutputPath() const { void LinkTarget::PreLink() { auto &storer = target_.storer_; - storer.current_lib_deps.Convert(); + for (const auto &p : storer.current_user_lib_deps) { + storer.current_internal_lib_deps.emplace( + internal::Path::CreateExistingPath(p)); + } + + storer.current_internal_external_lib_deps.insert( + storer.current_user_external_lib_deps.begin(), + storer.current_user_external_lib_deps.end()); storer.current_link_dependencies.Convert(); } @@ -79,11 +87,13 @@ void LinkTarget::BuildLink() { target_.GetCurrentLinkFlags()); target_.RecheckDirs(loader.GetLoadedLibDirs(), target_.GetCurrentLibDirs()); target_.RecheckExternalLib(loader.GetLoadedExternalLibDeps(), - storer.current_external_lib_deps); + storer.current_internal_external_lib_deps); target_.RecheckPaths(loader.GetLoadedLinkDependencies(), storer.current_link_dependencies.internal); + + // NOTE, This needs to be UNORDERED target_.RecheckPaths(loader.GetLoadedLibDeps(), - storer.current_lib_deps.internal); + storer.current_internal_lib_deps); if (!loader.GetLoadedTargetLinked()) { target_.dirty_ = true; } diff --git a/buildcc/lib/target/src/target/target_storer.cpp b/buildcc/lib/target/src/target/target_storer.cpp index 20f06a0d..cf76ff9f 100644 --- a/buildcc/lib/target/src/target/target_storer.cpp +++ b/buildcc/lib/target/src/target/target_storer.cpp @@ -50,11 +50,13 @@ bool Target::Store() { builder, storer_.current_header_files.internal); auto fbs_pch_files = internal::create_fbs_vector_path( builder, storer_.current_pch_files.internal); + // NOTE, This can be UNORDERED auto fbs_lib_deps = internal::create_fbs_vector_path( - builder, storer_.current_lib_deps.internal); + builder, storer_.current_internal_lib_deps); + // NOTE, This can be UNORDERED auto fbs_external_lib_deps = internal::create_fbs_vector_string( - builder, storer_.current_external_lib_deps); + builder, storer_.current_internal_external_lib_deps); auto fbs_include_dirs = internal::create_fbs_vector_string(builder, storer_.current_include_dirs); diff --git a/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h b/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h index fee24b9f..d6d8023f 100644 --- a/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h +++ b/buildcc/lib/toolchain/include/toolchain/api/toolchain_verify.h @@ -55,12 +55,7 @@ struct VerifiedToolchain { std::string target_arch; // TODO, Add more here as needed - void Print() const { - env::log_info( - __FUNCTION__, - fmt::format("Path: {}, Compiler Version: {}, Target Triple Arch: {}", - path.string(), compiler_version, target_arch)); - } + std::string ToString() const { return fmt::format("{}", *this); } }; template class ToolchainVerify { @@ -78,4 +73,22 @@ typedef base::VerifiedToolchain VerifiedToolchain; } // namespace buildcc +constexpr const char *const kVerifiedToolchainFormat = R"({{ + "path": "{}", + "compiler_version": "{}", + "target_arch": "{}" +}})"; + +template <> +struct fmt::formatter + : formatter { + template + auto format(const buildcc::base::VerifiedToolchain &vt, FormatContext &ctx) { + std::string verified_toolchain_info = + fmt::format(kVerifiedToolchainFormat, vt.path.string(), + vt.compiler_version, vt.target_arch); + return formatter::format(verified_toolchain_info, ctx); + } +}; + #endif diff --git a/buildcc/lib/toolchain/src/api/toolchain_verify.cpp b/buildcc/lib/toolchain/src/api/toolchain_verify.cpp index 71048ec4..1afcf998 100644 --- a/buildcc/lib/toolchain/src/api/toolchain_verify.cpp +++ b/buildcc/lib/toolchain/src/api/toolchain_verify.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include "toolchain/toolchain.h" #include "env/assert_fatal.h" @@ -207,9 +209,16 @@ ToolchainVerify::Verify(const VerifyToolchainConfig &config) { 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 : fs::directory_iterator(p)) { - if (!dir_iter.is_regular_file()) { + 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(); @@ -222,8 +231,8 @@ ToolchainVerify::Verify(const VerifyToolchainConfig &config) { VerifiedToolchain vt; vt.path = p; - vt.compiler_version = GetCompilerVersion(p, t).value_or(""); - vt.target_arch = GetCompilerArchitecture(p, t).value_or(""); + 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); } diff --git a/buildcc/lib/toolchain/test/test_toolchain_verify.cpp b/buildcc/lib/toolchain/test/test_toolchain_verify.cpp index 4a92e7cc..451bcc54 100644 --- a/buildcc/lib/toolchain/test/test_toolchain_verify.cpp +++ b/buildcc/lib/toolchain/test/test_toolchain_verify.cpp @@ -176,6 +176,34 @@ TEST(ToolchainTestGroup, VerifyToolchain_PathContainsDir) { CHECK_TRUE(verified_toolchains.empty()); } +TEST(ToolchainTestGroup, VerifyToolchain_LockedFolder) { + std::error_code err; + fs::permissions(fs::current_path() / "toolchains" / "gcc", fs::perms::none, + err); + if (err) { + FAIL_TEST("Could not set file permissions"); + } + + 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()); + + std::vector verified_toolchains = + gcc.Verify(config); + UT_PRINT(std::to_string(verified_toolchains.size()).c_str()); + CHECK_TRUE(verified_toolchains.empty()); + + fs::permissions(fs::current_path() / "toolchains" / "gcc", fs::perms::all, + err); + if (err) { + FAIL_TEST("Could not set file permissions"); + } +} + int main(int ac, char **av) { buildcc::env::m::VectorStringCopier copier; mock().installCopier(TEST_VECTOR_STRING_TYPE, copier); diff --git a/buildexe/CMakeLists.txt b/buildexe/CMakeLists.txt index 2c130297..cd4bc7d8 100644 --- a/buildexe/CMakeLists.txt +++ b/buildexe/CMakeLists.txt @@ -1,6 +1,18 @@ add_executable(buildexe buildexe.cpp ) +target_sources(buildexe PRIVATE + ../bootstrap/src/build_buildcc.cpp + ../bootstrap/src/build_cli11.cpp + ../bootstrap/src/build_flatbuffers.cpp + ../bootstrap/src/build_fmtlib.cpp + ../bootstrap/src/build_spdlog.cpp + ../bootstrap/src/build_taskflow.cpp + ../bootstrap/src/build_tpl.cpp +) +target_include_directories(buildexe PRIVATE + ../bootstrap/include +) target_link_libraries(buildexe PRIVATE buildcc) # TODO, Add this only if MINGW is used @@ -18,7 +30,7 @@ add_custom_target(run_buildexe_help ) # [Immediate Mode] Tpl example WIN MSVC -add_custom_target(run_buildexe_im_tpl_win_msvc +add_custom_target(run_buildexe_im_tpl_msvc_win COMMAND buildexe --help-all COMMAND buildexe --config ${CMAKE_CURRENT_SOURCE_DIR}/example_configs/tpl_win.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/../bootstrap/config/toolchain_msvc_win.toml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -26,9 +38,33 @@ add_custom_target(run_buildexe_im_tpl_win_msvc ) # [Immediate Mode] Tpl example LINUX GCC -add_custom_target(run_buildexe_im_tpl_linux_gcc +add_custom_target(run_buildexe_im_tpl_gcc_linux COMMAND buildexe --help-all COMMAND buildexe --config ${CMAKE_CURRENT_SOURCE_DIR}/example_configs/tpl_linux.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/../bootstrap/config/toolchain_gcc_linux.toml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} VERBATIM USES_TERMINAL ) + +# [Script Mode] Simple example WIN GCC +add_custom_target(run_buildexe_sm_simple_gcc_win + COMMAND buildexe --help-all + COMMAND buildexe --config ${CMAKE_CURRENT_SOURCE_DIR}/example_configs/sm_simple_linux.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/../bootstrap/config/toolchain_gcc_win.toml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../example/hybrid/simple + VERBATIM USES_TERMINAL +) + +# [Script Mode] Simple example WIN MSVC +add_custom_target(run_buildexe_sm_simple_msvc_win + COMMAND buildexe --help-all + COMMAND buildexe --config ${CMAKE_CURRENT_SOURCE_DIR}/example_configs/sm_simple_win.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/../bootstrap/config/toolchain_msvc_win.toml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../example/hybrid/simple + VERBATIM USES_TERMINAL +) + +# [Script Mode] Simple example LINUX GCC +add_custom_target(run_buildexe_sm_simple_gcc_linux + COMMAND buildexe --help-all + COMMAND buildexe --config ${CMAKE_CURRENT_SOURCE_DIR}/example_configs/sm_simple_linux.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/../bootstrap/config/toolchain_gcc_linux.toml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../example/hybrid/simple + VERBATIM USES_TERMINAL +) diff --git a/buildexe/buildexe.cpp b/buildexe/buildexe.cpp index eb0218a0..36738ead 100644 --- a/buildexe/buildexe.cpp +++ b/buildexe/buildexe.cpp @@ -16,6 +16,14 @@ #include "buildcc.h" +#include "bootstrap/build_buildcc.h" +#include "bootstrap/build_cli11.h" +#include "bootstrap/build_flatbuffers.h" +#include "bootstrap/build_fmtlib.h" +#include "bootstrap/build_spdlog.h" +#include "bootstrap/build_taskflow.h" +#include "bootstrap/build_tpl.h" + using namespace buildcc; constexpr const char *const kTag = "BuildExe"; @@ -49,6 +57,10 @@ struct ArgTargetInputs { std::vector link_flags; }; +struct ArgScriptInfo { + std::vector configs; +}; + static const std::unordered_map kTargetTypeMap{ {"executable", TargetType::Executable}, {"staticLibrary", TargetType::StaticLibrary}, @@ -64,11 +76,17 @@ static void clean_cb(); static void setup_arg_target_info(Args &args, ArgTargetInfo &out); static void setup_arg_target_inputs(Args &args, ArgTargetInputs &out); +static void setup_arg_script_mode(Args &args, ArgScriptInfo &out); + +static void host_toolchain_verify(const BaseToolchain &toolchain); + +static fs::path get_env_buildcc_home(); static void user_output_target_cb(BaseTarget &target, const ArgTargetInputs &inputs); // TODO, Add BuildExeMode::Script usage +// TODO, Refactor magic strings int main(int argc, char **argv) { Args args; @@ -92,10 +110,14 @@ int main(int argc, char **argv) { ArgTargetInputs out_targetinputs; setup_arg_target_inputs(args, out_targetinputs); - // TODO, Add base (git cloned raw versions) - // TODO, Add libraries (compiled version of code! with libs and header - // linkage options) - // TODO, Add extension + ArgScriptInfo out_scriptinfo; + setup_arg_script_mode(args, out_scriptinfo); + + // script mode specific arguments + + // TODO, Add buildcc (git cloned) + // TODO, Add libraries (git cloned) + // TODO, Add extension (git cloned) args.Parse(argc, argv); @@ -104,22 +126,105 @@ int main(int argc, char **argv) { // Build BaseToolchain toolchain = custom_toolchain_arg.ConstructToolchain(); - // TODO, Verify toolchain by compiling a dummy program + // BaseToolchain toolchain = custom_toolchain_arg.ConstructToolchain(); + 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++; + } + + // TODO, Update Toolchain with VerifiedToolchain + // toolchain.UpdateFrom(verified_toolchain); + + if (mode == BuildExeMode::Script) { + host_toolchain_verify(toolchain); + } + + PersistentStorage storage; Target_generic user_output_target(out_targetinfo.name, out_targetinfo.type, toolchain, TargetEnv(out_targetinfo.relative_to_root)); - // if (mode == BuildExeMode::Script) { - // TODO, Compile BuildCC here (and make persistent) - // NOTE, Add to user_output_target - // reg.Callback([&]() { user_output_target.AddLibDep(libbuildcc); }); - // } + if (mode == BuildExeMode::Script) { + // Compile buildcc using the constructed toolchain + fs::path buildcc_home = get_env_buildcc_home(); + auto &buildcc_package = storage.Add( + "BuildccPackage", reg, toolchain, + TargetEnv(buildcc_home / "buildcc", + buildcc_home / "buildcc" / "_build_exe")); + buildcc_package.Setup(custom_toolchain_arg.state); + + // Add buildcc as a dependency to user_output_target + user_output_target.AddLibDep(buildcc_package.GetBuildcc()); + user_output_target.Insert(buildcc_package.GetBuildcc(), + { + SyncOption::PreprocessorFlags, + SyncOption::CppCompileFlags, + SyncOption::IncludeDirs, + SyncOption::LinkFlags, + SyncOption::HeaderFiles, + SyncOption::IncludeDirs, + SyncOption::LibDeps, + SyncOption::ExternalLibDeps, + }); + switch (toolchain.GetId()) { + case ToolchainId::Gcc: + case ToolchainId::MinGW: + user_output_target.AddLinkFlag("-Wl,--allow-multiple-definition"); + break; + default: + break; + } + } + reg.Build(custom_toolchain_arg.state, user_output_target_cb, user_output_target, out_targetinputs); + if (mode == BuildExeMode::Script) { + auto &buildcc_package = storage.Ref("BuildccPackage"); + reg.Dep(user_output_target, buildcc_package.GetBuildcc()); + } + // Runners reg.RunBuild(); + // Run + if (mode == BuildExeMode::Script) { + std::vector configs; + for (const auto &c : out_scriptinfo.configs) { + std::string config = fmt::format("--config {}", c); + configs.push_back(config); + } + std::string aggregated_configs = fmt::format("{}", fmt::join(configs, " ")); + + env::Command command; + std::string command_str = command.Construct( + "{executable} {configs}", + { + {"executable", + fmt::format("{}", user_output_target.GetTargetPath())}, + {"configs", aggregated_configs}, + }); + env::Command::Execute(command_str); + } + // - Clang Compile Commands plugin::ClangCompileCommands({&user_output_target}).Generate(); @@ -171,6 +276,83 @@ static void setup_arg_target_inputs(Args &args, ArgTargetInputs &out) { app.add_option("--link_flags", out.link_flags, "Provide Link Flags"); } +static void setup_arg_script_mode(Args &args, ArgScriptInfo &out) { + auto *script_args = args.Ref().add_subcommand("script"); + script_args->add_option("--configs", out.configs, + "Config files for script mode"); +} + +static void host_toolchain_verify(const BaseToolchain &toolchain) { + env::log_info(kTag, "*** Starting Toolchain verification ***"); + + fs::path file = env::get_project_build_dir() / "verify_host_toolchain" / + "verify_host_toolchain.cpp"; + fs::create_directories(file.parent_path()); + std::string file_data = R"(// Generated by BuildExe +#include +#include + +namespace fs = std::filesystem; + +int main() { + std::cout << "Verifying host toolchain" << std::endl; + std::cout << "Current Path: " << fs::current_path() << std::endl; + return 0; +})"; + env::save_file(path_as_string(file).c_str(), file_data, false); + + ExecutableTarget_generic target( + "verify", toolchain, TargetEnv(file.parent_path(), file.parent_path())); + + target.AddSource(file); + switch (toolchain.GetId()) { + case ToolchainId::Gcc: + case ToolchainId::MinGW: + target.AddCppCompileFlag("-std=c++17"); + break; + case ToolchainId::Msvc: + target.AddCppCompileFlag("/std:c++17"); + break; + default: + env::assert_fatal("Invalid Compiler Id"); + } + target.Build(); + + // Build + tf::Executor executor; + executor.run(target.GetTaskflow()); + executor.wait_for_all(); + env::assert_fatal(env::get_task_state() == env::TaskState::SUCCESS, + "Input toolchain could not compile host program. " + "Requires HOST toolchain"); + + // Run + bool execute = env::Command::Execute(fmt::format( + "{executable}", fmt::arg("executable", target.GetTargetPath().string()))); + env::assert_fatal(execute, "Could not execute verification target"); + env::log_info(kTag, "*** Toolchain verification done ***"); +} + +static fs::path get_env_buildcc_home() { + const char *buildcc_home = getenv("BUILDCC_HOME"); + env::assert_fatal(buildcc_home != nullptr, + "BUILDCC_HOME environment variable not defined"); + + // NOTE, Verify BUILDCC_HOME + // auto &buildcc_path = storage.Add("buildcc_path", buildcc_home); + fs::path buildcc_home_path{buildcc_home}; + env::assert_fatal(fs::exists(buildcc_home_path), + "{BUILDCC_HOME} path not found path not found"); + env::assert_fatal(fs::exists(buildcc_home_path / "buildcc"), + "{BUILDCC_HOME}/buildcc path not found"); + env::assert_fatal(fs::exists(buildcc_home_path / "libs"), + "{BUILDCC_HOME}/libs path not found"); + env::assert_fatal(fs::exists(buildcc_home_path / "extensions"), + "{BUILDCC_HOME}/extensions path not found"); + + return buildcc_home_path; +} + static void user_output_target_cb(BaseTarget &target, const ArgTargetInputs &inputs) { for (const auto &s : inputs.source_files) { diff --git a/buildexe/example_configs/sm_simple_linux.toml b/buildexe/example_configs/sm_simple_linux.toml new file mode 100644 index 00000000..d1993cd7 --- /dev/null +++ b/buildexe/example_configs/sm_simple_linux.toml @@ -0,0 +1,25 @@ +root_dir = "" +build_dir = "_build_buildexe_simple" + +loglevel = "debug" +clean = false + +# TODO, verification +# [verification] +# os = ["win", "linux"] + +# BuildExe run mode +# mode = "immediate" +mode = "script" + +# Target information +# [build.info] +name = "simple" +type = "executable" +relative_to_root = "" + +# [build.inputs] +srcs = ["build.cpp"] + +[script] +configs = ["build_linux.toml"] diff --git a/buildexe/example_configs/sm_simple_win.toml b/buildexe/example_configs/sm_simple_win.toml new file mode 100644 index 00000000..f76d2d04 --- /dev/null +++ b/buildexe/example_configs/sm_simple_win.toml @@ -0,0 +1,25 @@ +root_dir = "" +build_dir = "_build_buildexe_simple" + +loglevel = "debug" +clean = false + +# TODO, verification +# [verification] +# os = ["win", "linux"] + +# BuildExe run mode +# mode = "immediate" +mode = "script" + +# Target information +# [build.info] +name = "simple" +type = "executable" +relative_to_root = "" + +# [build.inputs] +srcs = ["build.cpp"] + +[script] +configs = ["build_win.toml"]