// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #include "deps.h" #include "util.h" #include #include namespace { /* Format example: build/src/libctor_a-libctor_cc.o: src/libctor.cc \ src/getoptpp/getoptpp.hpp src/ctor.h src/configure.h src/rebuild.h \ src/A\ B\ C.h src/task.h src/build.h src/unittest.h */ std::vector readDepsMake(const std::string& dep_file) { auto str = readFile(dep_file); std::vector output; std::string tmp; enum class State { pre_colon, post_colon, in_escape, } state{State::pre_colon}; auto old_state{state}; for(const auto& c : str) { if(c == '\r') { // just always ignore windows extra newline char continue; } switch(state) { case State::pre_colon: if(c == ':') // ignore everything until the colon { state = State::post_colon; continue; } continue; case State::post_colon: if(c == '\n') { // done if(!tmp.empty()) { output.emplace_back(tmp); } return output; } if(c == '\\') { old_state = state; state = State::in_escape; continue; } if(c == '\t' || c == ' ') // new token { if(!tmp.empty()) { output.emplace_back(tmp); } tmp.clear(); continue; } break; case State::in_escape: if(c == '\n') { // linewrap state = old_state; continue; } state = old_state; break; } tmp += c; } if(!tmp.empty()) { output.emplace_back(tmp); } return output; } // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html // https://devblogs.microsoft.com/cppblog/introducing-source-dependency-reporting-with-msvc-in-visual-studio-2019-version-16-7/ /* Format examples: { "Version": "1.1", "Data": { "Source": "z:\\home\\deva\\docs\\c\\ctor\\src\\libctor.cc", "ProvidedModule": "", "Includes": [ "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\vector", "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\yvals_core.h", "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\vcruntime.h", . . . "z:\\home\\deva\\docs\\c\\ctor\\src\\unittest.h" ], "ImportedModules": [], "ImportedHeaderUnits": [] } } */ /* { "Version": "1.2", "Data": { "Source": "c:\\jenkins\\workspace\\ctor-linux64\\src\\build.cc", "ProvidedModule": "", "Includes": [ "c:\\jenkins\\workspace\\ctor-linux64\\src\\build.h", "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\string", "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\yvals_core.h", . . . "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\iostream" ], "ImportedModules": [], "ImportedHeaderUnits": [] } } */ std::vector readDepsJson(const std::string& dep_file) { std::ifstream stream(dep_file); auto json = nlohmann::json::parse(stream); for(const auto& [key, value] : json.items()) { if(key == "Data" && value.is_object()) { for(const auto& [inner_key, inner_value] : value.items()) { if(inner_key == "Includes" && inner_value.is_array()) { std::vector deps; for(const auto& dep : inner_value) { deps.emplace_back(dep); } return deps; } } } } return {}; } } std::vector readDeps(const std::string& dep_file, ctor::toolchain toolchain) { if(!std::filesystem::exists(dep_file)) { return {}; } switch(toolchain) { case ctor::toolchain::any: case ctor::toolchain::none: return {}; // json based: case ctor::toolchain::msvc: return readDepsJson(dep_file); // makefile .d file based: case ctor::toolchain::gcc: case ctor::toolchain::clang: return readDepsMake(dep_file); } return {}; }