aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--backend/ninja/Ninja.cpp208
-rw-r--r--backend/ninja/Ninja.hpp12
-rw-r--r--include/Conf.hpp31
-rw-r--r--include/Exec.hpp18
-rw-r--r--include/FileUtil.hpp3
-rw-r--r--include/GlobalLib.hpp16
-rw-r--r--include/PkgConfig.hpp19
-rw-r--r--include/Result.hpp2
-rw-r--r--include/env.hpp12
-rw-r--r--project.conf4
-rw-r--r--src/Conf.cpp50
-rw-r--r--src/Exec.cpp28
-rw-r--r--src/FileUtil.cpp56
-rw-r--r--src/GlobalLib.cpp143
-rw-r--r--src/PkgConfig.cpp131
-rw-r--r--src/main.cpp101
17 files changed, 607 insertions, 229 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 784e6da..96c4185 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,6 @@ set(SOURCE_FILES
src/main.cpp
src/FileUtil.cpp
src/Conf.cpp
- external/xxhash.c backend/ninja/Ninja.cpp)
+ external/xxhash.c backend/ninja/Ninja.cpp src/PkgConfig.cpp src/Exec.cpp src/GlobalLib.cpp)
add_executable(sibs ${SOURCE_FILES}) \ No newline at end of file
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 <cstring>
#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<ExecResult> exec(const char *cmd, bool print = false)
- {
- 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;
- if(print)
- printf("%s", buffer);
- }
- }
-
- ExecResult execResult;
- execResult.stdout = result;
- execResult.exitCode = WEXITSTATUS(pclose(pipe));
- return Result<ExecResult>::Ok(execResult);
}
void Ninja::addSourceFile(const char *filepath)
@@ -82,70 +61,15 @@ namespace backend
return false;
}
- Result<bool> Ninja::validatePkgConfigPackageExists(const string &name) const
+ Result<bool> validatePkgConfigPackageVersionExists(const Dependency &dependency)
{
- string command = "pkg-config --exists '";
- command += name;
- command += "'";
- Result<ExecResult> execResult = exec(command.c_str());
- if(execResult.isErr())
- {
- return Result<bool>::Err(execResult.getErrMsg());
- }
+ Result<bool> dependencyValidationResult = PkgConfig::validatePackageExists(dependency.name);
+ if(dependencyValidationResult.isErr())
+ return Result<bool>::Err(dependencyValidationResult.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);
- }
+ Result<bool> dependencyVersionValidationResult = PkgConfig::validatePackageVersionAtLeast(dependency.name, dependency.version);
+ if(dependencyVersionValidationResult.isErr())
+ return Result<bool>::Err(dependencyVersionValidationResult.getErrMsg());
return Result<bool>::Ok(true);
}
@@ -156,53 +80,39 @@ namespace backend
{
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());
- }
+ // TODO: Global library dir should be created during sibs installation
+ string globalLibDir = getHomeDir();
+ globalLibDir += "/.sibs/lib";
- string args;
+ string globalLibLinkerFlags;
+ vector<string> pkgConfigDependencies;
for(const sibs::Dependency &dependency : dependencies)
{
- args += " '";
- args += dependency.name;
- args += "'";
+ Result<bool> pkgConfigDependencyValidation = validatePkgConfigPackageVersionExists(dependency);
+ if(pkgConfigDependencyValidation.isOk())
+ {
+ pkgConfigDependencies.push_back(dependency.name);
+ }
+ else
+ {
+ printf("%s, trying global lib\n", pkgConfigDependencyValidation.getErrMsg().c_str());
+ Result<string> 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> execResult = exec(command.c_str());
- if(execResult.isErr())
- return Result<string>::Err(execResult.getErrMsg());
+ Result<string> pkgConfigLinkerFlagsResult = PkgConfig::getDynamicLibsLinkerFlags(pkgConfigDependencies);
+ if(pkgConfigLinkerFlagsResult.isErr())
+ return pkgConfigLinkerFlagsResult;
- 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);
- }
+ string allLinkerFlags = pkgConfigLinkerFlagsResult.unwrap();
+ allLinkerFlags += globalLibLinkerFlags;
+ return Result<string>::Ok(allLinkerFlags);
}
Result<bool> Ninja::createBuildFile(const std::string &packageName, const vector<Dependency> &dependencies, const char *savePath)
@@ -210,7 +120,8 @@ namespace backend
if(sourceFiles.empty())
return Result<bool>::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<bool>::Err("NOT IMPLEMENTED YET!");
+ }
vector<string> 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<bool>::Err(errMsg);
}
- printf("Created ninja build file: %s\n", savePath);
+ printf("Created ninja build file: %s\n", ninjaBuildFilePath.c_str());
return Result<bool>::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<bool> createBuildFile(const std::string &packageName, const std::vector<sibs::Dependency> &dependencies, const char *savePath);
sibs::Result<bool> build(const char *buildFilePath);
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;
+ LibraryType libraryType;
};
}
diff --git a/include/Conf.hpp b/include/Conf.hpp
index 8b98189..3634f4c 100644
--- a/include/Conf.hpp
+++ b/include/Conf.hpp
@@ -4,6 +4,7 @@
#include "Result.hpp"
#include "StringView.hpp"
#include "utils.hpp"
+#include "Dependency.hpp"
#include <vector>
#include <cassert>
#include <stdexcept>
@@ -79,6 +80,36 @@ namespace sibs
public:
static Result<bool> readFromFile(const char *filepath, const ConfigCallback &callback);
};
+
+ class SibsConfig : public ConfigCallback
+ {
+ public:
+ SibsConfig() : finishedProcessing(false) {}
+
+ const std::string& getPackageName() const
+ {
+ assert(finishedProcessing);
+ return packageName;
+ }
+
+ const std::vector<Dependency>& getDependencies() const
+ {
+ return dependencies;
+ }
+ protected:
+ void processObject(StringView name) override;
+ void processField(StringView name, const ConfigValue &value) override;
+
+ void finished() override
+ {
+ finishedProcessing = true;
+ }
+ private:
+ StringView currentObject;
+ std::string packageName;
+ std::vector<Dependency> dependencies;
+ bool finishedProcessing;
+ };
}
#endif //SIBS_CONF_HPP
diff --git a/include/Exec.hpp b/include/Exec.hpp
new file mode 100644
index 0000000..42b6905
--- /dev/null
+++ b/include/Exec.hpp
@@ -0,0 +1,18 @@
+#ifndef SIBS_EXEC_HPP
+#define SIBS_EXEC_HPP
+
+#include "Result.hpp"
+#include <string>
+
+namespace sibs
+{
+ struct ExecResult
+ {
+ std::string execStdout;
+ int exitCode;
+ };
+
+ Result<ExecResult> exec(const char *cmd, bool print = false);
+}
+
+#endif //SIBS_EXEC_HPP
diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp
index 4083cb1..5a0bbc3 100644
--- a/include/FileUtil.hpp
+++ b/include/FileUtil.hpp
@@ -18,9 +18,12 @@ namespace sibs
};
FileType getFileType(const char *path);
+ void walkDir(const char *directory, FileWalkCallbackFunc callbackFunc);
void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc);
+ void walkDirFilesRecursive(const char *directory, FileWalkCallbackFunc callbackFunc);
Result<StringView> getFileContent(const char *filepath);
bool fileOverwrite(const char *filepath, StringView data);
+ const char* getHomeDir();
}
#endif //SIBS_FILEUTIL_HPP
diff --git a/include/GlobalLib.hpp b/include/GlobalLib.hpp
new file mode 100644
index 0000000..e5a9374
--- /dev/null
+++ b/include/GlobalLib.hpp
@@ -0,0 +1,16 @@
+#ifndef SIBS_GLOBALLIB_HPP
+#define SIBS_GLOBALLIB_HPP
+
+#include "Result.hpp"
+
+namespace sibs
+{
+ class GlobalLib
+ {
+ public:
+ static Result<bool> validatePackageExists(const std::string &globalLibRootDir, const std::string &name);
+ static Result<std::string> getDynamicLibsLinkerFlags(const std::string &globalLibRootDir, const std::string &name, const std::string &version);
+ };
+}
+
+#endif //SIBS_GLOBALLIB_HPP
diff --git a/include/PkgConfig.hpp b/include/PkgConfig.hpp
new file mode 100644
index 0000000..4bafa18
--- /dev/null
+++ b/include/PkgConfig.hpp
@@ -0,0 +1,19 @@
+#ifndef SIBS_PKGCONFIG_HPP
+#define SIBS_PKGCONFIG_HPP
+
+#include "Result.hpp"
+#include <string>
+#include <vector>
+
+namespace sibs
+{
+ class PkgConfig
+ {
+ public:
+ static Result<bool> validatePackageExists(const std::string &name);
+ static Result<bool> validatePackageVersionAtLeast(const std::string &name, const std::string &version);
+ static Result<std::string> getDynamicLibsLinkerFlags(const std::vector<std::string> &libs);
+ };
+}
+
+#endif //SIBS_PKGCONFIG_HPP
diff --git a/include/Result.hpp b/include/Result.hpp
index 3ee60e5..f755b15 100644
--- a/include/Result.hpp
+++ b/include/Result.hpp
@@ -28,7 +28,7 @@ namespace sibs
bool isOk() const { return !error; }
bool isErr() const { return error; }
- const T& unwrap() const
+ T& unwrap()
{
assert(isOk());
return value;
diff --git a/include/env.hpp b/include/env.hpp
index 5d0a163..325db6e 100644
--- a/include/env.hpp
+++ b/include/env.hpp
@@ -1,12 +1,20 @@
#ifndef SIBS_ENV_HPP
#define SIBS_ENV_HPP
+#define OS_FAMILY_WINDOWS 0
+#define OS_FAMILY_POSIX 1
+
#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN64)
#define CISB_ENV_64BIT
#else
#define CISB_ENV_32BIT
#endif
+ #define OS_FAMILY OS_FAMILY_WINDOWS
+#endif
+
+#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(_POSIX_VERSION)
+ #define OS_FAMILY OS_FAMILY_POSIX
#endif
#if defined(__GNUC__)
@@ -21,4 +29,8 @@
#error "System is not detected as either 32-bit or 64-bit"
#endif
+#if !defined(OS_FAMILY)
+ #error "System not support. Only Windows and Posix systems support"
+#endif
+
#endif // SIBS_ENV_HPP
diff --git a/project.conf b/project.conf
index 0f65e5c..96bb9b9 100644
--- a/project.conf
+++ b/project.conf
@@ -3,4 +3,6 @@ name = "sibs"
version = "0.1.0"
authors = ["Aleksi Lindeman <aleksi_888@hotmail.com>"]
-[dependencies] \ No newline at end of file
+[dependencies]
+sfml-all = "2.4"
+xxhash = "0.1.0" \ No newline at end of file
diff --git a/src/Conf.cpp b/src/Conf.cpp
index 6383c30..dc1bbd0 100644
--- a/src/Conf.cpp
+++ b/src/Conf.cpp
@@ -331,4 +331,54 @@ namespace sibs
return Parser::parse(code, callback);
}
+
+ void SibsConfig::processObject(StringView name)
+ {
+ currentObject = name;
+ printf("Process object: %.*s\n", name.size, name.data);
+ }
+
+ void SibsConfig::processField(StringView name, const ConfigValue &value)
+ {
+ printf("Process field: %.*s, value: ", name.size, name.data);
+ if(value.isSingle())
+ {
+ printf("\"%.*s\"", value.asSingle().size, value.asSingle().data);
+ }
+ else
+ {
+ printf("[");
+ int i = 0;
+ for(auto listElement : value.asList())
+ {
+ if(i > 0)
+ printf(", ");
+ printf("\"%.*s\"", listElement.size, listElement.data);
+ ++i;
+ }
+ printf("]");
+ }
+ printf("\n");
+
+ if(currentObject.equals("package") && name.equals("name"))
+ {
+ if(value.isSingle())
+ packageName = string(value.asSingle().data, value.asSingle().size);
+ else
+ throw ParserException("Expected package.name to be a single value, was a list");
+ }
+ else if(currentObject.equals("dependencies"))
+ {
+ if(value.isSingle())
+ {
+ // TODO: Validate version is number in correct format
+ Dependency dependency;
+ dependency.name = string(name.data, name.size);
+ dependency.version = string(value.asSingle().data, value.asSingle().size);
+ dependencies.emplace_back(dependency);
+ }
+ else
+ throw ParserException("Expected field under dependencies to be a single value, was a list");
+ }
+ }
} \ No newline at end of file
diff --git a/src/Exec.cpp b/src/Exec.cpp
new file mode 100644
index 0000000..b245fd4
--- /dev/null
+++ b/src/Exec.cpp
@@ -0,0 +1,28 @@
+#include "../include/Exec.hpp"
+
+namespace sibs
+{
+ Result<ExecResult> exec(const char *cmd, bool print)
+ {
+ char buffer[128];
+ std::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;
+ if(print)
+ printf("%s", buffer);
+ }
+ }
+
+ ExecResult execResult;
+ execResult.execStdout = result;
+ execResult.exitCode = WEXITSTATUS(pclose(pipe));
+ return Result<ExecResult>::Ok(execResult);
+ }
+} \ No newline at end of file
diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp
index 59132dc..400b439 100644
--- a/src/FileUtil.cpp
+++ b/src/FileUtil.cpp
@@ -1,6 +1,13 @@
#include "../include/FileUtil.hpp"
+#include "../include/env.hpp"
#include <cstdio>
+#if OS_FAMILY == OS_FAMILY_POSIX
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#endif
+
using namespace std;
namespace sibs
@@ -19,6 +26,24 @@ namespace sibs
}
// TODO: Handle failure (directory doesn't exist, no permission etc)
+ void walkDir(const char *directory, FileWalkCallbackFunc callbackFunc)
+ {
+ tinydir_dir dir;
+ tinydir_open(&dir, directory);
+
+ while (dir.has_next)
+ {
+ tinydir_file file;
+ tinydir_readfile(&dir, &file);
+ if(_tinydir_strcmp(file.name, ".") != 0 && _tinydir_strcmp(file.name, "..") != 0)
+ callbackFunc(&file);
+ tinydir_next(&dir);
+ }
+
+ tinydir_close(&dir);
+ }
+
+ // TODO: Handle failure (directory doesn't exist, no permission etc)
void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc)
{
tinydir_dir dir;
@@ -30,8 +55,26 @@ namespace sibs
tinydir_readfile(&dir, &file);
if(file.is_reg)
callbackFunc(&file);
+ tinydir_next(&dir);
+ }
+
+ tinydir_close(&dir);
+ }
+
+ // TODO: Handle failure (directory doesn't exist, no permission etc)
+ void walkDirFilesRecursive(const char *directory, FileWalkCallbackFunc callbackFunc)
+ {
+ tinydir_dir dir;
+ tinydir_open(&dir, directory);
+
+ while (dir.has_next)
+ {
+ tinydir_file file;
+ tinydir_readfile(&dir, &file);
+ if(file.is_reg)
+ callbackFunc(&file);
else if(_tinydir_strcmp(file.name, ".") != 0 && _tinydir_strcmp(file.name, "..") != 0)
- walkDirFiles(file.path, callbackFunc);
+ walkDirFilesRecursive(file.path, callbackFunc);
tinydir_next(&dir);
}
@@ -77,4 +120,15 @@ namespace sibs
fclose(file);
return true;
}
+
+ const char* getHomeDir()
+ {
+ const char *homeDir = getenv("HOME");
+ if(!homeDir)
+ {
+ passwd *pw = getpwuid(getuid());
+ homeDir = pw->pw_dir;
+ }
+ return homeDir;
+ }
} \ No newline at end of file
diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp
new file mode 100644
index 0000000..0ed34c7
--- /dev/null
+++ b/src/GlobalLib.cpp
@@ -0,0 +1,143 @@
+#include "../include/GlobalLib.hpp"
+#include "../include/FileUtil.hpp"
+#include "../backend/ninja/Ninja.hpp"
+#include "../include/Conf.hpp"
+
+using namespace std;
+
+namespace sibs
+{
+ Result<bool> GlobalLib::validatePackageExists(const string &globalLibRootDir, const string &name)
+ {
+ string packageDir = globalLibRootDir + "/";
+ packageDir += name;
+ FileType packageDirFileType = getFileType(packageDir.c_str());
+ switch(packageDirFileType)
+ {
+ case FileType::FILE_NOT_FOUND:
+ {
+ string errMsg = "Global lib dependency not found: ";
+ errMsg += name;
+ return Result<bool>::Err(errMsg);
+ }
+ case FileType::REGULAR:
+ {
+ string errMsg = "Corrupt library directory. ";
+ errMsg += packageDir;
+ errMsg += " is a file, expected it to be a directory";
+ return Result<bool>::Err(errMsg);
+ }
+ case FileType::DIRECTORY:
+ {
+ return Result<bool>::Ok(true);
+ }
+ default:
+ {
+ return Result<bool>::Err("Unexpected error!");
+ }
+ }
+ }
+
+ const char *sourceFileExtensions[] = { "c", "cc", "cpp", "cxx" };
+ bool isSourceFile(tinydir_file *file)
+ {
+ if(!file->is_reg)
+ return false;
+
+ for(const char *sourceFileExtension : sourceFileExtensions)
+ {
+ if(_tinydir_strcmp(sourceFileExtension, file->extension) == 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ Result<string> GlobalLib::getDynamicLibsLinkerFlags(const string &globalLibRootDir, const string &name, const string &version)
+ {
+ Result<bool> packageExistsResult = validatePackageExists(globalLibRootDir, name);
+ if(packageExistsResult.isErr())
+ return Result<string>::Err(packageExistsResult.getErrMsg());
+
+ string packageDir = globalLibRootDir + "/";
+ packageDir += name;
+
+ // TODO: Instead of checking if version is exact match, check if package has same major version
+ // and same or newer minor version
+ string foundVersion;
+ walkDir(packageDir.c_str(), [&foundVersion, &version](tinydir_file *file)
+ {
+ if(file->is_dir)
+ {
+ printf("version: %s\n", file->name);
+ if(_tinydir_strcmp(version.c_str(), file->name) == 0)
+ foundVersion = file->name;
+ }
+ });
+
+ if(foundVersion.empty())
+ return Result<string>::Err("Global lib dependency found, but version doesn't match dependency version");
+
+ packageDir += "/";
+ packageDir += version;
+
+ string projectConfFilePath = packageDir;
+ projectConfFilePath += "/project.conf";
+
+ FileType projectConfFileType = getFileType(projectConfFilePath.c_str());
+ switch(projectConfFileType)
+ {
+ case FileType::FILE_NOT_FOUND:
+ {
+ string errMsg = "Global lib dependency found: ";
+ errMsg += packageDir;
+ errMsg += ", but it's missing a project.conf file";
+ return Result<string>::Err(errMsg);
+ }
+ case FileType::DIRECTORY:
+ {
+ string errMsg = "Global lib dependency found: ";
+ errMsg += packageDir;
+ errMsg += ", but it's corrupt (Found directory instead of file)";
+ return Result<string>::Err(errMsg);
+ }
+ }
+
+ SibsConfig sibsConfig;
+ Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig);
+ if(result.isErr())
+ return Result<string>::Err(result.getErrMsg());
+
+ if(sibsConfig.getPackageName().empty())
+ return Result<string>::Err("project.conf is missing required field package.name");
+
+ backend::Ninja ninja(backend::Ninja::LibraryType::STATIC);
+ walkDirFilesRecursive(packageDir.c_str(), [&ninja, &packageDir](tinydir_file *file)
+ {
+ if (isSourceFile(file))
+ {
+ printf("Adding source file: %s\n", file->path + packageDir.size() + 1);
+ ninja.addSourceFile(file->path + packageDir.size() + 1);
+ } else
+ {
+ //printf("Ignoring non-source file: %s\n", file->path + packageDir.size() + 1);
+ }
+ });
+
+ // TODO: Create build path if it doesn't exist
+ string debugBuildPath = packageDir + "/build/debug";
+ Result<bool> buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str());
+ if(buildFileResult.isErr())
+ return Result<string>::Err(buildFileResult.getErrMsg());
+
+ Result<bool> buildResult = ninja.build(debugBuildPath.c_str());
+ if(buildResult.isErr())
+ return Result<string>::Err(buildResult.getErrMsg());
+
+ string staticLibPath = debugBuildPath;
+ staticLibPath += "/lib";
+ staticLibPath += name;
+ staticLibPath += ".a";
+ return Result<string>::Ok(staticLibPath);
+ }
+} \ No newline at end of file
diff --git a/src/PkgConfig.cpp b/src/PkgConfig.cpp
new file mode 100644
index 0000000..11e1cf0
--- /dev/null
+++ b/src/PkgConfig.cpp
@@ -0,0 +1,131 @@
+#include "../include/PkgConfig.hpp"
+#include "../include/Exec.hpp"
+
+using namespace std;
+
+namespace sibs
+{
+ string trimRight(const string &input)
+ {
+ for(int i = input.size() - 1; i >= 0; --i)
+ {
+ if(!isspace(input[i]))
+ return input.substr(0, i + 1);
+ }
+ return input;
+ }
+
+ Result<bool> PkgConfig::validatePackageExists(const string &name)
+ {
+ 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 = "pkg-config 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> PkgConfig::validatePackageVersionAtLeast(const string &name, const string &version)
+ {
+ // TODO: Instead of checking if package version is same or newer, check if package is same major version
+ // and same or newer minor version
+
+ // 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);
+ }
+
+ Result<string> PkgConfig::getDynamicLibsLinkerFlags(const vector<string> &libs)
+ {
+ if(libs.empty()) return Result<string>::Ok("");
+
+ string args;
+ for(const string &lib : libs)
+ {
+ args += " '";
+ args += lib;
+ 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)
+ {
+ execResult.unwrap().execStdout = trimRight(execResult.unwrap().execStdout);
+ return Result<string>::Ok(execResult.unwrap().execStdout);
+ }
+ 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("Packages not found");
+ }
+ else if(execResult.unwrap().exitCode == 127)
+ {
+ return Result<string>::Err("pkg-config is not installed");
+ }
+ else
+ {
+ string errMsg = "Failed to get package dynamic lib linking flags, Unknown error, exit code: ";
+ errMsg += to_string(execResult.unwrap().exitCode);
+ return Result<string>::Err(errMsg);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 05a6a03..f9fbd82 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -51,83 +51,6 @@ void validateFilePath(const char *projectConfPath)
}
}
-class SibsConfig : public ConfigCallback
-{
-public:
- SibsConfig() : finishedProcessing(false) {}
-
- const string& getPackageName() const
- {
- assert(finishedProcessing);
- return packageName;
- }
-
- const std::vector<Dependency>& getDependencies() const
- {
- return dependencies;
- }
-protected:
- void processObject(StringView name) override
- {
- currentObject = name;
- printf("Process object: %.*s\n", name.size, name.data);
- }
-
- void processField(StringView name, const ConfigValue &value) override
- {
- printf("Process field: %.*s, value: ", name.size, name.data);
- if(value.isSingle())
- {
- printf("\"%.*s\"", value.asSingle().size, value.asSingle().data);
- }
- else
- {
- printf("[");
- int i = 0;
- for(auto listElement : value.asList())
- {
- if(i > 0)
- printf(", ");
- printf("\"%.*s\"", listElement.size, listElement.data);
- ++i;
- }
- printf("]");
- }
- printf("\n");
-
- if(currentObject.equals("package") && name.equals("name"))
- {
- if(value.isSingle())
- packageName = string(value.asSingle().data, value.asSingle().size);
- else
- throw ParserException("Expected package.name to be a single value, was a list");
- }
- else if(currentObject.equals("dependencies"))
- {
- if(value.isSingle())
- {
- // TODO: Validate version is number in correct format
- Dependency dependency;
- dependency.name = string(name.data, name.size);
- dependency.version = string(value.asSingle().data, value.asSingle().size);
- dependencies.emplace_back(dependency);
- }
- else
- throw ParserException("Expected field under dependencies to be a single value, was a list");
- }
- }
-
- void finished() override
- {
- finishedProcessing = true;
- }
-private:
- StringView currentObject;
- string packageName;
- std::vector<Dependency> dependencies;
- bool finishedProcessing;
-};
-
const char *sourceFileExtensions[] = { "cc", "cpp", "cxx" };
bool isSourceFile(tinydir_file *file)
{
@@ -150,6 +73,8 @@ int main(int argc, const char **argv)
string projectPath = argv[1];
validateDirectoryPath(projectPath.c_str());
+ if(projectPath.back() != '/')
+ projectPath += "/";
string projectConfFilePath = projectPath;
projectConfFilePath += "/project.conf";
@@ -163,27 +88,31 @@ int main(int argc, const char **argv)
exit(6);
}
+ if(sibsConfig.getPackageName().empty())
+ {
+ printf("project.conf is missing required field package.name\n");
+ exit(10);
+ }
+
//string projectSrcPath = projectPath + "/src";
//validateDirectoryPath(projectSrcPath.c_str());
backend::Ninja ninja;
- walkDirFiles(projectPath.c_str(), [&ninja, &projectPath](tinydir_file *file)
+ walkDirFilesRecursive(projectPath.c_str(), [&ninja, &projectPath](tinydir_file *file)
{
if (isSourceFile(file))
{
- printf("Adding source file: %s\n", file->path + projectPath.size() + 1);
- ninja.addSourceFile(file->path + projectPath.size() + 1);
- }
- else
+ printf("Adding source file: %s\n", file->path + projectPath.size());
+ ninja.addSourceFile(file->path + projectPath.size());
+ } else
{
- printf("Ignoring non-source file: %s\n", file->path + projectPath.size() + 1);
+ //printf("Ignoring non-source file: %s\n", file->path + projectPath.size());
}
});
// TODO: Create build path if it doesn't exist
string debugBuildPath = projectPath + "/build/debug";
- string buildFilePath = debugBuildPath + "/build.ninja";
- Result<bool> buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), buildFilePath.c_str());
+ Result<bool> buildFileResult = ninja.createBuildFile(sibsConfig.getPackageName(), sibsConfig.getDependencies(), debugBuildPath.c_str());
if(buildFileResult.isErr())
{
printf("Failed to build ninja file: %s\n", buildFileResult.getErrMsg().c_str());
@@ -197,4 +126,4 @@ int main(int argc, const char **argv)
}
return 0;
-} \ No newline at end of file
+}