diff options
Diffstat (limited to 'gcc')
| -rw-r--r-- | gcc/gcc/elna-module-loader.cc | 192 | ||||
| -rw-r--r-- | gcc/gcc/elna1.cc | 29 | ||||
| -rw-r--r-- | gcc/lang-specs.h | 11 | ||||
| -rw-r--r-- | gcc/lang.opt | 32 |
4 files changed, 258 insertions, 6 deletions
diff --git a/gcc/gcc/elna-module-loader.cc b/gcc/gcc/elna-module-loader.cc index 5852bbe..c32b614 100644 --- a/gcc/gcc/elna-module-loader.cc +++ b/gcc/gcc/elna-module-loader.cc @@ -18,14 +18,171 @@ along with GCC; see the file COPYING3. If not see #include "elna/gcc/elna-module-loader.h" #include <fstream> +#include <iostream> +#include <sstream> +#include <unordered_set> #include "elna/gcc/elna-builtins.h" #include "elna/gcc/elna-diagnostic.h" #include "elna/gcc/elna-generic.h" +#include "options.h" + namespace elna::gcc { std::vector<std::string> elna_include_dirs; + dependency_options elna_deps_options; + + std::string munge_make_string(const std::string_view str, const bool is_target) + { + std::string result; + result.reserve(str.size() * 2); + size_t slashes = 0; + + for (const char character : str) + { + switch (character) + { + case '\\': + slashes++; + break; + case '$': + result.push_back('$'); + slashes = 0; + break; + case ' ': + case '\t': + for (size_t i = 0; i <= slashes; i++) + { + result.push_back('\\'); + } + slashes = 0; + break; + case '#': + result.push_back('\\'); + slashes = 0; + break; + case ':': + if (is_target) + { + result.push_back('\\'); + } + slashes = 0; + break; + default: + slashes = 0; + break; + } + result.push_back(character); + } + return result; + } + + static void write_dependency_name(std::ostream& stream, const std::string_view name, + size_t& column, const size_t max_column = 72) + { + const size_t name_length = name.size(); + + if (column > 0) + { + if (max_column > 0 && column + 1 + name_length > max_column) + { + stream << " \\\n "; + column = 1; + } + else + { + stream << ' '; + column++; + } + } + stream << name; + column += name_length; + } + + static void emit_dependencies(const std::filesystem::path& input_file, + const std::vector<std::filesystem::path>& dependencies) + { + std::string target_name; + + if (!elna_deps_options.targets.empty()) + { + for (size_t i = 0; i < elna_deps_options.targets.size(); i++) + { + if (i > 0) + { + target_name += ' '; + } + target_name += elna_deps_options.targets[i]; + } + } + else + { + target_name = munge_make_string(input_file.stem().string() + ".o", true); + } + + std::ostringstream buffer; + size_t column = 0; + + write_dependency_name(buffer, target_name, column); + buffer << ':'; + column++; + + write_dependency_name(buffer, munge_make_string(input_file.string(), false), column); + + std::unordered_set<std::string> seen; + seen.insert(input_file.string()); + + std::vector<std::string> phony_deps; + + for (const auto& dep : dependencies) + { + const std::string dep_str = dep.string(); + if (seen.insert(dep_str).second) + { + write_dependency_name(buffer, munge_make_string(dep_str, false), column); + if (elna_deps_options.phony) + { + phony_deps.push_back(dep_str); + } + } + } + buffer << '\n'; + + if (elna_deps_options.phony) + { + for (const auto& dep_str : phony_deps) + { + buffer << munge_make_string(dep_str, false) << ":\n"; + } + } + + if (!elna_deps_options.output_file.empty()) + { + std::ofstream file(elna_deps_options.output_file); + if (!file.is_open()) + { + fatal_error(UNKNOWN_LOCATION, "Cannot open dependency file %s: %m", + elna_deps_options.output_file.c_str()); + } + file << buffer.str(); + } + else if (elna_deps_options.only_dependencies) + { + fputs(buffer.str().c_str(), stdout); + } + else + { + const std::filesystem::path default_file = input_file.stem().replace_extension(".d"); + std::ofstream file(default_file); + if (!file.is_open()) + { + fatal_error(UNKNOWN_LOCATION, "Cannot open dependency file %s: %m", + default_file.string().c_str()); + } + file << buffer.str(); + } + } module_loader::module_loader(const std::shared_ptr<symbol_table>& symbols) : symbols(symbols) @@ -62,6 +219,7 @@ namespace elna::gcc inform(UNKNOWN_LOCATION, " %s", candidate.native().c_str()); } } + this->m_dependencies.push_back(found.front()); return std::filesystem::weakly_canonical(found.front()); } @@ -85,12 +243,34 @@ namespace elna::gcc void compile_files(const char *const *filenames, unsigned int count) { + if (verbose_flag) + { + for (const auto& include_dir : elna_include_dirs) + { + if (!std::filesystem::exists(include_dir)) + { + std::cerr << "ignoring nonexistent directory \"" << include_dir << "\"\n"; + } + } + std::cerr << "#include \"...\" search starts here:\n"; + std::cerr << "#include <...> search starts here:\n"; + for (const auto& include_dir : elna_include_dirs) + { + if (std::filesystem::exists(include_dir)) + { + std::cerr << ' ' << include_dir << '\n'; + } + } + std::cerr << "End of search list.\n"; + } + const boot::target_info target = get_host_target(); boot::dependency_state<std::shared_ptr<symbol_table>> state{ builtin_symbol_table(), target }; module_loader loader{ state.custom }; for (unsigned int i = 0; i < count; i++) { + loader.clear_dependencies(); const std::filesystem::path key = std::filesystem::weakly_canonical(filenames[i]); boot::dependency result = state.compile(key, loader, target); @@ -99,7 +279,17 @@ namespace elna::gcc report_errors(diagnostics); } - if (result.value != nullptr && result.errors.empty()) + if (elna_deps_options.enabled && result.errors.empty()) + { + emit_dependencies(filenames[i], loader.dependencies()); + } + + const bool should_generate_code = !flag_syntax_only + && !elna_deps_options.only_dependencies + && result.value != nullptr + && result.errors.empty(); + + if (should_generate_code) { linemap_add(line_table, LC_ENTER, 0, ggc_strdup(key.native().c_str()), 1); generic_visitor visitor{ state.custom, state.find(key)->second, target }; diff --git a/gcc/gcc/elna1.cc b/gcc/gcc/elna1.cc index 2c43178..35101f1 100644 --- a/gcc/gcc/elna1.cc +++ b/gcc/gcc/elna1.cc @@ -167,8 +167,35 @@ static bool elna_langhook_handle_option( case OPT_I: elna::gcc::elna_include_dirs.emplace_back(arg); return true; - default: + case OPT_M: + case OPT_MM: + elna::gcc::elna_deps_options.enabled = true; + elna::gcc::elna_deps_options.only_dependencies = true; + return true; + case OPT_MD: + case OPT_MMD: + elna::gcc::elna_deps_options.enabled = true; + if (elna::gcc::elna_deps_options.output_file.empty() && arg != nullptr) + { + elna::gcc::elna_deps_options.output_file = arg; + } + return true; + case OPT_MF: + elna::gcc::elna_deps_options.enabled = true; + elna::gcc::elna_deps_options.output_file = arg; return true; + case OPT_MP: + elna::gcc::elna_deps_options.phony = true; + return true; + case OPT_MT: + elna::gcc::elna_deps_options.targets.emplace_back(arg); + return true; + case OPT_MQ: + elna::gcc::elna_deps_options.targets.push_back( + elna::gcc::munge_make_string(arg, true)); + return true; + default: + return false; } } diff --git a/gcc/lang-specs.h b/gcc/lang-specs.h index 5ef06e9..48c3fed 100644 --- a/gcc/lang-specs.h +++ b/gcc/lang-specs.h @@ -21,8 +21,11 @@ along with GCC; see the file COPYING3. If not see "elna1 %i \ %{!Q:-quiet} " DUMPS_OPTIONS("") " %{m*} %{aux-info*} \ %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} \ - %{pg:-p} %{p} %{f*} %{undef} %{I*} \ - %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}} \ - %{fsyntax-only:-o %j} %{-param*} \ - %{!fsyntax-only:%(invoke_as)}", + %{pg:-p} %{p} %{f*} %{undef} %{I*} %{v} \ + %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} \ + %{M} %{MM} %{MF*} %{MP} %{MQ*} %{MT*} \ + %{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}} \ + %{!fsyntax-only:%{!M:%{!MM:%{S:%W{o*}%{!o*:-o %w%b.s}}}}} \ + %{fsyntax-only|M|MM:-o %j} %{-param*} \ + %{!fsyntax-only:%{!M:%{!MM:%(invoke_as)}}}", nullptr, 0, 0}, diff --git a/gcc/lang.opt b/gcc/lang.opt index e8e5920..ffa84a0 100644 --- a/gcc/lang.opt +++ b/gcc/lang.opt @@ -25,3 +25,35 @@ Elna I Elna Joined Separate MissingArgError(missing path after %qs) -I <dir> Add <dir> to the end of the main include path. + +M +Elna +; Documented in C + +MD +Elna Separate NoDriverArg +; Documented in C + +MF +Elna Joined Separate MissingArgError(missing filename after %qs) +; Documented in C + +MM +Elna +; Documented in C + +MMD +Elna Separate NoDriverArg +; Documented in C + +MP +Elna +; Documented in C + +MQ +Elna Joined Separate MissingArgError(missing target after %qs) +; Documented in C + +MT +Elna Joined Separate MissingArgError(missing target after %qs) +; Documented in C |
