| return ret; | return ret; | ||||
| } | } | ||||
| msvc_deps_info dds::parse_msvc_output_for_deps(std::string_view output, std::string_view leader) { | |||||
| auto lines = split_view(output, "\n"); | |||||
| std::string cleaned_output; | |||||
| deps_info deps; | |||||
| for (auto line : lines) { | |||||
| line = trim_view(line); | |||||
| if (!starts_with(line, leader)) { | |||||
| cleaned_output += std::string(line); | |||||
| cleaned_output.push_back('\n'); | |||||
| continue; | |||||
| } | |||||
| auto remaining = trim_view(line.substr(leader.size())); | |||||
| deps.inputs.emplace_back(fs::weakly_canonical(remaining)); | |||||
| } | |||||
| if (!cleaned_output.empty()) { | |||||
| // Remove the extra newline at the back | |||||
| cleaned_output.pop_back(); | |||||
| } | |||||
| return {deps, cleaned_output}; | |||||
| } | |||||
| void dds::update_deps_info(database& db, const deps_info& deps) { | void dds::update_deps_info(database& db, const deps_info& deps) { | ||||
| db.store_mtime(deps.output, fs::last_write_time(deps.output)); | db.store_mtime(deps.output, fs::last_write_time(deps.output)); | ||||
| db.store_file_command(deps.output, {deps.command, deps.command_output}); | db.store_file_command(deps.output, {deps.command, deps.command_output}); |
| deps_info parse_mkfile_deps_file(path_ref where); | deps_info parse_mkfile_deps_file(path_ref where); | ||||
| deps_info parse_mkfile_deps_str(std::string_view str); | deps_info parse_mkfile_deps_str(std::string_view str); | ||||
| struct msvc_deps_info { | |||||
| struct deps_info deps_info; | |||||
| std::string cleaned_output; | |||||
| }; | |||||
| msvc_deps_info parse_msvc_output_for_deps(std::string_view output, std::string_view leader); | |||||
| void update_deps_info(database& db, const deps_info&); | void update_deps_info(database& db, const deps_info&); | ||||
| struct deps_rebuild_info { | struct deps_rebuild_info { | ||||
| std::string previous_command_output; | std::string previous_command_output; | ||||
| }; | }; | ||||
| deps_rebuild_info | |||||
| get_rebuild_info(database& db, path_ref output_path); | |||||
| deps_rebuild_info get_rebuild_info(database& db, path_ref output_path); | |||||
| } // namespace dds | } // namespace dds |
| deps = dds::parse_mkfile_deps_str("foo.c"); | deps = dds::parse_mkfile_deps_str("foo.c"); | ||||
| CHECK(deps.output.empty()); | CHECK(deps.output.empty()); | ||||
| CHECK(deps.inputs.empty()); | CHECK(deps.inputs.empty()); | ||||
| } | |||||
| TEST_CASE("Parse MSVC deps") { | |||||
| auto mscv_output = R"( | |||||
| Note: including file: C:\foo\bar\filepath/thing.hpp | |||||
| Note: including file: C:\foo\bar\filepath/baz.h | |||||
| Note: including file: C:\foo\bar\filepath/quux.h | |||||
| Note: including file: C:\foo\bar\filepath/cats/quux.h | |||||
| Other line | |||||
| Something else | |||||
| )"; | |||||
| auto res = dds::parse_msvc_output_for_deps(mscv_output, "Note: including file:"); | |||||
| auto& deps = res.deps_info; | |||||
| auto new_output = res.cleaned_output; | |||||
| CHECK(new_output == "\nOther line\nSomething else\n"); | |||||
| CHECK(deps.inputs | |||||
| == std::vector<dds::fs::path>({ | |||||
| "C:\\foo\\bar\\filepath/thing.hpp", | |||||
| "C:\\foo\\bar\\filepath/baz.h", | |||||
| "C:\\foo\\bar\\filepath/quux.h", | |||||
| "C:\\foo\\bar\\filepath/cats/quux.h", | |||||
| })); | |||||
| } | } |