diff options
author | dec05eba <dec05eba@protonmail.com> | 2017-12-09 16:36:23 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2017-12-09 16:38:31 +0100 |
commit | e7384a7672e4449bc194ca3ec66cdd4fcc63801e (patch) | |
tree | c79bc4dfbb8b3a752ae33f26f5e1b2992a484ace /backend/ninja | |
parent | 6cc190828160586abc6961354a7c05e99537d7e2 (diff) |
Add support for dependencies (including version check)
This currently only works using pkg-config and it only adds
linking flags. Need to check with a library that also includes
other types of flags.
TODO: Fallback to dependencies sub directory and github/server
if package not found in pkg-config.
Diffstat (limited to 'backend/ninja')
-rw-r--r-- | backend/ninja/Ninja.cpp | 174 | ||||
-rw-r--r-- | backend/ninja/Ninja.hpp | 8 |
2 files changed, 177 insertions, 5 deletions
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 7006d30..683fb67 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -3,6 +3,7 @@ #include "../../include/FileUtil.hpp" using namespace std; +using namespace sibs; namespace backend { @@ -35,6 +36,32 @@ namespace backend return move(result); } + struct ExecResult + { + string stdout; + int exitCode; + }; + + Result<ExecResult> exec(const char *cmd) + { + char buffer[128]; + string result; + FILE *pipe = popen(cmd, "r"); + if(!pipe) + return Result<ExecResult>::Err("popen() failed"); + + while(!feof(pipe)) + { + if(fgets(buffer, 128, pipe)) + result += buffer; + } + + ExecResult execResult; + execResult.stdout = result; + execResult.exitCode = WEXITSTATUS(pclose(pipe)); + return Result<ExecResult>::Ok(execResult); + } + void Ninja::addSourceFile(const char *filepath) { if(filepath && !containsSourceFile(filepath)) @@ -51,9 +78,134 @@ namespace backend return false; } - void Ninja::build(const std::string &packageName, const char *savePath) + Result<bool> Ninja::validatePkgConfigPackageExists(const string &name) const { - if(sourceFiles.empty()) return; + string command = "pkg-config --exists '"; + command += name; + command += "'"; + Result<ExecResult> execResult = exec(command.c_str()); + if(execResult.isErr()) + { + return Result<bool>::Err(execResult.getErrMsg()); + } + + if(execResult.unwrap().exitCode == 1) + { + string errMsg = "Dependency not found: "; + errMsg += name; + return Result<bool>::Err(errMsg); + } + else if(execResult.unwrap().exitCode == 127) + { + return Result<bool>::Err("pkg-config is not installed"); + } + else if(execResult.unwrap().exitCode != 0) + { + string errMsg = "Failed to check if dependency exists, Unknown error, exit code: "; + errMsg += to_string(execResult.unwrap().exitCode); + return Result<bool>::Err(errMsg); + } + + return Result<bool>::Ok(true); + } + + Result<bool> Ninja::validatePkgConfigPackageVersionAtLeast(const string &name, const string &version) const + { + // Use --modversion instead and check if the version returned is newer or equal to dependency version. + // This way we can output installed version vs expected dependency version + string command = "pkg-config '--atleast-version="; + command += version; + command += "' '"; + command += name; + command += "'"; + Result<ExecResult> execResult = exec(command.c_str()); + if(execResult.isErr()) + { + return Result<bool>::Err(execResult.getErrMsg()); + } + + if(execResult.unwrap().exitCode == 1) + { + string errMsg = "Dependency "; + errMsg += name; + errMsg += " is installed but the version older than "; + errMsg += version; + return Result<bool>::Err(errMsg); + } + else if(execResult.unwrap().exitCode == 127) + { + return Result<bool>::Err("pkg-config is not installed"); + } + else if(execResult.unwrap().exitCode != 0) + { + string errMsg = "Failed to check dependency version, Unknown error, exit code: "; + errMsg += to_string(execResult.unwrap().exitCode); + return Result<bool>::Err(errMsg); + } + + return Result<bool>::Ok(true); + } + + // TODO: First check if pkg-config is installed. If it's not, only check dependencies that exists in the dependencies sub directory. + // If pkg-config is installed and dependency is not installed, check in dependencies sub directory. + Result<string> Ninja::getLinkerFlags(const vector<Dependency> &dependencies) const + { + if(dependencies.empty()) return Result<string>::Ok(""); + + for(const sibs::Dependency &dependency : dependencies) + { + Result<bool> dependencyValidationResult = validatePkgConfigPackageExists(dependency.name); + if(dependencyValidationResult.isErr()) + return Result<string>::Err(dependencyValidationResult.getErrMsg()); + + Result<bool> dependencyVersionValidationResult = validatePkgConfigPackageVersionAtLeast(dependency.name, dependency.version); + if(dependencyVersionValidationResult.isErr()) + return Result<string>::Err(dependencyVersionValidationResult.getErrMsg()); + } + + string args; + for(const sibs::Dependency &dependency : dependencies) + { + args += " '"; + args += dependency.name; + args += "'"; + } + + string command = "pkg-config --libs"; + command += args; + Result<ExecResult> execResult = exec(command.c_str()); + if(execResult.isErr()) + return Result<string>::Err(execResult.getErrMsg()); + + if(execResult.unwrap().exitCode == 0) + { + return Result<string>::Ok(execResult.unwrap().stdout); + } + else if(execResult.unwrap().exitCode == 1) + { + // TODO: This shouldn't happen because we check if each dependency is installed before this, + // but maybe the package is uninstalled somewhere between here... + // Would be better to recheck if each package is installed here again + // to know which package was uninstalled + return Result<string>::Err("Dependencies not found"); + } + else if(execResult.unwrap().exitCode == 127) + { + return Result<string>::Err("pkg-config is not installed"); + } + else + { + string errMsg = "Failed to get dependencies linking flags, Unknown error, exit code: "; + errMsg += to_string(execResult.unwrap().exitCode); + return Result<string>::Err(errMsg); + } + } + + Result<bool> Ninja::createBuildFile(const std::string &packageName, const vector<Dependency> &dependencies, const char *savePath) + { + if(sourceFiles.empty()) + return Result<bool>::Err("No source files provided"); + printf("Package name: %s\n", packageName.c_str()); string result; @@ -82,14 +234,28 @@ namespace backend objectNames.emplace_back(objectName); } + Result<string> linkerFlags = getLinkerFlags(dependencies); + if(linkerFlags.isErr()) + return Result<bool>::Err(linkerFlags.getErrMsg()); + result += "build "; result += packageName; result += ": cpp_LINKER "; result += join(objectNames, " "); result += "\n"; - result += " LINK_ARGS = '-Wl,--no-undefined' '-Wl,--as-needed'\n\n"; + result += " LINK_ARGS = '-Wl,--no-undefined' '-Wl,--as-needed' "; + result += linkerFlags.unwrap(); + result += "\n\n"; + + bool fileOverwritten = sibs::fileOverwrite(savePath, sibs::StringView(result.data(), result.size())); + if(!fileOverwritten) + { + string errMsg = "Failed to overwrite ninja build file: "; + errMsg += savePath; + return Result<bool>::Err(errMsg); + } - sibs::fileOverwrite(savePath, sibs::StringView(result.data(), result.size())); printf("Created ninja build file: %s\n", savePath); + return Result<bool>::Ok(true); } }
\ No newline at end of file diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index ad71c80..1ba20c7 100644 --- a/backend/ninja/Ninja.hpp +++ b/backend/ninja/Ninja.hpp @@ -1,18 +1,24 @@ #ifndef BACKEND_NINJA_HPP #define BACKEND_NINJA_HPP +#include "../../include/Dependency.hpp" +#include "../../include/Result.hpp" #include <vector> #include <string> + namespace backend { class Ninja { public: void addSourceFile(const char *filepath); - void build(const std::string &packageName, const char *savePath); + sibs::Result<bool> createBuildFile(const std::string &packageName, const std::vector<sibs::Dependency> &dependencies, const char *savePath); private: bool containsSourceFile(const char *filepath) const; + sibs::Result<std::string> getLinkerFlags(const std::vector<sibs::Dependency> &dependencies) const; + sibs::Result<bool> validatePkgConfigPackageExists(const std::string &name) const; + sibs::Result<bool> validatePkgConfigPackageVersionAtLeast(const std::string &name, const std::string &version) const; private: std::vector<std::string> sourceFiles; }; |