diff options
Diffstat (limited to 'Builder.cpp')
-rw-r--r-- | Builder.cpp | 147 |
1 files changed, 92 insertions, 55 deletions
diff --git a/Builder.cpp b/Builder.cpp index 51ac90f..86f6920 100644 --- a/Builder.cpp +++ b/Builder.cpp @@ -60,6 +60,16 @@ namespace { return sources; } + // get link libs of single target, ptree is <build> subtree + std::vector<std::string> get_link_libs_of_build(const pt::ptree& ptree) { + std::vector<std::string> linklibs; + for (const pt::ptree::value_type &v: ptree) { + if (v.first == "linklib") + linklibs.push_back(v.second.data()); + } + return linklibs; + } + // ptree is main tree std::vector<fs::path> get_all_sources(const pt::ptree& ptree) { std::vector<fs::path> result; @@ -105,20 +115,6 @@ namespace { return t_p < t_other; } - // outdated according to dependency file list, non-recursively - bool is_outdated(const fs::path& p, const std::vector<fs::path> &dependencies) { - if (!fs::exists(p)) - return true; - - for (const auto& dep: dependencies) { - if (!fs::exists(dep) || is_older(p, dep)) { - return true; - } - } - - return false; - } - std::vector<fs::path> deps_from_depfile(const fs::path& path) { std::string depfile_content{Reichwein::File::getFile(path)}; std::vector<std::string> parts {Reichwein::Stringhelper::split(depfile_content, ":\r\n")}; @@ -138,43 +134,19 @@ namespace { return depfile; } - // return contained dependencies - // input: cpp - std::vector<fs::path> make_depfile_from(const fs::path& p) { - fs::path depfile{depfile_name_from(p)}; - - // check if depfile exists and if it contains up to date info - if (!fs::exists(depfile) || is_outdated(depfile, deps_from_depfile(depfile))) { - // actually create depfile - int result{system(fmt::format("g++ -MM -MF {} -c {}", depfile.string(), p.string()).c_str())}; - if (result != 0) { - throw std::runtime_error(fmt::format("Depfile {} can't be created", depfile.string())); - } - } - - return deps_from_depfile(depfile); - } - - std::unordered_map<fs::path, std::vector<fs::path>> get_dependencies(const pt::ptree& ptree) { - std::unordered_map<fs::path, std::vector<fs::path>> dependencies; + std::unordered_map<fs::path, std::vector<std::string>> get_link_libs(const pt::ptree& ptree) { + std::unordered_map<fs::path, std::vector<std::string>> link_libs_map; for (const auto& build: ptree.get_child("ymake")) { if (build.first == "build") { - dependencies.emplace(get_target(build.second), get_objects(build.second)); - - std::vector<fs::path> sources{get_sources(build.second)}; - for (const auto& p: sources) { - fs::path p_obj{p}; - p_obj.replace_extension("o"); - std::vector<fs::path> deps {make_depfile_from(p)}; - // keep .d files for now to speed dependencies detection on following runs - //fs::remove(depfile_name_from(p)); - dependencies.emplace(p_obj, deps); + std::vector<std::string> link_libs{get_link_libs_of_build(build.second)}; + if (!link_libs.empty()) { + link_libs_map.emplace(get_target(build.second), link_libs); } } } - return dependencies; + return link_libs_map; } } @@ -182,7 +154,8 @@ namespace { Builder::Builder(const pt::ptree& ptree): _ptree(ptree), _all_targets{get_all_targets(ptree)}, - _all_objects{get_all_objects(ptree)} + _all_objects{get_all_objects(ptree)}, + _link_libs{get_link_libs(ptree)} { // intentionally defer creation of _dependencies to build() // to prevent creation of .d files in clean() @@ -197,6 +170,15 @@ std::vector<fs::path> Builder::dependencies_of(const fs::path& p) const } } +std::vector<std::string> Builder::link_libs_of(const fs::path& p) const +{ + try { + return _link_libs.at(p); + } catch (const std::out_of_range& ex) { + return {}; // empty by default + } +} + // outdated according to dependency tree, recursively bool Builder::is_outdated(const fs::path& p) const { @@ -217,24 +199,79 @@ bool Builder::is_outdated(const fs::path& p) const return false; } +// outdated according to dependency file list, non-recursively +bool Builder::is_outdated(const fs::path& p, const std::vector<fs::path> &dependencies) const +{ + if (!fs::exists(p)) + return true; + + for (const auto& dep: dependencies) { + if (!fs::exists(dep) || is_older(p, dep)) { + return true; + } + } + + return false; +} + +// return contained dependencies +// input: cpp +std::vector<fs::path> Builder::make_depfile_from(const fs::path& p) const +{ + fs::path depfile{depfile_name_from(p)}; + + // check if depfile exists and if it contains up to date info + if (!fs::exists(depfile) || is_outdated(depfile, deps_from_depfile(depfile))) { + // actually create depfile + int result{system(_lang.getDepCommand(depfile.string(), p.string()).c_str())}; + if (result != 0) { + throw std::runtime_error(fmt::format("Depfile {} can't be created", depfile.string())); + } + } + + return deps_from_depfile(depfile); +} + +std::unordered_map<fs::path, std::vector<fs::path>> Builder::get_dependencies(const pt::ptree& ptree) const +{ + std::unordered_map<fs::path, std::vector<fs::path>> dependencies; + + for (const auto& build: ptree.get_child("ymake")) { + if (build.first == "build") { + dependencies.emplace(get_target(build.second), get_objects(build.second)); + + std::vector<fs::path> sources{get_sources(build.second)}; + for (const auto& p: sources) { + fs::path p_obj{p}; + p_obj.replace_extension("o"); + std::vector<fs::path> deps {make_depfile_from(p)}; + // keep .d files for now to speed dependencies detection on following runs + //fs::remove(depfile_name_from(p)); + dependencies.emplace(p_obj, deps); + } + } + } + + return dependencies; +} + // build 1 file void Builder::build_file(const fs::path& p) { std::string command; if (p.extension() == ".o") { - // compile - fs::path cppfile{p}; - cppfile.replace_extension("cpp"); - command = fmt::format("g++ -std=c++17 -c {} -o {}", cppfile.string(), p.string()); + // compile + std::vector<fs::path> source_files{dependencies_of(p)}; + auto it{std::find_if(source_files.begin(), source_files.end(), is_compile_unit_source_by_extension)}; + if (it == source_files.end()) { + throw std::runtime_error(fmt::format("No source file found for {}", p.string())); + } + command = _lang.getCompileCommand(p, *it); } else { // link - command = "g++"; std::vector<fs::path> objects{dependencies_of(p)}; - for (auto &i: objects) { - command += fmt::format(" {}", i.string()); - } - command += " -lreichwein -lfmt"; - command += fmt::format(" -o {}", p.string()); + std::vector<std::string> link_libs{link_libs_of(p)}; + command = _lang.getLinkCommand(p, objects, link_libs); } std::cout << command << std::endl; |