Browse Source

Add arguments that handle the generation of compile dependency information.

default_compile_flags
vector-of-bool 5 years ago
parent
commit
1fca2fd03f
9 changed files with 117 additions and 33 deletions
  1. +9
    -7
      src/dds/build/plan/compile_file.cpp
  2. +4
    -3
      src/dds/build/plan/compile_file.hpp
  3. +2
    -2
      src/dds/compdb.cpp
  4. +21
    -0
      src/dds/toolchain/deps.hpp
  5. +27
    -3
      src/dds/toolchain/from_dds.cpp
  6. +24
    -15
      src/dds/toolchain/from_dds.test.cpp
  7. +4
    -0
      src/dds/toolchain/prep.hpp
  8. +16
    -2
      src/dds/toolchain/toolchain.cpp
  9. +10
    -1
      src/dds/toolchain/toolchain.hpp

+ 9
- 7
src/dds/build/plan/compile_file.cpp View File



using namespace dds; using namespace dds;


std::vector<std::string> compile_file_plan::generate_compile_command(build_env_ref env) const
noexcept {
compile_command_info compile_file_plan::generate_compile_command(build_env_ref env) const noexcept {
compile_file_spec spec{_source.path, calc_object_file_path(env)}; compile_file_spec spec{_source.path, calc_object_file_path(env)};
spec.enable_warnings = _rules.enable_warnings(); spec.enable_warnings = _rules.enable_warnings();
extend(spec.include_dirs, _rules.include_dirs()); extend(spec.include_dirs, _rules.include_dirs());
return env.toolchain.create_compile_command(spec); return env.toolchain.create_compile_command(spec);
} }


void compile_file_plan::compile(const build_env& env) const {
std::optional<deps_info> compile_file_plan::compile(const build_env& env) const {
const auto obj_path = calc_object_file_path(env); const auto obj_path = calc_object_file_path(env);
fs::create_directories(obj_path.parent_path()); fs::create_directories(obj_path.parent_path());


fs::relative(_source.path, _source.basis_path).string()); fs::relative(_source.path, _source.basis_path).string());


spdlog::info(msg); spdlog::info(msg);
auto cmd = generate_compile_command(env);
auto&& [dur_ms, compile_res] = timed<std::chrono::milliseconds>([&] { return run_proc(cmd); });
auto cmd = generate_compile_command(env);
auto&& [dur_ms, compile_res]
= timed<std::chrono::milliseconds>([&] { return run_proc(cmd.command); });
spdlog::info("{} - {:>7n}ms", msg, dur_ms.count()); spdlog::info("{} - {:>7n}ms", msg, dur_ms.count());


if (!compile_res.okay()) { if (!compile_res.okay()) {
spdlog::error("Compilation failed: {}", _source.path.string()); spdlog::error("Compilation failed: {}", _source.path.string());
spdlog::error("Subcommand FAILED: {}\n{}", quote_command(cmd), compile_res.output);
spdlog::error("Subcommand FAILED: {}\n{}", quote_command(cmd.command), compile_res.output);
throw compile_failure(fmt::format("Compilation failed for {}", _source.path.string())); throw compile_failure(fmt::format("Compilation failed for {}", _source.path.string()));
} }


if (!compile_res.output.empty()) { if (!compile_res.output.empty()) {
spdlog::warn("While compiling file {} [{}]:\n{}", spdlog::warn("While compiling file {} [{}]:\n{}",
_source.path.string(), _source.path.string(),
quote_command(cmd),
quote_command(cmd.command),
compile_res.output); compile_res.output);
} }

return std::nullopt;
} }


