aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <0xdec05eba@gmail.com>2018-09-20 06:37:59 +0200
committerdec05eba <0xdec05eba@gmail.com>2018-09-20 06:40:28 +0200
commit194a5708f3a42c6254cf99d8e03b5c8c60224feb (patch)
tree650a6427b438f5ebdbc31746e5d8e5b5debef7ff
parentce415d8b76e355c34dc42b68c4da5a69b2c392b8 (diff)
Initial commit, works to create ninja file
-rw-r--r--.gitignore5
-rw-r--r--.vscode/c_cpp_properties.json17
-rw-r--r--.vscode/settings.json49
-rw-r--r--include/ninja/Ninja.hpp100
-rw-r--r--project.conf9
-rw-r--r--src/Ninja.cpp121
-rw-r--r--test.build20
-rw-r--r--tests/main.cpp37
8 files changed, 358 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..636c6b9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+# Compiled sibs files
+sibs-build/
+compile_commands.json
+tests/sibs-build/
+tests/compile_commands.json
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..3c26c84
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,17 @@
+{
+ "configurations": [
+ {
+ "name": "Linux",
+ "includePath": [
+ "${workspaceFolder}/**"
+ ],
+ "defines": [],
+ "compilerPath": "/usr/bin/gcc",
+ "cStandard": "c11",
+ "cppStandard": "c++14",
+ "intelliSenseMode": "clang-x64",
+ "compileCommands": "${workspaceFolder}/tests/compile_commands.json"
+ }
+ ],
+ "version": 4
+} \ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..b91803e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,49 @@
+{
+ "files.associations": {
+ "*.tcc": "cpp",
+ "unordered_map": "cpp",
+ "vector": "cpp",
+ "deque": "cpp",
+ "list": "cpp",
+ "__config": "cpp",
+ "__nullptr": "cpp",
+ "typeinfo": "cpp",
+ "array": "cpp",
+ "atomic": "cpp",
+ "cctype": "cpp",
+ "chrono": "cpp",
+ "cinttypes": "cpp",
+ "clocale": "cpp",
+ "cmath": "cpp",
+ "cstdarg": "cpp",
+ "cstddef": "cpp",
+ "cstdint": "cpp",
+ "cstdio": "cpp",
+ "cstdlib": "cpp",
+ "cstring": "cpp",
+ "ctime": "cpp",
+ "cwchar": "cpp",
+ "cwctype": "cpp",
+ "exception": "cpp",
+ "fstream": "cpp",
+ "functional": "cpp",
+ "initializer_list": "cpp",
+ "iosfwd": "cpp",
+ "istream": "cpp",
+ "limits": "cpp",
+ "memory": "cpp",
+ "new": "cpp",
+ "numeric": "cpp",
+ "optional": "cpp",
+ "ostream": "cpp",
+ "ratio": "cpp",
+ "sstream": "cpp",
+ "stdexcept": "cpp",
+ "streambuf": "cpp",
+ "string_view": "cpp",
+ "system_error": "cpp",
+ "type_traits": "cpp",
+ "tuple": "cpp",
+ "utility": "cpp"
+ }
+} \ No newline at end of file
diff --git a/include/ninja/Ninja.hpp b/include/ninja/Ninja.hpp
new file mode 100644
index 0000000..cd9be0a
--- /dev/null
+++ b/include/ninja/Ninja.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <string>
+#include <unordered_map>
+#include <stdexcept>
+#include <vector>
+
+namespace ninja
+{
+ enum class NinjaError
+ {
+ NONE,
+ VARIABLE_ALREADY_DEFINED,
+ RULE_ALREADY_DEFINED,
+ RULE_AREADY_BUILT
+ };
+
+ class NinjaException : public std::runtime_error
+ {
+ public:
+ NinjaException(const NinjaError _errorCode, const std::string &errMsg = "") :
+ std::runtime_error(errMsg),
+ errorCode(_errorCode)
+ {
+
+ }
+
+ const NinjaError errorCode;
+ };
+
+ struct NinjaVariable
+ {
+ const std::string name;
+ };
+
+ class NinjaBuildFile;
+
+ class NinjaArg
+ {
+ public:
+ enum class Type
+ {
+ NONE,
+ VALUE,
+ VARIABLE
+ };
+
+ NinjaArg() : type(Type::NONE) {}
+ NinjaArg(const std::string &value) : type(Type::VALUE), arg(value) {}
+ NinjaArg(const NinjaVariable &var) : type(Type::VARIABLE), arg(var.name) {}
+
+ Type type;
+ std::string arg;
+ };
+
+ struct NinjaArgValue
+ {
+ const NinjaVariable arg;
+ const std::string value;
+ };
+
+ // Functions throw NinjaException on failure
+ class NinjaRule
+ {
+ public:
+ NinjaRule(NinjaBuildFile *buildFile, const std::string &name, const std::string &command);
+ void build(const std::string &in, const std::string &out, const std::vector<ninja::NinjaArgValue> &additionalArgs);
+
+ const std::string name;
+ const std::string command;
+ std::string depFile;
+ private:
+ NinjaBuildFile *buildFile;
+ };
+
+ struct NinjaBuild
+ {
+ const NinjaRule *rule;
+ const std::string in;
+ const std::string out;
+ const std::vector<ninja::NinjaArgValue> additionalArgs;
+ };
+
+ // Functions throw NinjaException on failure
+ class NinjaBuildFile
+ {
+ public:
+ ~NinjaBuildFile();
+
+ void defineGlobalVariable(const std::string &name, const std::string &value);
+ NinjaRule* createRule(const std::string &name, const std::vector<NinjaArg> &commandArgs);
+ void build(const NinjaRule *rule, const std::string &in, const std::string &out, const std::vector<ninja::NinjaArgValue> &additionalArgs);
+
+ std::string generate() const;
+ private:
+ std::unordered_map<std::string, std::string> globalVariables;
+ std::unordered_map<std::string, NinjaRule*> rules;
+ std::vector<NinjaBuild> builds;
+ };
+} \ No newline at end of file
diff --git a/project.conf b/project.conf
new file mode 100644
index 0000000..d5a3d2e
--- /dev/null
+++ b/project.conf
@@ -0,0 +1,9 @@
+[package]
+name = "libninja"
+type = "static"
+version = "0.1.0"
+platforms = ["any"]
+tests = "tests"
+
+[config]
+expose_include_dirs = ["include"]
diff --git a/src/Ninja.cpp b/src/Ninja.cpp
new file mode 100644
index 0000000..7b3212e
--- /dev/null
+++ b/src/Ninja.cpp
@@ -0,0 +1,121 @@
+#include "../include/ninja/Ninja.hpp"
+#include <cassert>
+
+namespace ninja
+{
+ static std::string joinArgs(const std::vector<NinjaArg> &args)
+ {
+ std::string result;
+ for(const NinjaArg &arg : args)
+ {
+ if(!result.empty())
+ result += ' ';
+ result += '\'';
+ if(arg.type == NinjaArg::Type::VARIABLE)
+ result += "$";
+ result += arg.arg;
+ result += '\'';
+ }
+ return result;
+ }
+
+ NinjaRule::NinjaRule(NinjaBuildFile *_buildFile, const std::string &_name, const std::string &_command) :
+ buildFile(_buildFile),
+ name(_name),
+ command(_command)
+ {
+ assert(buildFile);
+ }
+
+ NinjaBuildFile::~NinjaBuildFile()
+ {
+ for(auto &rule : rules)
+ {
+ delete rule.second;
+ }
+ }
+
+ void NinjaRule::build(const std::string &in, const std::string &out, const std::vector<ninja::NinjaArgValue> &additionalArgs)
+ {
+ buildFile->build(this, in, out, additionalArgs);
+ }
+
+ void NinjaBuildFile::defineGlobalVariable(const std::string &name, const std::string &value)
+ {
+ auto it = globalVariables.find(name);
+ if(it != globalVariables.end())
+ throw NinjaException(NinjaError::VARIABLE_ALREADY_DEFINED, "Global variable already defined: " + name);
+ globalVariables[name] = value;
+ }
+
+ NinjaRule* NinjaBuildFile::createRule(const std::string &name, const std::vector<NinjaArg> &commandArgs)
+ {
+ auto it = rules.find(name);
+ if(it != rules.end())
+ throw NinjaException(NinjaError::RULE_ALREADY_DEFINED, "Rule already defined: " + name);
+
+ NinjaRule *rule = new NinjaRule(this, name, joinArgs(commandArgs));
+ rules[name] = rule;
+ return rule;
+ }
+
+ void NinjaBuildFile::build(const NinjaRule *rule, const std::string &in, const std::string &out, const std::vector<ninja::NinjaArgValue> &additionalArgs)
+ {
+ for(const NinjaBuild &build : builds)
+ {
+ if(build.rule == rule)
+ throw NinjaException(NinjaError::RULE_AREADY_BUILT, "Rule already built: " + rule->name);
+ }
+ builds.push_back({ rule, in, out, additionalArgs });
+ }
+
+ std::string NinjaBuildFile::generate() const
+ {
+ std::string result;
+ for(const auto &globalVar : globalVariables)
+ {
+ result += globalVar.first;
+ result += " = ";
+ result += globalVar.second;
+ result += '\n';
+ }
+
+ if(!globalVariables.empty())
+ result += '\n';
+
+ for(const auto &rule : rules)
+ {
+ result += "rule ";
+ result += rule.first;
+ result += "\n command = ";
+ result += rule.second->command;
+ if(!rule.second->depFile.empty())
+ {
+ result += "\n depfile = ";
+ result += rule.second->depFile;
+ }
+ result += "\n\n";
+ }
+
+ // TODO: enclose all names with quotes to escape whitespace?
+ for(const NinjaBuild &build : builds)
+ {
+ result += "build ";
+ result += build.out;
+ result += ": ";
+ result += build.rule->name;
+ result += ' ';
+ result += build.in;
+ for(const NinjaArgValue &additionalArg : build.additionalArgs)
+ {
+ result += "\n ";
+ result += additionalArg.arg.name;
+ result += " = ";
+ result += additionalArg.value;
+
+ }
+ result += "\n\n";
+ }
+ return result;
+ }
+}
diff --git a/test.build b/test.build
new file mode 100644
index 0000000..f34a1e7
--- /dev/null
+++ b/test.build
@@ -0,0 +1,20 @@
+
+
+rule c_COMPILER
+ command = 'cc' '$ARGS' '-c' '$in' '-o' '$out'
+
+rule cpp_COMPILER
+ command = 'c++' '$ARGS' '-c' '$in' '-o' '$out'
+ depfile = $out.d
+
+rule BUILD_EXEC
+ command = 'c++' '$ARGS' '-o' '$out' '$in' '$LINK_ARGS' '$aliasing'
+ depfile = $out.d
+
+build test@exe/main.cpp.o: cpp_COMPILER ../../main.cpp
+ ARGS = $globalIncDir -std=c++14 -pedantic -fpie -MMD -MP '-Itest@exe' '-I..' -Wall -Wextra -Werror=return-type -fdiagnostics-show-option '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Winvalid-pch' -fstack-protector '-Og' -fexceptions -Wnon-virtual-dtor -g3 -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables
+
+build test: BUILD_EXEC test@exe/main.cpp.o
+ ARGS = $globalIncDir -std=c++14 -pedantic -fpie -MMD -MP '-Itest@exe' '-I..' -Wall -Wextra -Werror=return-type -fdiagnostics-show-option '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Winvalid-pch' -fstack-protector '-Og' -fexceptions -Wnon-virtual-dtor -g3 -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables
+
+
diff --git a/tests/main.cpp b/tests/main.cpp
new file mode 100644
index 0000000..9af7241
--- /dev/null
+++ b/tests/main.cpp
@@ -0,0 +1,37 @@
+#include <cstdio>
+#include <ninja/Ninja.hpp>
+
+using namespace ninja;
+
+int main(int argc, char **argv)
+{
+ NinjaBuildFile ninjaBuildFile;
+ ninjaBuildFile.defineGlobalVariable("globalIncDir", "'-I/home/dec05eba/git/libninja/include'");
+
+ NinjaVariable argsVar = { "ARGS" };
+ NinjaVariable linkArgsVar = { "LINK_ARGS" };
+
+ NinjaRule *compileCppRule = ninjaBuildFile.createRule("cpp_COMPILER",
+ { NinjaArg("c++"), NinjaArg(argsVar), NinjaArg("-c"), NinjaArg("$in"), NinjaArg("-o"), NinjaArg("$out") });
+ compileCppRule->depFile = "$out.d";
+
+ NinjaRule *buildExeRule = ninjaBuildFile.createRule("BUILD_EXEC",
+ { NinjaArg("c++"), NinjaArg(argsVar), NinjaArg("-o"), NinjaArg("$out"), NinjaArg("$in"), NinjaArg(linkArgsVar), NinjaArg("$aliasing") });
+ buildExeRule->depFile = "$out.d";
+
+ NinjaRule *compileCRule = ninjaBuildFile.createRule("c_COMPILER",
+ { NinjaArg("cc"), NinjaArg(argsVar), NinjaArg("-c"), NinjaArg("$in"), NinjaArg("-o"), NinjaArg("$out") });
+ buildExeRule->depFile = "$out.d";
+
+
+ NinjaArgValue argsValue = { argsVar, "$globalIncDir -std=c++14 -pedantic -fpie -MMD -MP '-Itest@exe' '-I..' -Wall -Wextra -Werror=return-type -fdiagnostics-show-option '-fdiagnostics-color=always' '-pipe' '-D_FILE_OFFSET_BITS=64' '-Winvalid-pch' -fstack-protector '-Og' -fexceptions -Wnon-virtual-dtor -g3 -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables" };
+ compileCppRule->build("../../main.cpp", "test@exe/main.cpp.o", { argsValue });
+
+ NinjaArgValue linkArgsValue = { linkArgsVar, "-Wl,--no-undefined,--as-needed -ldl -lm -pthread -pthread \"/home/dec05eba/git/libninja/sibs-build/debug/liblibninja.so\"" };
+ buildExeRule->build("test@exe/main.cpp.o", "test", { argsValue });
+
+ std::string generatedNinjaFile = ninjaBuildFile.generate();
+
+ printf("%s\n", generatedNinjaFile.c_str());
+ return 0;
+}