| #include "./deps.hpp" | |||||
| #include "./file_deps.hpp" | |||||
| #include <dds/db/database.hpp> | #include <dds/db/database.hpp> | ||||
| #include <dds/proc.hpp> | #include <dds/proc.hpp> | ||||
| using namespace dds; | using namespace dds; | ||||
| deps_info dds::parse_mkfile_deps_file(path_ref where) { | |||||
| file_deps_info dds::parse_mkfile_deps_file(path_ref where) { | |||||
| auto content = slurp_file(where); | auto content = slurp_file(where); | ||||
| return parse_mkfile_deps_str(content); | return parse_mkfile_deps_str(content); | ||||
| } | } | ||||
| deps_info dds::parse_mkfile_deps_str(std::string_view str) { | |||||
| deps_info ret; | |||||
| file_deps_info dds::parse_mkfile_deps_str(std::string_view str) { | |||||
| file_deps_info ret; | |||||
| // Remove escaped newlines | // Remove escaped newlines | ||||
| auto no_newlines = replace(str, "\\\n", " "); | auto no_newlines = replace(str, "\\\n", " "); | ||||
| } | } | ||||
| msvc_deps_info dds::parse_msvc_output_for_deps(std::string_view output, std::string_view leader) { | 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; | |||||
| auto lines = split_view(output, "\n"); | |||||
| std::string cleaned_output; | |||||
| file_deps_info deps; | |||||
| for (const auto full_line : lines) { | for (const auto full_line : lines) { | ||||
| auto trimmed = trim_view(full_line); | auto trimmed = trim_view(full_line); | ||||
| if (!starts_with(trimmed, leader)) { | if (!starts_with(trimmed, leader)) { | ||||
| return {deps, cleaned_output}; | return {deps, cleaned_output}; | ||||
| } | } | ||||
| void dds::update_deps_info(database& db, const deps_info& deps) { | |||||
| void dds::update_deps_info(database& db, const file_deps_info& deps) { | |||||
| db.store_file_command(deps.output, {deps.command, deps.command_output}); | db.store_file_command(deps.output, {deps.command, deps.command_output}); | ||||
| db.forget_inputs_of(deps.output); | db.forget_inputs_of(deps.output); | ||||
| for (auto&& inp : deps.inputs) { | for (auto&& inp : deps.inputs) { |
| #include <dds/util/fs.hpp> | #include <dds/util/fs.hpp> | ||||
| #include <string> | #include <string> | ||||
| #include <vector> | |||||
| #include <string_view> | #include <string_view> | ||||
| #include <vector> | |||||
| namespace dds { | namespace dds { | ||||
| enum class deps_mode { | |||||
| enum class file_deps_mode { | |||||
| none, | none, | ||||
| msvc, | msvc, | ||||
| gnu, | gnu, | ||||
| }; | }; | ||||
| struct deps_info { | |||||
| struct file_deps_info { | |||||
| fs::path output; | fs::path output; | ||||
| std::vector<fs::path> inputs; | std::vector<fs::path> inputs; | ||||
| std::string command; | std::string command; | ||||
| class database; | class database; | ||||
| deps_info parse_mkfile_deps_file(path_ref where); | |||||
| deps_info parse_mkfile_deps_str(std::string_view str); | |||||
| file_deps_info parse_mkfile_deps_file(path_ref where); | |||||
| file_deps_info parse_mkfile_deps_str(std::string_view str); | |||||
| struct msvc_deps_info { | struct msvc_deps_info { | ||||
| struct deps_info deps_info; | |||||
| std::string cleaned_output; | |||||
| struct file_deps_info deps_info; | |||||
| std::string cleaned_output; | |||||
| }; | }; | ||||
| msvc_deps_info parse_msvc_output_for_deps(std::string_view output, std::string_view leader); | 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 file_deps_info&); | |||||
| struct deps_rebuild_info { | struct deps_rebuild_info { | ||||
| std::vector<fs::path> newer_inputs; | std::vector<fs::path> newer_inputs; |
| #include <dds/build/deps.hpp> | |||||
| #include <dds/build/file_deps.hpp> | |||||
| #include <catch2/catch.hpp> | #include <catch2/catch.hpp> | ||||
| CHECK(new_output == "\nOther line\n indented line\nSomething else\n"); | CHECK(new_output == "\nOther line\n indented line\nSomething else\n"); | ||||
| CHECK(deps.inputs | CHECK(deps.inputs | ||||
| == std::vector<dds::fs::path>({ | == 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", | |||||
| })); | |||||
| "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", | |||||
| })); | |||||
| } | } |
| #pragma once | #pragma once | ||||
| #include <dds/sdist.hpp> | |||||
| #include <dds/toolchain/toolchain.hpp> | #include <dds/toolchain/toolchain.hpp> | ||||
| #include <dds/util/fs.hpp> | #include <dds/util/fs.hpp> | ||||
| #include <dds/sdist.hpp> | |||||
| #include <optional> | #include <optional> | ||||
| #include "./compile_exec.hpp" | #include "./compile_exec.hpp" | ||||
| #include <dds/build/deps.hpp> | |||||
| #include <dds/build/file_deps.hpp> | |||||
| #include <dds/proc.hpp> | #include <dds/proc.hpp> | ||||
| #include <dds/util/string.hpp> | #include <dds/util/string.hpp> | ||||
| #include <dds/util/time.hpp> | #include <dds/util/time.hpp> | ||||
| * @param env The build environment | * @param env The build environment | ||||
| * @param counter A thread-safe counter for display progress to the user | * @param counter A thread-safe counter for display progress to the user | ||||
| */ | */ | ||||
| std::optional<deps_info> | |||||
| std::optional<file_deps_info> | |||||
| do_compile(const compile_file_full& cf, build_env_ref env, compile_counter& counter) { | do_compile(const compile_file_full& cf, build_env_ref env, compile_counter& counter) { | ||||
| // Create the parent directory | // Create the parent directory | ||||
| fs::create_directories(cf.object_file_path.parent_path()); | fs::create_directories(cf.object_file_path.parent_path()); | ||||
| std::string compiler_output = std::move(proc_res.output); | std::string compiler_output = std::move(proc_res.output); | ||||
| // Build dependency information, if applicable to the toolchain | // Build dependency information, if applicable to the toolchain | ||||
| std::optional<deps_info> ret_deps_info; | |||||
| std::optional<file_deps_info> ret_deps_info; | |||||
| if (env.toolchain.deps_mode() == deps_mode::gnu) { | |||||
| if (env.toolchain.deps_mode() == file_deps_mode::gnu) { | |||||
| // GNU-style deps using Makefile generation | // GNU-style deps using Makefile generation | ||||
| assert(cf.cmd_info.gnu_depfile_path.has_value()); | assert(cf.cmd_info.gnu_depfile_path.has_value()); | ||||
| auto& df_path = *cf.cmd_info.gnu_depfile_path; | auto& df_path = *cf.cmd_info.gnu_depfile_path; | ||||
| dep_info.command_output = compiler_output; | dep_info.command_output = compiler_output; | ||||
| ret_deps_info = std::move(dep_info); | ret_deps_info = std::move(dep_info); | ||||
| } | } | ||||
| } else if (env.toolchain.deps_mode() == deps_mode::msvc) { | |||||
| } else if (env.toolchain.deps_mode() == file_deps_mode::msvc) { | |||||
| // Uglier deps generation by parsing the output from cl.exe | // Uglier deps generation by parsing the output from cl.exe | ||||
| /// TODO: Handle different #include Note: prefixes, since those are localized | /// TODO: Handle different #include Note: prefixes, since those are localized | ||||
| auto msvc_deps = parse_msvc_output_for_deps(compiler_output, "Note: including file:"); | auto msvc_deps = parse_msvc_output_for_deps(compiler_output, "Note: including file:"); | ||||
| compile_counter counter{{1}, total, max_digits}; | compile_counter counter{{1}, total, max_digits}; | ||||
| // Ass we execute, accumulate new dependency information from successful compilations | // Ass we execute, accumulate new dependency information from successful compilations | ||||
| std::vector<deps_info> all_new_deps; | |||||
| std::mutex mut; | |||||
| std::vector<file_deps_info> all_new_deps; | |||||
| std::mutex mut; | |||||
| // Do it! | // Do it! | ||||
| auto okay = parallel_run(each_realized, njobs, [&](const compile_file_full& full) { | auto okay = parallel_run(each_realized, njobs, [&](const compile_file_full& full) { | ||||
| auto new_dep = do_compile(full, env, counter); | auto new_dep = do_compile(full, env, counter); |
| bool is_msvc = compiler_id_e == msvc; | bool is_msvc = compiler_id_e == msvc; | ||||
| bool is_gnu_like = is_gnu || is_clang; | bool is_gnu_like = is_gnu || is_clang; | ||||
| const enum deps_mode deps_mode = [&] { | |||||
| const enum file_deps_mode deps_mode = [&] { | |||||
| if (!deps_mode_str.has_value()) { | if (!deps_mode_str.has_value()) { | ||||
| if (is_gnu_like) { | if (is_gnu_like) { | ||||
| return deps_mode::gnu; | |||||
| return file_deps_mode::gnu; | |||||
| } else if (is_msvc) { | } else if (is_msvc) { | ||||
| return deps_mode::msvc; | |||||
| return file_deps_mode::msvc; | |||||
| } else { | } else { | ||||
| return deps_mode::none; | |||||
| return file_deps_mode::none; | |||||
| } | } | ||||
| } else if (deps_mode_str == "GNU") { | } else if (deps_mode_str == "GNU") { | ||||
| return deps_mode::gnu; | |||||
| return file_deps_mode::gnu; | |||||
| } else if (deps_mode_str == "MSVC") { | } else if (deps_mode_str == "MSVC") { | ||||
| return deps_mode::msvc; | |||||
| return file_deps_mode::msvc; | |||||
| } else if (deps_mode_str == "None") { | } else if (deps_mode_str == "None") { | ||||
| return deps_mode::none; | |||||
| return file_deps_mode::none; | |||||
| } else { | } else { | ||||
| fail(context, "Unknown Deps-Mode '{}'", *deps_mode_str); | fail(context, "Unknown Deps-Mode '{}'", *deps_mode_str); | ||||
| } | } |
| #pragma once | #pragma once | ||||
| #include <dds/build/deps.hpp> | |||||
| #include <dds/build/file_deps.hpp> | |||||
| #include <string> | #include <string> | ||||
| #include <vector> | #include <vector> | ||||
| std::string exe_prefix; | std::string exe_prefix; | ||||
| std::string exe_suffix; | std::string exe_suffix; | ||||
| enum deps_mode deps_mode; | |||||
| enum file_deps_mode deps_mode; | |||||
| toolchain realize() const; | toolchain realize() const; | ||||
| }; | }; |
| std::optional<fs::path> gnu_depfile_path; | std::optional<fs::path> gnu_depfile_path; | ||||
| if (_deps_mode == deps_mode::gnu) { | |||||
| if (_deps_mode == file_deps_mode::gnu) { | |||||
| gnu_depfile_path = spec.out_path; | gnu_depfile_path = spec.out_path; | ||||
| gnu_depfile_path->replace_extension(gnu_depfile_path->extension().string() + ".d"); | gnu_depfile_path->replace_extension(gnu_depfile_path->extension().string() + ".d"); | ||||
| extend(flags, | extend(flags, | ||||
| std::string_view(gnu_depfile_path->string()), | std::string_view(gnu_depfile_path->string()), | ||||
| "-MT"sv, | "-MT"sv, | ||||
| std::string_view(spec.out_path.string())}); | std::string_view(spec.out_path.string())}); | ||||
| } else if (_deps_mode == deps_mode::msvc) { | |||||
| } else if (_deps_mode == file_deps_mode::msvc) { | |||||
| flags.push_back("/showIncludes"); | flags.push_back("/showIncludes"); | ||||
| } | } | ||||
| } | } | ||||
| #define CXX_VER_TAG(str, version) \ | #define CXX_VER_TAG(str, version) \ | ||||
| if (starts_with(tc_id, str)) { \ | |||||
| if (starts_with(tc_id, str)) { \ | |||||
| tc_id = tc_id.substr(std::string_view(str).length()); \ | tc_id = tc_id.substr(std::string_view(str).length()); \ | ||||
| tc_content += "C++-Version: "s + version + "\n"; \ | |||||
| tc_content += "C++-Version: "s + version + "\n"; \ | |||||
| } \ | } \ | ||||
| static_assert(true) | static_assert(true) | ||||
| #pragma once | #pragma once | ||||
| #include <dds/build/deps.hpp> | |||||
| #include <dds/build/file_deps.hpp> | |||||
| #include <dds/util/fs.hpp> | #include <dds/util/fs.hpp> | ||||
| #include <optional> | #include <optional> | ||||
| std::string _exe_prefix; | std::string _exe_prefix; | ||||
| std::string _exe_suffix; | std::string _exe_suffix; | ||||
| enum deps_mode _deps_mode; | |||||
| enum file_deps_mode _deps_mode; | |||||
| public: | public: | ||||
| toolchain() = default; | toolchain() = default; |