fs::path compile_file_plan::calc_object_file_path(const build_env& env) const noexcept { fs::path compile_file_plan::calc_object_file_path(const build_env& env) const noexcept {

+ 4
- 3
src/dds/build/plan/compile_file.hpp View File



#include <dds/build/plan/base.hpp> #include <dds/build/plan/base.hpp>
#include <dds/source.hpp> #include <dds/source.hpp>
#include <dds/toolchain/deps.hpp>


#include <memory> #include <memory>


, _qualifier(qual) , _qualifier(qual)
, _subdir(subdir) {} , _subdir(subdir) {}


std::vector<std::string> generate_compile_command(build_env_ref) const noexcept;
compile_command_info generate_compile_command(build_env_ref) const noexcept;


const source_file& source() const noexcept { return _source; } const source_file& source() const noexcept { return _source; }
path_ref source_path() const noexcept { return _source.path; } path_ref source_path() const noexcept { return _source.path; }


fs::path calc_object_file_path(build_env_ref env) const noexcept;
void compile(build_env_ref) const;
fs::path calc_object_file_path(build_env_ref env) const noexcept;
std::optional<deps_info> compile(build_env_ref) const;
}; };


} // namespace dds } // namespace dds

+ 2
- 2
src/dds/compdb.cpp View File

auto compdb = nlohmann::json::array(); auto compdb = nlohmann::json::array();


