diff options
Diffstat (limited to 'libcppbuild.cc')
-rw-r--r-- | libcppbuild.cc | 204 |
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; +} |