| archive_spec ar; | archive_spec ar; | ||||
| ar.input_files = std::move(objects); | ar.input_files = std::move(objects); | ||||
| ar.out_path = env.output_root / calc_archive_file_path(env.toolchain); | ar.out_path = env.output_root / calc_archive_file_path(env.toolchain); | ||||
| auto ar_cmd = env.toolchain.create_archive_command(ar, env.knobs); | |||||
| auto ar_cmd = env.toolchain.create_archive_command(ar, fs::current_path(), env.knobs); | |||||
| // `out_relpath` is purely for the benefit of the user to have a short name | // `out_relpath` is purely for the benefit of the user to have a short name | ||||
| // in the logs | // in the logs |
| extend(spec.external_include_dirs, env.ureqs.include_paths(use)); | extend(spec.external_include_dirs, env.ureqs.include_paths(use)); | ||||
| } | } | ||||
| extend(spec.definitions, _rules.defs()); | extend(spec.definitions, _rules.defs()); | ||||
| return env.toolchain.create_compile_command(spec, env.knobs); | |||||
| return env.toolchain.create_compile_command(spec, dds::fs::current_path(), env.knobs); | |||||
| } | } | ||||
| 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 { |
| std::reverse(spec.inputs.begin(), spec.inputs.end()); | std::reverse(spec.inputs.begin(), spec.inputs.end()); | ||||
| // Do it! | // Do it! | ||||
| const auto link_command = env.toolchain.create_link_executable_command(spec, env.knobs); | |||||
| const auto link_command | |||||
| = env.toolchain.create_link_executable_command(spec, dds::fs::current_path(), env.knobs); | |||||
| fs::create_directories(spec.output.parent_path()); | fs::create_directories(spec.output.parent_path()); | ||||
| auto msg = fmt::format("[{}] Link: {:30}", | auto msg = fmt::format("[{}] Link: {:30}", | ||||
| lib.qualified_name(), | lib.qualified_name(), |
| auto tc = dds::parse_toolchain_json5(tc_content); | auto tc = dds::parse_toolchain_json5(tc_content); | ||||
| dds::compile_file_spec cf; | dds::compile_file_spec cf; | ||||
| cf.source_path = "foo.cpp"; | |||||
| cf.out_path = "foo.o"; | |||||
| auto cf_cmd = tc.create_compile_command(cf, dds::toolchain_knobs{}); | |||||
| cf.source_path = "foo.cpp"; | |||||
| cf.out_path = "foo.o"; | |||||
| auto cf_cmd = tc.create_compile_command(cf, dds::fs::current_path(), dds::toolchain_knobs{}); | |||||
| auto cf_cmd_str = dds::quote_command(cf_cmd.command); | 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, dds::toolchain_knobs{}); | |||||
| cf_cmd_str = dds::quote_command(cf_cmd.command); | |||||
| cf_cmd = tc.create_compile_command(cf, dds::fs::current_path(), dds::toolchain_knobs{}); | |||||
| 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; | ||||
| ar_spec.input_files.push_back("foo.o"); | ar_spec.input_files.push_back("foo.o"); | ||||
| ar_spec.input_files.push_back("bar.o"); | ar_spec.input_files.push_back("bar.o"); | ||||
| ar_spec.out_path = "stuff.a"; | ar_spec.out_path = "stuff.a"; | ||||
| auto ar_cmd = tc.create_archive_command(ar_spec, dds::toolchain_knobs{}); | |||||
| auto ar_cmd_str = dds::quote_command(ar_cmd); | |||||
| auto ar_cmd | |||||
| = tc.create_archive_command(ar_spec, dds::fs::current_path(), dds::toolchain_knobs{}); | |||||
| auto ar_cmd_str = dds::quote_command(ar_cmd); | |||||
| CHECK(ar_cmd_str == expected_ar); | CHECK(ar_cmd_str == expected_ar); | ||||
| dds::link_exe_spec exe_spec; | dds::link_exe_spec exe_spec; | ||||
| exe_spec.inputs.push_back("foo.o"); | exe_spec.inputs.push_back("foo.o"); | ||||
| exe_spec.inputs.push_back("bar.a"); | exe_spec.inputs.push_back("bar.a"); | ||||
| exe_spec.output = "meow.exe"; | exe_spec.output = "meow.exe"; | ||||
| auto exe_cmd = tc.create_link_executable_command(exe_spec, dds::toolchain_knobs{}); | |||||
| auto exe_cmd = tc.create_link_executable_command(exe_spec, | |||||
| dds::fs::current_path(), | |||||
| dds::toolchain_knobs{}); | |||||
| auto exe_cmd_str = dds::quote_command(exe_cmd); | auto exe_cmd_str = dds::quote_command(exe_cmd); | ||||
| CHECK(exe_cmd_str == expected_exe); | CHECK(exe_cmd_str == expected_exe); | ||||
| } | } | ||||
| dds::compile_file_spec cfs; | dds::compile_file_spec cfs; | ||||
| 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, dds::toolchain_knobs{}); | |||||
| auto cmd = tc.create_compile_command(cfs, dds::fs::current_path(), dds::toolchain_knobs{}); | |||||
| CHECK(cmd.command | CHECK(cmd.command | ||||
| == std::vector<std::string>{"g++", | == std::vector<std::string>{"g++", | ||||
| "-fPIC", | "-fPIC", | ||||
| "-ofoo.o"}); | "-ofoo.o"}); | ||||
| cfs.definitions.push_back("FOO=BAR"); | cfs.definitions.push_back("FOO=BAR"); | ||||
| cmd = tc.create_compile_command(cfs, dds::toolchain_knobs{.is_tty = true}); | |||||
| cmd = tc.create_compile_command(cfs, | |||||
| dds::fs::current_path(), | |||||
| dds::toolchain_knobs{.is_tty = true}); | |||||
| CHECK(cmd.command | CHECK(cmd.command | ||||
| == std::vector<std::string>{"g++", | == std::vector<std::string>{"g++", | ||||
| "-fPIC", | "-fPIC", | ||||
| "-ofoo.o"}); | "-ofoo.o"}); | ||||
| cfs.include_dirs.push_back("fake-dir"); | cfs.include_dirs.push_back("fake-dir"); | ||||
| cmd = tc.create_compile_command(cfs, dds::toolchain_knobs{}); | |||||
| cmd = tc.create_compile_command(cfs, dds::fs::current_path(), dds::toolchain_knobs{}); | |||||
| CHECK(cmd.command | CHECK(cmd.command | ||||
| == std::vector<std::string>{"g++", | == std::vector<std::string>{"g++", | ||||
| "-fPIC", | "-fPIC", |
| #include <dds/util/paths.hpp> | #include <dds/util/paths.hpp> | ||||
| #include <dds/util/string.hpp> | #include <dds/util/string.hpp> | ||||
| #include <range/v3/view/transform.hpp> | |||||
| #include <cassert> | #include <cassert> | ||||
| #include <optional> | #include <optional> | ||||
| #include <string> | #include <string> | ||||
| return replace(_def_template, "[def]", s); | return replace(_def_template, "[def]", s); | ||||
| } | } | ||||
| static fs::path shortest_path_from(path_ref file, path_ref base) { | |||||
| auto relative = file.lexically_normal().lexically_proximate(base); | |||||
| auto abs = file.lexically_normal(); | |||||
| if (relative.string().size() > abs.string().size()) { | |||||
| return abs; | |||||
| } else { | |||||
| return relative; | |||||
| } | |||||
| } | |||||
| template <typename R> | |||||
| static auto shortest_path_args(path_ref base, R&& r) { | |||||
| return ranges::views::all(r) // | |||||
| | ranges::views::transform( | |||||
| [base](auto&& path) { return shortest_path_from(path, base).string(); }); // | |||||
| } | |||||
| compile_command_info toolchain::create_compile_command(const compile_file_spec& spec, | compile_command_info toolchain::create_compile_command(const compile_file_spec& spec, | ||||
| path_ref, | |||||
| toolchain_knobs knobs) const noexcept { | toolchain_knobs knobs) const noexcept { | ||||
| using namespace std::literals; | using namespace std::literals; | ||||
| } | } | ||||
| vector<string> toolchain::create_archive_command(const archive_spec& spec, | vector<string> toolchain::create_archive_command(const archive_spec& spec, | ||||
| path_ref cwd, | |||||
| toolchain_knobs) const noexcept { | toolchain_knobs) const noexcept { | ||||
| vector<string> cmd; | vector<string> cmd; | ||||
| auto out_arg = shortest_path_from(spec.out_path, cwd).string(); | |||||
| for (auto& arg : _link_archive) { | for (auto& arg : _link_archive) { | ||||
| if (arg == "[in]") { | if (arg == "[in]") { | ||||
| std::transform(spec.input_files.begin(), | |||||
| spec.input_files.end(), | |||||
| std::back_inserter(cmd), | |||||
| [](auto&& p) { return p.string(); }); | |||||
| extend(cmd, shortest_path_args(cwd, spec.input_files)); | |||||
| } else { | } else { | ||||
| cmd.push_back(replace(arg, "[out]", spec.out_path.string())); | |||||
| cmd.push_back(replace(arg, "[out]", out_arg)); | |||||
| } | } | ||||
| } | } | ||||
| return cmd; | return cmd; | ||||
| } | } | ||||
| vector<string> toolchain::create_link_executable_command(const link_exe_spec& spec, | vector<string> toolchain::create_link_executable_command(const link_exe_spec& spec, | ||||
| path_ref cwd, | |||||
| toolchain_knobs) const noexcept { | toolchain_knobs) const noexcept { | ||||
| vector<string> cmd; | vector<string> cmd; | ||||
| for (auto& arg : _link_exe) { | for (auto& arg : _link_exe) { | ||||
| if (arg == "[in]") { | if (arg == "[in]") { | ||||
| std::transform(spec.inputs.begin(), | |||||
| spec.inputs.end(), | |||||
| std::back_inserter(cmd), | |||||
| [](auto&& p) { return p.string(); }); | |||||
| extend(cmd, shortest_path_args(cwd, spec.inputs)); | |||||
| } else { | } else { | ||||
| cmd.push_back(replace(arg, "[out]", spec.output.string())); | |||||
| cmd.push_back(replace(arg, "[out]", shortest_path_from(spec.output, cwd).string())); | |||||
| } | } | ||||
| } | } | ||||
| return cmd; | return cmd; |
| 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> external_include_args(const fs::path& p) const noexcept; | std::vector<std::string> external_include_args(const fs::path& p) const noexcept; | ||||
| compile_command_info create_compile_command(const compile_file_spec&, | |||||
| toolchain_knobs) const noexcept; | |||||
| std::vector<std::string> create_archive_command(const archive_spec&, | |||||
| toolchain_knobs) const noexcept; | |||||
| compile_command_info | |||||
| create_compile_command(const compile_file_spec&, path_ref cwd, toolchain_knobs) const noexcept; | |||||
| std::vector<std::string> | |||||
| create_archive_command(const archive_spec&, path_ref cwd, toolchain_knobs) const noexcept; | |||||
| std::vector<std::string> create_link_executable_command(const link_exe_spec&, | std::vector<std::string> create_link_executable_command(const link_exe_spec&, | ||||
| path_ref cwd, | |||||
| toolchain_knobs) const noexcept; | toolchain_knobs) const noexcept; | ||||
| static std::optional<toolchain> get_builtin(std::string_view key) noexcept; | static std::optional<toolchain> get_builtin(std::string_view key) noexcept; |