diff --git a/docs/usage.md b/docs/usage.md index 9303c1ddf..1a3449221 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -50,7 +50,9 @@ Poac uses a cache since we executed the command with no changes. ## Install dependencies -Like Cargo does, Poac installs dependencies at build time. Poac currently supports Git and system dependencies. You can use the `poac add` command to add dependencies to your project. +Like Cargo does, Poac installs dependencies at build time. Poac currently supports Git, path, and system dependencies. You can use two ways to add dependencies to your project: using the `poac add` command and editing `poac.toml` directly. + +### `poac add` The `poac add` command accepts the following arguments: @@ -69,6 +71,23 @@ poac add libgit2 --sys --version "1.1.0" poac add "ToruNiina/toml11" --rev "846abd9a49082fe51440aa07005c360f13a67bbf" ``` +### Editing `poac.toml` directly + +The syntax for `poac.toml` is as follows: + +```toml +[dependencies] + +# git dependency +"ToruNiina/toml11" = { git = "https://github.com/ToruNiina/toml11.git", rev = "846abd9a49082fe51440aa07005c360f13a67bbf" } + +# path dependency +local_lib = { path = "../local_lib" } + +# system dependency +fmt = { version = ">= 9", system = true } +``` + If `tag`, `branch`, or `rev` is unspecified for git dependencies, Poac will use the latest revision of the default branch. System dependency names must be acceptable by `pkg-config`. The version requirement syntax is specified in [src/VersionReq.hpp](https://github.com/poac-dev/poac/blob/main/src/VersionReq.hpp). After adding dependencies, executing the `build` command will install the package and its dependencies. diff --git a/src/Manifest.cc b/src/Manifest.cc index 400031b73..f2fd5c20b 100644 --- a/src/Manifest.cc +++ b/src/Manifest.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -126,6 +127,13 @@ struct GitDependency { DepMetadata install() const; }; +struct PathDependency { + std::string name; + std::string path; + + DepMetadata install() const; +}; + struct SystemDependency { std::string name; VersionReq versionReq; @@ -133,6 +141,9 @@ struct SystemDependency { DepMetadata install() const; }; +using Dependency = + std::variant; + void Profile::merge(const Profile& other) { cxxflags.insert(other.cxxflags.begin(), other.cxxflags.end()); @@ -166,10 +177,8 @@ struct Manifest { std::optional data = std::nullopt; std::optional package = std::nullopt; - std::optional>> - dependencies = std::nullopt; - std::optional>> - devDependencies = std::nullopt; + std::optional> dependencies = std::nullopt; + std::optional> devDependencies = std::nullopt; std::optional profile = std::nullopt; std::optional devProfile = std::nullopt; @@ -536,6 +545,16 @@ parseGitDep(const std::string& name, const toml::table& info) { return { .name = name, .url = gitUrlStr, .target = target }; } +static PathDependency +parsePathDep(const std::string& name, const toml::table& info) { + validateDepName(name); + const auto& path = info.at("path"); + if (!path.is_string()) { + throw PoacError("path dependency must be a string"); + } + return { .name = name, .path = path.as_string() }; +} + static SystemDependency parseSystemDep(const std::string& name, const toml::table& info) { validateDepName(name); @@ -548,7 +567,7 @@ parseSystemDep(const std::string& name, const toml::table& info) { return { .name = name, .versionReq = VersionReq::parse(versionReq) }; } -static std::optional>> +static std::optional> parseDependencies(const char* key) { Manifest& manifest = Manifest::instance(); const auto& table = toml::get(manifest.data.value()); @@ -558,7 +577,7 @@ parseDependencies(const char* key) { } const auto tomlDeps = toml::find(manifest.data.value(), key); - std::vector> deps; + std::vector deps; for (const auto& dep : tomlDeps) { if (dep.second.is_table()) { const auto& info = dep.second.as_table(); @@ -568,11 +587,15 @@ parseDependencies(const char* key) { } else if (info.contains("system") && info.at("system").as_boolean()) { deps.emplace_back(parseSystemDep(dep.first, info)); continue; + } else if (info.contains("path")) { + deps.emplace_back(parsePathDep(dep.first, info)); + continue; } } throw PoacError( - "Only Git dependency and system dependency are supported for now: ", + "Only Git dependency, path dependency, and system dependency are " + "supported for now: ", dep.first ); } @@ -619,6 +642,29 @@ GitDependency::install() const { return { .includes = includes, .libs = "" }; } +DepMetadata +PathDependency::install() const { + const fs::path installDir = fs::weakly_canonical(path); + if (fs::exists(installDir) && !fs::is_empty(installDir)) { + logger::debug("{} is already installed", name); + } else { + throw PoacError(installDir.string() + " can't be accessible as directory"); + } + + const fs::path includeDir = installDir / "include"; + std::string includes = "-isystem"; + + if (fs::exists(includeDir) && fs::is_directory(includeDir) + && !fs::is_empty(includeDir)) { + includes += includeDir.string(); + } else { + includes += installDir.string(); + } + + // Currently, no libs are supported. + return { .includes = includes, .libs = "" }; +} + DepMetadata SystemDependency::install() const { const std::string pkgConfigVer = versionReq.toPkgConfigString(name);