From 474ce1322f3c13fe414b5e2201d82a4136a947da Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Fri, 11 Jun 2021 19:07:09 +0200 Subject: Simple build config with dependency tracking. --- Makefile | 11 ++++ cppbuild.cc | 19 ++++++ libcppbuild.cc | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libcppbuild.h | 12 ++++ src/bar.cc | 9 +++ src/bar.o | Bin 0 -> 2848 bytes src/bas.h | 2 + src/foo.cc | 6 ++ src/foo.h | 5 ++ 9 files changed, 268 insertions(+) create mode 100644 Makefile create mode 100644 cppbuild.cc create mode 100644 libcppbuild.cc create mode 100644 libcppbuild.h create mode 100644 src/bar.cc create mode 100644 src/bar.o create mode 100644 src/bas.h create mode 100644 src/foo.cc create mode 100644 src/foo.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7cad9bd --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +all: libcppbuild.a cppbuild + +libcppbuild.a: libcppbuild.cc + g++ -g -std=c++17 libcppbuild.cc -c -o libcppbuild.o + ar rcs libcppbuild.a libcppbuild.o + +cppbuild: cppbuild.cc libcppbuild.a + g++ -g -std=c++17 cppbuild.cc libcppbuild.a -o cppbuild + +clean: + rm -f cppbuild libcppbuild.o libcppbuild.a diff --git a/cppbuild.cc b/cppbuild.cc new file mode 100644 index 0000000..b06b082 --- /dev/null +++ b/cppbuild.cc @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "libcppbuild.h" + +BuildConfiguration configs() +{ + return + { + // target + "bas", + { + // source files + "src/foo.cc", + "src/bar.cc", + } + }; +} 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 +#include +#include +#include +#include +#include +#include + +#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 bytes(fileSize); + ifs.read(bytes.data(), fileSize); + + return std::string(bytes.data(), fileSize); +} + +std::vector readDeps(const std::string& depFile) +{ + if(!std::filesystem::exists(depFile)) + { + return {}; + } + + auto str = readFile(depFile); + + std::vector 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 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; +} diff --git a/libcppbuild.h b/libcppbuild.h new file mode 100644 index 0000000..11a8eb7 --- /dev/null +++ b/libcppbuild.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +struct BuildConfiguration +{ + std::string target; + std::vector sources; +}; + +BuildConfiguration configs(); diff --git a/src/bar.cc b/src/bar.cc new file mode 100644 index 0000000..2486a0a --- /dev/null +++ b/src/bar.cc @@ -0,0 +1,9 @@ +#include + +#include "foo.h" + +int main() +{ + foo(); + std::cout << __FILE__ << "\n"; +} diff --git a/src/bar.o b/src/bar.o new file mode 100644 index 0000000..37903db Binary files /dev/null and b/src/bar.o differ diff --git a/src/bas.h b/src/bas.h new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/src/bas.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/src/foo.cc b/src/foo.cc new file mode 100644 index 0000000..b2c478c --- /dev/null +++ b/src/foo.cc @@ -0,0 +1,6 @@ +#include + +void foo() +{ + std::cout << __FILE__ << "\n"; +} diff --git a/src/foo.h b/src/foo.h new file mode 100644 index 0000000..9620fc7 --- /dev/null +++ b/src/foo.h @@ -0,0 +1,5 @@ +#pragma once + +#include "bas.h" + +void foo(); -- cgit v1.2.3