#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; |