aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2017-12-09 02:43:02 +0100
committerdec05eba <dec05eba@protonmail.com>2017-12-09 02:43:02 +0100
commitd9090882cae78695765204a3e1b60c6a9bf27977 (patch)
treee3e75fef97df7e02cd715af718ae7c3ffeaee00f
parentfb2072deb3e50afdb062570a3a80ec1afb5bfb56 (diff)
Added ninja backend, very simple project works
-rw-r--r--CMakeLists.txt2
-rw-r--r--backend/ninja/Ninja.cpp95
-rw-r--r--backend/ninja/Ninja.hpp21
-rw-r--r--include/Conf.hpp10
-rw-r--r--include/FileUtil.hpp1
-rw-r--r--src/Conf.cpp10
-rw-r--r--src/FileUtil.cpp14
-rw-r--r--src/main.cpp49
8 files changed, 178 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ed5c57..784e6da 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)
+ external/xxhash.c backend/ninja/Ninja.cpp)
add_executable(sibs ${SOURCE_FILES}) \ No newline at end of file
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
new file mode 100644
index 0000000..7006d30
--- /dev/null
+++ b/backend/ninja/Ninja.cpp
@@ -0,0 +1,95 @@
+#include <cstring>
+#include "Ninja.hpp"
+#include "../../include/FileUtil.hpp"
+
+using namespace std;
+
+namespace backend
+{
+ string join(const vector<string> &list, const char *joinStr)
+ {
+ if(list.empty()) return "";
+ string result;
+ long stringSize = 0;
+ long joinStrLen = strlen(joinStr);
+ int i = 0;
+ for(const string &str : list)
+ {
+ stringSize += str.size();
+ if(!str.empty() && i > 0)
+ stringSize += joinStrLen;
+ ++i;
+ }
+
+ result.reserve(stringSize);
+
+ i = 0;
+ for(const string &str : list)
+ {
+ if(i > 0);
+ result += joinStr;
+ result += str;
+ ++i;
+ }
+
+ return move(result);
+ }
+
+ void Ninja::addSourceFile(const char *filepath)
+ {
+ if(filepath && !containsSourceFile(filepath))
+ sourceFiles.emplace_back(filepath);
+ }
+
+ bool Ninja::containsSourceFile(const char *filepath) const
+ {
+ for(const string &sourceFile : sourceFiles)
+ {
+ if(sourceFile == filepath)
+ return true;
+ }
+ return false;
+ }
+
+ void Ninja::build(const std::string &packageName, const char *savePath)
+ {
+ if(sourceFiles.empty()) return;
+ printf("Package name: %s\n", packageName.c_str());
+
+ string result;
+ result.reserve(16384);
+
+ result += "cflags = -Wall -Werror\n\n";
+
+ 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";
+
+ vector<string> objectNames;
+ for(const string &sourceFile : sourceFiles)
+ {
+ //string sourceFileEncoded = sourceFile;
+ //replace(sourceFileEncoded, '/', '@');
+ string objectName = packageName + "@exe/" + sourceFile + ".o";
+ result += "build ";
+ result += objectName;
+ 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";
+ objectNames.emplace_back(objectName);
+ }
+
+ result += "build ";
+ result += packageName;
+ result += ": cpp_LINKER ";
+ result += join(objectNames, " ");
+ result += "\n";
+ result += " LINK_ARGS = '-Wl,--no-undefined' '-Wl,--as-needed'\n\n";
+
+ sibs::fileOverwrite(savePath, sibs::StringView(result.data(), result.size()));
+ printf("Created ninja build file: %s\n", savePath);
+ }
+} \ No newline at end of file
diff --git a/backend/ninja/Ninja.hpp b/backend/ninja/Ninja.hpp
new file mode 100644
index 0000000..ad71c80
--- /dev/null
+++ b/backend/ninja/Ninja.hpp
@@ -0,0 +1,21 @@
+#ifndef BACKEND_NINJA_HPP
+#define BACKEND_NINJA_HPP
+
+#include <vector>
+#include <string>
+
+namespace backend
+{
+ class Ninja
+ {
+ public:
+ void addSourceFile(const char *filepath);
+ void build(const std::string &packageName, const char *savePath);
+ private:
+ bool containsSourceFile(const char *filepath) const;
+ private:
+ std::vector<std::string> sourceFiles;
+ };
+}
+
+#endif //BACKEND_NINJA_HPP
diff --git a/include/Conf.hpp b/include/Conf.hpp
index c27046b..8b98189 100644
--- a/include/Conf.hpp
+++ b/include/Conf.hpp
@@ -6,6 +6,7 @@
#include "utils.hpp"
#include <vector>
#include <cassert>
+#include <stdexcept>
namespace sibs
{
@@ -55,6 +56,15 @@ namespace sibs
class Parser;
+ class ParserException : public std::runtime_error
+ {
+ public:
+ ParserException(const std::string &errMsg) : runtime_error(errMsg)
+ {
+
+ }
+ };
+
class ConfigCallback
{
friend class Parser;
diff --git a/include/FileUtil.hpp b/include/FileUtil.hpp
index 345c72a..4083cb1 100644
--- a/include/FileUtil.hpp
+++ b/include/FileUtil.hpp
@@ -20,6 +20,7 @@ namespace sibs
FileType getFileType(const char *path);
void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc);
Result<StringView> getFileContent(const char *filepath);
+ bool fileOverwrite(const char *filepath, StringView data);
}
#endif //SIBS_FILEUTIL_HPP
diff --git a/src/Conf.cpp b/src/Conf.cpp
index cea1b01..56b1e2a 100644
--- a/src/Conf.cpp
+++ b/src/Conf.cpp
@@ -1,7 +1,6 @@
#include "../include/Conf.hpp"
#include "../include/FileUtil.hpp"
#include "../external/utf8/unchecked.h"
-#include <stdexcept>
using namespace std;
using u8string = utf8::unchecked::iterator<char*>;
@@ -156,15 +155,6 @@ namespace sibs
};
};
- class ParserException : public std::runtime_error
- {
- public:
- ParserException(const string &errMsg) : runtime_error(errMsg)
- {
-
- }
- };
-
class Parser
{
public:
diff --git a/src/FileUtil.cpp b/src/FileUtil.cpp
index 30fe03d..8502e84 100644
--- a/src/FileUtil.cpp
+++ b/src/FileUtil.cpp
@@ -18,6 +18,7 @@ namespace sibs
}
}
+ // TODO: Handle failure (directory doesn't exist, no permission etc)
void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc)
{
tinydir_dir dir;
@@ -50,6 +51,7 @@ namespace sibs
size_t fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
+ // TODO: Change this to string so it can be deallocated and use std::move to prevent copies
char *result = (char*)malloc(fileSize + 1);
if(!result)
{
@@ -62,4 +64,16 @@ namespace sibs
fclose(file);
return Result<StringView>::Ok(StringView(result, fileSize));
}
+
+ bool fileOverwrite(const char *filepath, StringView data)
+ {
+ FILE *file = fopen(filepath, "wb");
+ if(!file || errno != 0)
+ {
+ perror(filepath);
+ return false;
+ }
+ fwrite(data.data, 1, data.size, file);
+ fclose(file);
+ }
} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index ce914b7..866d691 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,7 +1,9 @@
#include <cstdio>
#include "../include/FileUtil.hpp"
#include "../include/Conf.hpp"
+#include "../backend/ninja/Ninja.hpp"
#include <string>
+#include <cassert>
using namespace std;
using namespace sibs;
@@ -50,6 +52,14 @@ void validateFilePath(const char *projectConfPath)
class SibsConfig : public ConfigCallback
{
+public:
+ SibsConfig() : finishedProcessing(false) {}
+
+ const string& getPackageName() const
+ {
+ assert(finishedProcessing);
+ return packageName;
+ }
protected:
void processObject(StringView name) override
{
@@ -78,15 +88,24 @@ protected:
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");
+ }
}
void finished() override
{
-
+ finishedProcessing = true;
}
-
private:
StringView currentObject;
+ string packageName;
+ bool finishedProcessing;
};
const char *sourceFileExtensions[] = { "cc", "cpp", "cxx" };
@@ -109,8 +128,8 @@ int main(int argc, const char **argv)
if(argc != 2)
usage();
- const char *projectPath = argv[1];
- validateDirectoryPath(projectPath);
+ string projectPath = argv[1];
+ validateDirectoryPath(projectPath.c_str());
string projectConfFilePath = projectPath;
projectConfFilePath += "/project.conf";
@@ -118,29 +137,33 @@ int main(int argc, const char **argv)
SibsConfig sibsConfig;
Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig);
- if(result.isOk())
- {
-
- }
- else
+ if(result.isErr())
{
printf("Failed to read config: %s\n", result.getErrMsg().c_str());
exit(6);
}
- string projectSrcPath = string(projectPath) + "/src";
+ string projectSrcPath = projectPath + "/src";
validateDirectoryPath(projectSrcPath.c_str());
- walkDirFiles(projectSrcPath.c_str(), [](tinydir_file *file)
+
+ backend::Ninja ninja;
+ walkDirFiles(projectSrcPath.c_str(), [&ninja, &projectPath](tinydir_file *file)
{
if (isSourceFile(file))
{
- printf("source file: %s\n", file->path);
+ printf("Adding source file: %s\n", file->path + projectPath.size() + 1);
+ ninja.addSourceFile(file->path + projectPath.size() + 1);
}
else
{
- printf("non source file: %s\n", file->path);
+ printf("Ignoring non-source file: %s\n", file->path + projectPath.size() + 1);
}
});
+ // TODO: Create build path if it doesn't exist
+ string debugBuildPath = projectPath + "/build/debug";
+ string buildFilePath = debugBuildPath + "/build.ninja";
+ ninja.build(sibsConfig.getPackageName(), buildFilePath.c_str());
+
return 0;
} \ No newline at end of file