for (const compile_file_plan& cf : iter_compilations(plan)) { for (const compile_file_plan& cf : iter_compilations(plan)) {
auto command = cf.generate_compile_command(env);
auto cmd_info = cf.generate_compile_command(env);
auto entry = nlohmann::json::object({ auto entry = nlohmann::json::object({
{"directory", env.output_root.string()}, {"directory", env.output_root.string()},
{"arguments", command},
{"arguments", cmd_info.command},
{"file", cf.source_path().string()}, {"file", cf.source_path().string()},
}); });
compdb.push_back(std::move(entry)); compdb.push_back(std::move(entry));

+ 21
- 0
src/dds/toolchain/deps.hpp View File

#pragma once

#include <dds/util/fs.hpp>

#include <vector>

namespace dds {

enum class deps_mode {
none,
msvc,
gnu,
};

struct deps_info {
fs::path output;
std::vector<fs::path> inputs;
std::vector<std::string> command;
};

} // namespace dds

+ 27
- 3
src/dds/toolchain/from_dds.cpp View File

opt_string obj_suffix; opt_string obj_suffix;
opt_string exe_prefix; opt_string exe_prefix;
opt_string exe_suffix; opt_string exe_suffix;
opt_string deps_mode_str;
optional<bool> do_debug; optional<bool> do_debug;
optional<bool> do_optimize; optional<bool> do_optimize;
opt_str_seq include_template; opt_str_seq include_template;
lm::read_bool("Debug", do_debug), lm::read_bool("Debug", do_debug),
// Miscellaneous // Miscellaneous
read_argv{"Compiler-Launcher", compile_launcher}, read_argv{"Compiler-Launcher", compile_launcher},
lm::read_opt("Deps-Mode", deps_mode_str),
// Command templates // Command templates
read_argv{"C-Compile-File", c_compile_file}, read_argv{"C-Compile-File", c_compile_file},
read_argv{"C++-Compile-File", cxx_compile_file}, read_argv{"C++-Compile-File", cxx_compile_file},
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 = [&] {
if (!deps_mode_str.has_value()) {
if (is_gnu_like) {
return deps_mode::gnu;
} else if (is_msvc) {
return deps_mode::msvc;
} else {
return deps_mode::none;
}
} else if (deps_mode_str == "GNU") {
return deps_mode::gnu;
} else if (deps_mode_str == "MSVC") {
return deps_mode::msvc;
} else if (deps_mode_str == "None") {
return deps_mode::none;
} else {
fail(context, "Unknown Deps-Mode '{}'", *deps_mode_str);
}
}();

// Now convert the flags we've been given into a real toolchain // Now convert the flags we've been given into a real toolchain
auto get_compiler = [&](language lang) -> string { auto get_compiler = [&](language lang) -> string {
if (lang == language::cxx && cxx_compiler_fpath) { if (lang == language::cxx && cxx_compiler_fpath) {
rt_lib = "/MTd"; rt_lib = "/MTd";
} }
ret.emplace_back(rt_lib); ret.emplace_back(rt_lib);
extend(ret, {"/nologo", "<FLAGS>", "/permissive-", "/c", "<IN>", "/Fo<OUT>"});
if (lang == language::cxx) { if (lang == language::cxx) {
extend(ret, {"/EHsc"}); extend(ret, {"/EHsc"});
} }
extend(ret, {"/nologo", "/permissive-", "<FLAGS>", "/c", "<IN>", "/Fo<OUT>"});
} else if (is_gnu_like) { } else if (is_gnu_like) {
if (do_optimize.has_value() && *do_optimize) { if (do_optimize.has_value() && *do_optimize) {
extend(ret, {"-O2"}); extend(ret, {"-O2"});
return ret; return ret;
}; };


tc.deps_mode = deps_mode;

tc.c_compile = read_opt(c_compile_file, [&] { tc.c_compile = read_opt(c_compile_file, [&] {
string_seq c; string_seq c;
if (compile_launcher) { if (compile_launcher) {
} }
if (is_gnu_like) { if (is_gnu_like) {
return {"-I", "<PATH>"}; return {"-I", "<PATH>"};
} else if (compiler_id == "MSVC") {
} else if (is_msvc) {
return {"/I", "<PATH>"}; return {"/I", "<PATH>"};
} }
assert(false && "Include-Template deduction failed"); assert(false && "Include-Template deduction failed");
} }
if (is_gnu_like) { if (is_gnu_like) {
return {"-D", "<DEF>"}; return {"-D", "<DEF>"};
} else if (compiler_id == "MSVC") {
} else if (is_msvc) {
return {"/D", "<DEF>"}; return {"/D", "<DEF>"};
} }
assert(false && "Define-Template deduction failed"); assert(false && "Define-Template deduction failed");

+ 24
- 15
src/dds/toolchain/from_dds.test.cpp View File

cf.source_path = "foo.cpp"; cf.source_path = "foo.cpp";
cf.out_path = "foo.o"; cf.out_path = "foo.o";
auto cf_cmd = tc.create_compile_command(cf); auto cf_cmd = tc.create_compile_command(cf);
auto cf_cmd_str = dds::quote_command(cf_cmd);
auto cf_cmd_str = dds::quote_command(cf_cmd.command);
CHECK(cf_cmd_str == expected_compile); CHECK(cf_cmd_str == expected_compile);


cf.enable_warnings = true; cf.enable_warnings = true;
cf_cmd = tc.create_compile_command(cf); cf_cmd = tc.create_compile_command(cf);
cf_cmd_str = dds::quote_command(cf_cmd);
cf_cmd_str = dds::quote_command(cf_cmd.command);
CHECK(cf_cmd_str == expected_compile_warnings); CHECK(cf_cmd_str == expected_compile_warnings);


dds::archive_spec ar_spec; dds::archive_spec ar_spec;


TEST_CASE("Generating toolchain commands") { TEST_CASE("Generating toolchain commands") {
check_tc_compile("Compiler-ID: GNU", check_tc_compile("Compiler-ID: GNU",
"g++ -fPIC -fdiagnostics-color -pthread -c foo.cpp -ofoo.o",
"g++ -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -c foo.cpp -ofoo.o",
"g++ -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " "g++ -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion "
"-c foo.cpp -ofoo.o",
"-MD -MF foo.o.d -c foo.cpp -ofoo.o",
"ar rcs stuff.a foo.o bar.o", "ar rcs stuff.a foo.o bar.o",
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -lstdc++fs -omeow.exe"); "g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -lstdc++fs -omeow.exe");


check_tc_compile( check_tc_compile(
"Compiler-ID: GNU\nDebug: True", "Compiler-ID: GNU\nDebug: True",
"g++ -g -fPIC -fdiagnostics-color -pthread -c foo.cpp -ofoo.o",
"g++ -g -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -c foo.cpp -ofoo.o",
"g++ -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " "g++ -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion "
"-c foo.cpp -ofoo.o",
"-MD -MF foo.o.d -c foo.cpp -ofoo.o",
"ar rcs stuff.a foo.o bar.o", "ar rcs stuff.a foo.o bar.o",
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -lstdc++fs -omeow.exe -g"); "g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -lstdc++fs -omeow.exe -g");


check_tc_compile( check_tc_compile(
"Compiler-ID: GNU\nDebug: True\nOptimize: True", "Compiler-ID: GNU\nDebug: True\nOptimize: True",
"g++ -O2 -g -fPIC -fdiagnostics-color -pthread -c foo.cpp -ofoo.o",
"g++ -O2 -g -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -c foo.cpp -ofoo.o",
"g++ -O2 -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " "g++ -O2 -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion "
"-c foo.cpp -ofoo.o",
"-MD -MF foo.o.d -c foo.cpp -ofoo.o",
"ar rcs stuff.a foo.o bar.o", "ar rcs stuff.a foo.o bar.o",
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -lstdc++fs -omeow.exe -O2 -g"); "g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -lstdc++fs -omeow.exe -O2 -g");


check_tc_compile("Compiler-ID: MSVC", check_tc_compile("Compiler-ID: MSVC",
"cl.exe /MT /nologo /permissive- /c foo.cpp /Fofoo.o /EHsc",
"cl.exe /MT /nologo /W4 /permissive- /c foo.cpp /Fofoo.o /EHsc",
"cl.exe /MT /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o", "lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT"); "cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT");


check_tc_compile("Compiler-ID: MSVC\nDebug: True", check_tc_compile("Compiler-ID: MSVC\nDebug: True",
"cl.exe /Z7 /DEBUG /MTd /nologo /permissive- /c foo.cpp /Fofoo.o /EHsc",
"cl.exe /Z7 /DEBUG /MTd /nologo /W4 /permissive- /c foo.cpp /Fofoo.o /EHsc",
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o", "lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /Z7 /DEBUG /MTd"); "cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /Z7 /DEBUG /MTd");


cfs.source_path = "foo.cpp"; cfs.source_path = "foo.cpp";
cfs.out_path = "foo.o"; cfs.out_path = "foo.o";
auto cmd = tc.create_compile_command(cfs); auto cmd = tc.create_compile_command(cfs);
CHECK(cmd
CHECK(cmd.command
== std::vector<std::string>{"g++", == std::vector<std::string>{"g++",
"-fPIC", "-fPIC",
"-fdiagnostics-color", "-fdiagnostics-color",
"-pthread", "-pthread",
"-MD",
"-MF",
"foo.o.d",
"-c", "-c",
"foo.cpp", "foo.cpp",
"-ofoo.o"}); "-ofoo.o"});


cfs.definitions.push_back("FOO=BAR"); cfs.definitions.push_back("FOO=BAR");
cmd = tc.create_compile_command(cfs); cmd = tc.create_compile_command(cfs);
CHECK(cmd
CHECK(cmd.command
== std::vector<std::string>{"g++", == std::vector<std::string>{"g++",
"-fPIC", "-fPIC",
"-fdiagnostics-color", "-fdiagnostics-color",
"-pthread", "-pthread",
"-D", "-D",
"FOO=BAR", "FOO=BAR",
"-MD",
"-MF",
"foo.o.d",
"-c", "-c",
"foo.cpp", "foo.cpp",
"-ofoo.o"}); "-ofoo.o"});


cfs.include_dirs.push_back("fake-dir"); cfs.include_dirs.push_back("fake-dir");
cmd = tc.create_compile_command(cfs); cmd = tc.create_compile_command(cfs);
CHECK(cmd
CHECK(cmd.command
== std::vector<std::string>{"g++", == std::vector<std::string>{"g++",
"-fPIC", "-fPIC",
"-fdiagnostics-color", "-fdiagnostics-color",
"fake-dir", "fake-dir",
"-D", "-D",
"FOO=BAR", "FOO=BAR",
"-MD",
"-MF",
"foo.o.d",
"-c", "-c",
"foo.cpp", "foo.cpp",
"-ofoo.o"}); "-ofoo.o"});

+ 4
- 0
src/dds/toolchain/prep.hpp View File

#pragma once #pragma once


#include <dds/toolchain/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;

toolchain realize() const; toolchain realize() const;
}; };



+ 16
- 2
src/dds/toolchain/toolchain.cpp View File

ret._object_suffix = prep.object_suffix; ret._object_suffix = prep.object_suffix;
ret._exe_prefix = prep.exe_prefix; ret._exe_prefix = prep.exe_prefix;
ret._exe_suffix = prep.exe_suffix; ret._exe_suffix = prep.exe_suffix;
ret._deps_mode = prep.deps_mode;
return ret; return ret;
} }


return replace(_def_template, "<DEF>", s); return replace(_def_template, "<DEF>", s);
} }


vector<string> toolchain::create_compile_command(const compile_file_spec& spec) const noexcept {
compile_command_info toolchain::create_compile_command(const compile_file_spec& spec) const
noexcept {
vector<string> flags; vector<string> flags;


using namespace std::literals;

language lang = spec.lang; language lang = spec.lang;
if (lang == language::automatic) { if (lang == language::automatic) {
if (spec.source_path.extension() == ".c" || spec.source_path.extension() == ".C") { if (spec.source_path.extension() == ".c" || spec.source_path.extension() == ".C") {
extend(flags, _warning_flags); extend(flags, _warning_flags);
} }


std::optional<fs::path> gnu_depfile_path;

if (_deps_mode == deps_mode::gnu) {
gnu_depfile_path = spec.out_path;
gnu_depfile_path->replace_extension(gnu_depfile_path->extension().string() + ".d");
extend(flags, {"-MD"sv, "-MF"sv, std::string_view(gnu_depfile_path->string())});
} else if (_deps_mode == deps_mode::msvc) {
flags.push_back("/showIncludes");
}

vector<string> command; vector<string> command;
for (auto arg : cmd_template) { for (auto arg : cmd_template) {
if (arg == "<FLAGS>") { if (arg == "<FLAGS>") {
command.push_back(arg); command.push_back(arg);
} }
} }
return command;
return {command, gnu_depfile_path};
} }


vector<string> toolchain::create_archive_command(const archive_spec& spec) const noexcept { vector<string> toolchain::create_archive_command(const archive_spec& spec) const noexcept {

+ 10
- 1
src/dds/toolchain/toolchain.hpp View File

#pragma once #pragma once


#include <dds/toolchain/deps.hpp>
#include <dds/util/fs.hpp> #include <dds/util/fs.hpp>


#include <optional> #include <optional>
bool enable_warnings = false; bool enable_warnings = false;
}; };


struct compile_command_info {
std::vector<std::string> command;
std::optional<fs::path> gnu_depfile_path;
};

struct archive_spec { struct archive_spec {
std::vector<fs::path> input_files; std::vector<fs::path> input_files;
fs::path out_path; fs::path out_path;
std::string _exe_prefix; std::string _exe_prefix;
std::string _exe_suffix; std::string _exe_suffix;


enum deps_mode _deps_mode;

public: public:
toolchain() = default; toolchain() = default;


auto& archive_suffix() const noexcept { return _archive_suffix; } auto& archive_suffix() const noexcept { return _archive_suffix; }
auto& object_suffix() const noexcept { return _object_suffix; } auto& object_suffix() const noexcept { return _object_suffix; }
auto& executable_suffix() const noexcept { return _exe_suffix; } auto& executable_suffix() const noexcept { return _exe_suffix; }
auto deps_mode() const noexcept { return _deps_mode; }


std::vector<std::string> definition_args(std::string_view s) const noexcept; std::vector<std::string> definition_args(std::string_view s) const noexcept;
std::vector<std::string> include_args(const fs::path& p) const noexcept; std::vector<std::string> include_args(const fs::path& p) const noexcept;
std::vector<std::string> create_compile_command(const compile_file_spec&) const noexcept;
compile_command_info create_compile_command(const compile_file_spec&) const noexcept;
std::vector<std::string> create_archive_command(const archive_spec&) const noexcept; std::vector<std::string> create_archive_command(const archive_spec&) const noexcept;
std::vector<std::string> create_link_executable_command(const link_exe_spec&) const noexcept; std::vector<std::string> create_link_executable_command(const link_exe_spec&) const noexcept;



Loading…
Cancel
Save