summaryrefslogtreecommitdiff
path: root/libcppbuild.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libcppbuild.cc')
-rw-r--r--libcppbuild.cc204
1 files changed, 204 insertions, 0 deletions
diff --git a/libcppbuild.cc b/libcppbuild.cc
new file mode 100644
index 0000000..ff208b3
--- /dev/null
+++ b/libcppbuild.cc
@@ -0,0 +1,204 @@
+#include <vector>
+#include <string>
+#include <filesystem>
+#include <iostream>
+#include <fstream>
+#include <regex>
+#include <utility>
+
+#include "libcppbuild.h"
+
+namespace
+{
+std::string readFile(const std::string &fileName)
+{
+ std::ifstream ifs(fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
+
+ std::ifstream::pos_type fileSize = ifs.tellg();
+ ifs.seekg(0, std::ios::beg);
+
+ std::vector<char> bytes(fileSize);
+ ifs.read(bytes.data(), fileSize);
+
+ return std::string(bytes.data(), fileSize);
+}
+
+std::vector<std::string> readDeps(const std::string& depFile)
+{
+ if(!std::filesystem::exists(depFile))
+ {
+ return {};
+ }
+
+ auto str = readFile(depFile);
+
+ std::vector<std::string> output;
+ std::string tmp;
+ bool start{false};
+ bool in_whitespace{false};
+ for(const auto& c : str)
+ {
+ if(c == '\\' || c == '\n')
+ {
+ continue;
+ }
+
+ if(c == ':')
+ {
+ start = true;
+ continue;
+ }
+
+ if(!start)
+ {
+ continue;
+ }
+
+ if(c == ' ' || c == '\t')
+ {
+ if(in_whitespace)
+ {
+ continue;
+ }
+
+ if(!tmp.empty())
+ {
+ output.push_back(tmp);
+ }
+ tmp.clear();
+ in_whitespace = true;
+ }
+ else
+ {
+ in_whitespace = false;
+ tmp += c;
+ }
+ }
+
+ if(!tmp.empty())
+ {
+ output.push_back(tmp);
+ }
+
+ return output;
+}
+} // namespace ::
+
+
+
+int main(int argc, const char* argv[])
+{
+ if(argc == 2 && std::string(argv[1]) == "clean")
+ {
+ system("rm -Rf build");
+ return 0;
+ }
+
+ std::filesystem::path builddir("build/");
+ std::filesystem::create_directory(builddir);
+
+ auto project = configs();
+ std::string output = "build/" + project.target;
+ const auto& files = project.sources;
+ std::vector<std::string> objects;
+
+ std::cout << "Building\n";
+ for(const auto& file : files)
+ {
+ auto path = std::filesystem::path(file);
+ std::string object = builddir / path.stem();
+ object += ".o";
+ objects.push_back(object);
+
+ std::string deps = builddir / path.stem();
+ deps += ".d";
+
+ if(!std::filesystem::exists(file))
+ {
+ std::cout << "Missing source file: " << file << "\n";
+ return 1;
+ }
+
+ bool recompile{false};
+
+ if(!std::filesystem::exists(object) ||
+ !std::filesystem::exists(deps))
+ {
+ recompile = true;
+ }
+
+ if(!recompile &&
+ std::filesystem::last_write_time(file) >
+ std::filesystem::last_write_time(deps))
+ {
+ recompile = true;
+ }
+
+ if(!recompile)
+ {
+ auto depList = readDeps(deps);
+ for(const auto& dep : depList)
+ {
+ if(!std::filesystem::exists(dep) ||
+ std::filesystem::last_write_time(object) <
+ std::filesystem::last_write_time(dep))
+ {
+ recompile = true;
+ break;
+ }
+ }
+ }
+
+ if(recompile ||
+ !std::filesystem::exists(object) ||
+ std::filesystem::last_write_time(file) >
+ std::filesystem::last_write_time(object))
+ {
+ std::string compiler = "g++ -MMD -c " + file + " -o " + object;
+ std::cout << compiler << "\n";
+ if(system(compiler.data()))
+ {
+ return 1;
+ }
+ }
+ }
+
+ std::cout << "Linking\n";
+ bool dolink{false};
+ if(!std::filesystem::exists(output))
+ {
+ dolink = true;
+ }
+ else
+ {
+ for(const auto& object : objects)
+ {
+ if(std::filesystem::last_write_time(output) <=
+ std::filesystem::last_write_time(object))
+ {
+ dolink = true;
+ break;
+ }
+ }
+ }
+
+ if(!dolink)
+ {
+ std::cout << "No linking needed\n";
+ return 0;
+ }
+
+ std::string objectlist;
+ for(const auto& object : objects)
+ {
+ objectlist += object + " ";
+ }
+ std::string compiler = "g++ " + objectlist + " -o " + output;
+ std::cout << compiler << "\n";
+ if(system(compiler.data()))
+ {
+ return 1;
+ }
+
+ return 0;
+}