aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gcc/elna-module-loader.cc192
-rw-r--r--gcc/gcc/elna1.cc29
-rw-r--r--gcc/lang-specs.h11
-rw-r--r--gcc/lang.opt32
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