From 1d3e221a7a20bfd03517e3ae1e35e4a309a69b6a Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 10 Dec 2017 01:10:48 +0100 Subject: Add support for dependencies in global lib dir Global lib dir is located at ~/.sibs/lib TODO: If global lib dir doesn't exist, download it from github/server --- backend/ninja/Ninja.cpp | 208 +++++++++++++++++------------------------------- backend/ninja/Ninja.hpp | 12 ++- 2 files changed, 81 insertions(+), 139 deletions(-) (limited to 'backend') diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 73a6dc3..3df4e41 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -1,6 +1,9 @@ #include #include "Ninja.hpp" #include "../../include/FileUtil.hpp" +#include "../../include/Exec.hpp" +#include "../../include/PkgConfig.hpp" +#include "../../include/GlobalLib.hpp" using namespace std; using namespace sibs; @@ -36,34 +39,10 @@ namespace backend return move(result); } - struct ExecResult + Ninja::Ninja(LibraryType _libraryType) : + libraryType(_libraryType) { - string stdout; - int exitCode; - }; - Result exec(const char *cmd, bool print = false) - { - char buffer[128]; - string result; - FILE *pipe = popen(cmd, "r"); - if(!pipe) - return Result::Err("popen() failed"); - - while(!feof(pipe)) - { - if(fgets(buffer, 128, pipe)) - { - result += buffer; - if(print) - printf("%s", buffer); - } - } - - ExecResult execResult; - execResult.stdout = result; - execResult.exitCode = WEXITSTATUS(pclose(pipe)); - return Result::Ok(execResult); } void Ninja::addSourceFile(const char *filepath) @@ -82,70 +61,15 @@ namespace backend return false; } - Result Ninja::validatePkgConfigPackageExists(const string &name) const + Result validatePkgConfigPackageVersionExists(const Dependency &dependency) { - string command = "pkg-config --exists '"; - command += name; - command += "'"; - Result execResult = exec(command.c_str()); - if(execResult.isErr()) - { - return Result::Err(execResult.getErrMsg()); - } + Result dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name); + if(dependencyValidationResult.isErr()) + return Result::Err(dependencyValidationResult.getErrMsg()); - if(execResult.unwrap().exitCode == 1) - { - string errMsg = "Dependency not found: "; - errMsg += name; - return Result::Err(errMsg); - } - else if(execResult.unwrap().exitCode == 127) - { - return Result::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::Err(errMsg); - } - - return Result::Ok(true); - } - - Result 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 = exec(command.c_str()); - if(execResult.isErr()) - { - return Result::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::Err(errMsg); - } - else if(execResult.unwrap().exitCode == 127) - { - return Result::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::Err(errMsg); - } + Result dependencyVersionValidationResult = PkgConfig::validatePackageVersionAtLeast(dependency.name, dependency.version); + if(dependencyVersionValidationResult.isErr()) + return Result::Err(dependencyVersionValidationResult.getErrMsg()); return Result::Ok(true); } @@ -156,53 +80,39 @@ namespace backend { if(dependencies.empty()) return Result::Ok(""); - for(const sibs::Dependency &dependency : dependencies) - { - Result dependencyValidationResult = validatePkgConfigPackageExists(dependency.name); - if(dependencyValidationResult.isErr()) - return Result::Err(dependencyValidationResult.getErrMsg()); - - Result dependencyVersionValidationResult = validatePkgConfigPackageVersionAtLeast(dependency.name, dependency.version); - if(dependencyVersionValidationResult.isErr()) - return Result::Err(dependencyVersionValidationResult.getErrMsg()); - } + // TODO: Global library dir should be created during sibs installation + string globalLibDir = getHomeDir(); + globalLibDir += "/.sibs/lib"; - string args; + string globalLibLinkerFlags; + vector pkgConfigDependencies; for(const sibs::Dependency &dependency : dependencies) { - args += " '"; - args += dependency.name; - args += "'"; + Result pkgConfigDependencyValidation = validatePkgConfigPackageVersionExists(dependency); + if(pkgConfigDependencyValidation.isOk()) + { + pkgConfigDependencies.push_back(dependency.name); + } + else + { + printf("%s, trying global lib\n", pkgConfigDependencyValidation.getErrMsg().c_str()); + Result globalLibLinkerFlagsResult = GlobalLib::getDynamicLibsLinkerFlags(globalLibDir, dependency.name, dependency.version); + if(globalLibLinkerFlagsResult.isErr()) + return globalLibLinkerFlagsResult; + + globalLibLinkerFlags += " "; + globalLibLinkerFlags += globalLibLinkerFlagsResult.unwrap(); + // TODO: If package doesn't exist, download it from github/server + } } - string command = "pkg-config --libs"; - command += args; - Result execResult = exec(command.c_str()); - if(execResult.isErr()) - return Result::Err(execResult.getErrMsg()); + Result pkgConfigLinkerFlagsResult = PkgConfig::getDynamicLibsLinkerFlags(pkgConfigDependencies); + if(pkgConfigLinkerFlagsResult.isErr()) + return pkgConfigLinkerFlagsResult; - if(execResult.unwrap().exitCode == 0) - { - return Result::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::Err("Dependencies not found"); - } - else if(execResult.unwrap().exitCode == 127) - { - return Result::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::Err(errMsg); - } + string allLinkerFlags = pkgConfigLinkerFlagsResult.unwrap(); + allLinkerFlags += globalLibLinkerFlags; + return Result::Ok(allLinkerFlags); } Result Ninja::createBuildFile(const std::string &packageName, const vector &dependencies, const char *savePath) @@ -210,7 +120,8 @@ namespace backend if(sourceFiles.empty()) return Result::Err("No source files provided"); - printf("Package name: %s\n", packageName.c_str()); + string ninjaBuildFilePath = savePath; + ninjaBuildFilePath += "/build.ninja"; string result; result.reserve(16384); @@ -220,8 +131,30 @@ namespace backend result += "rule cpp_COMPILER\n"; result += " command = ccache c++ $ARGS -c $in -o $out\n\n"; - result += "rule cpp_LINKER\n"; - result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n"; + string linkerJob; + switch(libraryType) + { + case LibraryType::EXECUTABLE: + { + result += "rule cpp_EXEC_LINKER\n"; + result += " command = ccache c++ $ARGS -o $out $in $LINK_ARGS $aliasing\n\n"; + linkerJob = "cpp_EXEC_LINKER"; + break; + } + case LibraryType::STATIC: + { + result += "rule cpp_STATIC_LINKER\n"; + result += " command = ar rcs lib"; + result += packageName; + result += ".a"; + result += " $in\n\n"; + linkerJob = "cpp_STATIC_LINKER"; + break; + } + default: + assert(false); + return Result::Err("NOT IMPLEMENTED YET!"); + } vector objectNames; for(const string &sourceFile : sourceFiles) @@ -234,7 +167,8 @@ namespace backend result += ": cpp_COMPILER ../../"; result += sourceFile; result += "\n"; - result += " ARGS = '-I" + packageName + "@exe' '-I.' '-I..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-O0' '-g'\n\n"; + // TODO: Create .deps directory if it doesn't exist. Should be a symlink to homedir/.sibs/lib + result += " ARGS = '-I../../.deps' '-I" + packageName + "@exe' '-I.' '-I..' '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-O0' '-g'\n\n"; objectNames.emplace_back(objectName); } @@ -244,22 +178,22 @@ namespace backend result += "build "; result += packageName; - result += ": cpp_LINKER "; + result += ": " + linkerJob + " "; result += join(objectNames, " "); result += "\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())); + bool fileOverwritten = sibs::fileOverwrite(ninjaBuildFilePath.c_str(), sibs::StringView(result.data(), result.size())); if(!fileOverwritten) { string errMsg = "Failed to overwrite ninja build file: "; - errMsg += savePath; + errMsg += ninjaBuildFilePath; return Result::Err(errMsg); } - printf("Created ninja build file: %s\n", savePath); + printf("Created ninja build file: %s\n", ninjaBuildFilePath.c_str()); return Result::Ok(true); } diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp index fdaa890..9ca6ace 100644 --- a/backend/ninja/Ninja.hpp +++ b/backend/ninja/Ninja.hpp @@ -12,16 +12,24 @@ namespace backend class Ninja { public: + enum class LibraryType + { + EXECUTABLE, + DYNAMIC, + STATIC + }; + + Ninja(LibraryType libraryType = LibraryType::EXECUTABLE); + void addSourceFile(const char *filepath); sibs::Result createBuildFile(const std::string &packageName, const std::vector &dependencies, const char *savePath); sibs::Result build(const char *buildFilePath); private: bool containsSourceFile(const char *filepath) const; sibs::Result getLinkerFlags(const std::vector &dependencies) const; - sibs::Result validatePkgConfigPackageExists(const std::string &name) const; - sibs::Result validatePkgConfigPackageVersionAtLeast(const std::string &name, const std::string &version) const; private: std::vector sourceFiles; + LibraryType libraryType; }; } -- cgit v1.2.3