diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | xmake.cpp | 90 |
2 files changed, 59 insertions, 32 deletions
@@ -7,6 +7,7 @@ OBJ=$(SRC:.cpp=.o) all: $(PROJECTNAME) LDLIBS += -lfmt +CXXFLAGS += -std=c++17 $(PROJECTNAME): $(OBJ) $(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@ @@ -27,33 +27,51 @@ namespace { std::cout << "Usage: xmake <target>" << std::endl; } - std::string get_target(pt::ptree& ptree) { + fs::path get_target(const pt::ptree& ptree) { return ptree.get<std::string>("xmake.build.name"); } - std::vector<std::string> get_sources(pt::ptree& ptree) { - std::vector<std::string> sources; - for (pt::ptree::value_type &v: ptree.get_child("xmake.build")) { + std::vector<fs::path> get_sources(const pt::ptree& ptree) { + std::vector<fs::path> sources; + for (const pt::ptree::value_type &v: ptree.get_child("xmake.build")) { if (v.first == "source") sources.push_back(v.second.data()); } return sources; } - std::vector<std::string> get_objects(pt::ptree& ptree) { - std::vector<std::string> objects{get_sources(ptree)}; + std::vector<fs::path> get_objects(const pt::ptree& ptree) { + std::vector<fs::path> objects{get_sources(ptree)}; for (auto &i: objects) { - fs::path p{i}; - p.replace_extension("o"); - i = p.string(); + i.replace_extension("o"); } return objects; } - void build(pt::ptree& ptree) { - std::string target{get_target(ptree)}; + // both need to exist + bool is_older(const fs::path& p, const fs::path& other) { + auto t_p{fs::last_write_time(p)}; + auto t_other{fs::last_write_time(other)}; + return t_p < t_other; + } + + bool is_outdated(const fs::path& p, const std::vector<fs::path> &dependencies) { + if (!fs::exists(p)) + return true; + + for (auto& dep: dependencies) { + if (!exists(dep) || is_older(p, dep)) { + return true; + } + } - std::vector<std::string> sources{get_sources(ptree)}; + return false; + } + + void build(const pt::ptree& ptree) { + fs::path target{get_target(ptree)}; + + std::vector<fs::path> sources{get_sources(ptree)}; std::cout << "Target: " << target << std::endl; @@ -64,44 +82,52 @@ namespace { std::vector<std::string> commands; // compile - for (auto &i: sources) { - fs::path p{i}; - fs::path p_obj{i}; + for (auto &p: sources) { + fs::path p_obj{p}; p_obj.replace_extension("o"); - commands.push_back(fmt::format("g++ -std=c++17 -c {} -o {}", p.string(), p_obj.string())); + if (is_outdated(p_obj, std::vector<fs::path>{p})) { + commands.push_back(fmt::format("g++ -std=c++17 -c {} -o {}", p.string(), p_obj.string())); + } } // link - std::string link_command{"g++"}; - std::vector<std::string> objects{get_objects(ptree)}; - for (auto &i: objects) { - link_command += fmt::format(" {}", i); + std::vector<fs::path> objects{get_objects(ptree)}; + std::vector<fs::path> dependencies{sources}; + if (is_outdated(target, dependencies)) { + std::string link_command{"g++"}; + for (auto &i: objects) { + link_command += fmt::format(" {}", i.string()); + } + link_command += " -lfmt"; + link_command += fmt::format(" -o {}", target.string()); + commands.push_back(link_command); } - link_command += " -lfmt"; - link_command += fmt::format(" -o {}", target); - commands.push_back(link_command); std::cout << "Commands: " << std::endl; for (auto &i: commands) { std::cout << " " << i << std::endl; } - std::cout << "Running commands: " << std::endl; - for (auto &i: commands) { - std::cout << i << std::endl; - int result{system(i.c_str())}; - if (result != 0) { - throw std::runtime_error(fmt::format("Error {}", result)); + if (commands.size() == 0) { + std::cout << "Everything up to date." << std::endl; + } else { + std::cout << "Running commands: " << std::endl; + for (auto &i: commands) { + std::cout << i << std::endl; + int result{system(i.c_str())}; + if (result != 0) { + throw std::runtime_error(fmt::format("Error {}", result)); + } } } } - void clean(pt::ptree& ptree) { - std::vector<std::string> cleanlist{get_objects(ptree)}; + void clean(const pt::ptree& ptree) { + std::vector<fs::path> cleanlist{get_objects(ptree)}; cleanlist.push_back(get_target(ptree)); std::vector<std::string> commands; for (auto &i: cleanlist) { - commands.push_back(fmt::format("rm -f {}", i)); + commands.push_back(fmt::format("rm -f {}", i.string())); } std::cout << "Running commands: " << std::endl; |