diff --git a/Dockerfile b/Dockerfile index 586aaeb06..4bca8b659 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,6 @@ COPY .git . COPY Makefile . COPY include ./include/ COPY lib ./lib/ -COPY rs-cpp ./rs-cpp/ COPY src ./src/ RUN make BUILD=release install diff --git a/Makefile b/Makefile index 756876375..cfb9e0b4d 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,9 @@ CUSTOM_CXXFLAGS := $(shell grep -m1 cxxflags cabin.toml | sed 's/cxxflags = \[// # Git dependency versions TOML11_VER := $(shell grep -m1 toml11 cabin.toml | sed 's/.*tag = \(.*\)}/\1/' | tr -d '"') -RESULT_VER := $(shell grep -m1 cpp-result rs-cpp/cabin.toml | sed 's/.*tag = \(.*\)}/\1/' | tr -d '"') +RESULT_VER := v11.0.0 -GIT_DEPS := $(O)/DEPS/toml11 $(O)/DEPS/mitama-cpp-result +GIT_DEPS := $(O)/DEPS/toml11 $(O)/DEPS/mitama-cpp-result $(O)/DEPS/rs-cpp # System dependency versions PKGS := \ @@ -44,8 +44,9 @@ DEFINES := -DCABIN_CABIN_PKG_VERSION='"$(VERSION)"' \ -DCABIN_CABIN_COMMIT_HASH='"$(COMMIT_HASH)"' \ -DCABIN_CABIN_COMMIT_SHORT_HASH='"$(COMMIT_SHORT_HASH)"' \ -DCABIN_CABIN_COMMIT_DATE='"$(COMMIT_DATE)"' -INCLUDES := -Iinclude -Isrc -Irs-cpp/include -isystem $(O)/DEPS/toml11/include \ - -isystem $(O)/DEPS/mitama-cpp-result/include +INCLUDES := -Iinclude -Isrc -isystem $(O)/DEPS/toml11/include \ + -isystem $(O)/DEPS/mitama-cpp-result/include \ + -isystem $(O)/DEPS/rs-cpp/include CXXFLAGS := -std=c++$(EDITION) -fdiagnostics-color $(CUSTOM_CXXFLAGS) \ $(DEFINES) $(INCLUDES) $(PKG_CFLAGS) -MMD -MP @@ -105,3 +106,7 @@ $(O)/DEPS/mitama-cpp-result: @mkdir -p $(@D) @$(GIT) clone https://github.com/loliGothicK/mitama-cpp-result.git $@ @$(GIT) -C $@ reset --hard $(RESULT_VER) + +$(O)/DEPS/rs-cpp: + @mkdir -p $(@D) + @$(GIT) clone https://github.com/ken-matsui/rs-cpp.git $@ diff --git a/cabin.toml b/cabin.toml index eee9f7f2c..a2ababc98 100644 --- a/cabin.toml +++ b/cabin.toml @@ -18,7 +18,7 @@ libcurl = {version = ">=7.79.1 && <9", system = true} libgit2 = {version = ">=1.7 && <1.10", system = true} nlohmann_json = {version = "3.10.5", system = true} tbb = {version = ">=2021.5.0 && <2023.0.0", system = true} -rs-cpp = {path = "./rs-cpp"} +rs-cpp = {git = "https://github.com/ken-matsui/rs-cpp.git", branch = "main"} [dev-dependencies] boost-ut = {git = "https://github.com/boost-ext/ut.git", tag = "v2.3.1"} diff --git a/include/Dependency.hpp b/include/Dependency.hpp index 10afe3175..82c4b2f6c 100644 --- a/include/Dependency.hpp +++ b/include/Dependency.hpp @@ -3,6 +3,7 @@ #include "Builder/Compiler.hpp" #include "VersionReq.hpp" +#include #include #include #include @@ -16,6 +17,7 @@ struct GitDependency { const std::string url; const std::optional target; + [[nodiscard]] std::filesystem::path installDir() const; rs::Result install() const; GitDependency(std::string name, std::string url, diff --git a/lib/Dependency.cc b/lib/Dependency.cc index d129ab3d5..d71fac3dd 100644 --- a/lib/Dependency.cc +++ b/lib/Dependency.cc @@ -25,17 +25,22 @@ static const fs::path CACHE_DIR(getXdgCacheHome() / "cabin"); static const fs::path GIT_DIR(CACHE_DIR / "git"); static const fs::path GIT_SRC_DIR(GIT_DIR / "src"); -rs::Result GitDependency::install() const { - fs::path installDir = GIT_SRC_DIR / name; +fs::path GitDependency::installDir() const { + fs::path dir = GIT_SRC_DIR / name; if (target.has_value()) { - installDir += '-' + target.value(); + dir += '-' + target.value(); } + return dir; +} - if (fs::exists(installDir) && !fs::is_empty(installDir)) { +rs::Result GitDependency::install() const { + const fs::path targetDir = installDir(); + + if (fs::exists(targetDir) && !fs::is_empty(targetDir)) { spdlog::debug("{} is already installed", name); } else { git2::Repository repo; - repo.clone(url, installDir.string()); + repo.clone(url, targetDir.string()); if (target.has_value()) { // Checkout to target. @@ -49,14 +54,14 @@ rs::Result GitDependency::install() const { target.has_value() ? target.value() : url); } - const fs::path includeDir = installDir / "include"; + const fs::path includeDir = targetDir / "include"; fs::path include; if (fs::exists(includeDir) && fs::is_directory(includeDir) && !fs::is_empty(includeDir)) { include = includeDir; } else { - include = installDir; + include = targetDir; } return rs::Ok(CompilerOpts(CFlags({}, { IncludeDir{ include } }, {}), diff --git a/lib/Manifest.cc b/lib/Manifest.cc index 16f2e4bbb..e8a7b50ca 100644 --- a/lib/Manifest.cc +++ b/lib/Manifest.cc @@ -210,7 +210,23 @@ installDependencies(const Manifest& manifest, const bool includeDevDeps, return std::visit( Overloaded{ [&](const GitDependency& gitDep) -> rs::Result { - installed.emplace_back(rs_try(gitDep.install())); + CompilerOpts depOpts = rs_try(gitDep.install()); + + const fs::path depManifestPath = + gitDep.installDir() / Manifest::FILE_NAME; + if (fs::exists(depManifestPath)) { + const Manifest depManifest = + rs_try(Manifest::tryParse(depManifestPath, false)); + + std::vector nestedDeps; + rs_try(installDependencies(depManifest, includeDevDeps, + seenDeps, visited, nestedDeps)); + for (const CompilerOpts& opts : nestedDeps) { + depOpts.merge(opts); + } + } + + installed.emplace_back(std::move(depOpts)); return rs::Ok(); }, [&](const SystemDependency& sysDep) -> rs::Result { diff --git a/rs-cpp/cabin.toml b/rs-cpp/cabin.toml deleted file mode 100644 index 809fa1977..000000000 --- a/rs-cpp/cabin.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "rs-cpp" -version = "0.1.0" -edition = "23" - -[dependencies] -fmt = {version = ">=9 && <13", system = true} -mitama-cpp-result = {git = "https://github.com/loliGothicK/mitama-cpp-result.git", tag = "v11.0.0"} diff --git a/rs-cpp/include/rs.hpp b/rs-cpp/include/rs.hpp deleted file mode 100644 index 58966ba10..000000000 --- a/rs-cpp/include/rs.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef RS_HPP -#define RS_HPP - -#include -#include - -#endif // RS_HPP diff --git a/rs-cpp/include/rs/result.hpp b/rs-cpp/include/rs/result.hpp deleted file mode 100644 index 8141a758e..000000000 --- a/rs-cpp/include/rs/result.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef RS_RESULT_HPP -#define RS_RESULT_HPP - -#include -#include -#include -#include -#include - -// NOLINTBEGIN(readability-identifier-naming,cppcoreguidelines-macro-usage) - -#define rs_try(...) MITAMA_TRY(__VA_ARGS__) -#define rs_bail(...) MITAMA_BAIL(__VA_ARGS__) -#define rs_ensure(...) MITAMA_ENSURE(__VA_ARGS__) - -namespace rs { - -using mitama::anyhow::anyhow; - -// FIXME: shared_ptr is an implementation detail. Upstream the fix. -using AnyhowErr = mitama::failure_t>; - -struct UseAnyhow {}; - -template -using Result = - std::conditional_t, mitama::anyhow::result, - mitama::result>; - -template -inline auto Ok(Args&&... args) - -> decltype(mitama::success(std::forward(args)...)) { - return mitama::success(std::forward(args)...); -} - -template - requires std::is_void_v || std::is_base_of_v -inline auto Err(Args&&... args) { - if constexpr (std::is_void_v) { - return mitama::failure(std::forward(args)...); - } else { - return mitama::anyhow::failure(std::forward(args)...); - } -} - -inline constexpr auto to_anyhow = [](auto... xs) { - return anyhow(std::forward(xs)...); -}; - -} // namespace rs - -// NOLINTEND(readability-identifier-naming,cppcoreguidelines-macro-usage) - -#endif // RS_RESULT_HPP diff --git a/rs-cpp/include/rs/tests.hpp b/rs-cpp/include/rs/tests.hpp deleted file mode 100644 index ab6fc497b..000000000 --- a/rs-cpp/include/rs/tests.hpp +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef RS_TESTS_HPP -#define RS_TESTS_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rs { - -inline constinit const std::string_view GREEN = "\033[32m"; -inline constinit const std::string_view RED = "\033[31m"; -inline constinit const std::string_view RESET = "\033[0m"; - -template -concept Eq = requires(T lhs, U rhs) { - { lhs == rhs } -> std::convertible_to; -}; - -template -concept Ne = requires(T lhs, U rhs) { - { lhs != rhs } -> std::convertible_to; -}; - -template -concept Lt = requires(T lhs, U rhs) { - { lhs < rhs } -> std::convertible_to; -}; - -std::string getModName(std::string_view file) { - return std::filesystem::relative(file).replace_extension().string(); -} - -constexpr std::string_view prettifyFuncName(std::string_view func) noexcept { - if (func.empty()) { - return func; - } - - const std::size_t end = func.find_last_of('('); - if (end == std::string_view::npos) { - return func; - } - func = func.substr(0, end); - - const std::size_t start = func.find_last_of(' '); - if (start == std::string_view::npos) { - return func; - } - return func.substr(start + 1); -} - -inline void -pass(const std::source_location& loc = std::source_location::current()) { - std::print(" test {}::{} ... {}ok{}\n", getModName(loc.file_name()), - prettifyFuncName(loc.function_name()), GREEN, RESET); -} - -[[noreturn]] inline void error(const std::source_location& loc, - const std::string_view msg) { - std::print(stderr, - "\n test {}::{} ... {}FAILED{}\n\n" - "'{}' failed at '{}', {}:{}\n", - getModName(loc.file_name()), prettifyFuncName(loc.function_name()), - RED, RESET, prettifyFuncName(loc.function_name()), msg, - loc.file_name(), loc.line()); - throw std::logic_error("test failed"); -} - -inline void -assertTrue(const bool cond, const std::string_view msg = "", - const std::source_location& loc = std::source_location::current()) { - if (cond) { - return; // OK - } - - if (msg.empty()) { - error(loc, "expected `true` but got `false`"); - } else { - error(loc, msg); - } -} - -inline void -assertFalse(const bool cond, const std::string_view msg = "", - const std::source_location& loc = std::source_location::current()) { - if (!cond) { - return; // OK - } - - if (msg.empty()) { - error(loc, "expected `false` but got `true`"); - } else { - error(loc, msg); - } -} - -template - requires Eq && fmt::is_formattable::value - && fmt::is_formattable::value -inline void -assertEq(Lhs&& lhs, Rhs&& rhs, const std::string_view msg = "", - const std::source_location& loc = std::source_location::current()) { - if (lhs == rhs) { - return; // OK - } - - if (msg.empty()) { - std::string msg; - try { - msg = fmt::format(fmt::runtime("assertion failed: `(left == right)`\n" - " left: `{:?}`\n" - " right: `{:?}`\n"), - std::forward(lhs), std::forward(rhs)); - } catch (const fmt::format_error& e) { - msg = fmt::format(fmt::runtime("assertion failed: `(left == right)`\n" - " left: `{}`\n" - " right: `{}`\n"), - std::forward(lhs), std::forward(rhs)); - } - error(loc, msg); - } else { - error(loc, msg); - } -} - -template - requires Ne && fmt::is_formattable::value - && fmt::is_formattable::value -inline void -assertNe(Lhs&& lhs, Rhs&& rhs, const std::string_view msg = "", - const std::source_location& loc = std::source_location::current()) { - if (lhs != rhs) { - return; // OK - } - - if (msg.empty()) { - std::string msg; - try { - msg = fmt::format(fmt::runtime("assertion failed: `(left != right)`\n" - " left: `{:?}`\n" - " right: `{:?}`\n"), - std::forward(lhs), std::forward(rhs)); - } catch (const fmt::format_error& e) { - msg = fmt::format(fmt::runtime("assertion failed: `(left != right)`\n" - " left: `{}`\n" - " right: `{}`\n"), - std::forward(lhs), std::forward(rhs)); - } - error(loc, msg); - } else { - error(loc, msg); - } -} - -template - requires Lt && fmt::is_formattable::value - && fmt::is_formattable::value -inline void -assertLt(Lhs&& lhs, Rhs&& rhs, const std::string_view msg = "", - const std::source_location& loc = std::source_location::current()) { - if (lhs < rhs) { - return; // OK - } - - if (msg.empty()) { - std::string msg; - try { - msg = fmt::format(fmt::runtime("assertion failed: `(left < right)`\n" - " left: `{:?}`\n" - " right: `{:?}`\n"), - std::forward(lhs), std::forward(rhs)); - } catch (const fmt::format_error& e) { - msg = fmt::format(fmt::runtime("assertion failed: `(left < right)`\n" - " left: `{}`\n" - " right: `{}`\n"), - std::forward(lhs), std::forward(rhs)); - } - error(loc, msg); - } else { - error(loc, msg); - } -} - -} // namespace rs - -#endif // RS_TESTS_HPP