robertoraggi / cplusplus

A compiler front end for the C++ language
https://robertoraggi.github.io/cplusplus/
MIT License
122 stars 12 forks source link

Add "-M" and "-MM" command line options #312

Open mingodad opened 9 months ago

mingodad commented 9 months ago

To help debug I propose to add -M and -MM command line options, I already got an MVP partially working (it's missing extract the filename without path and extension to use as root dependency like src/test.cpp -> test.o and check the last entry in the loop to omit the line continuation), see bellow .

Or maybe drop the line continuation and root dependency and simple dump the filenames.

--------------------------- src/frontend/cxx/cli.cc ---------------------------
index a2f9aa8..795cd68 100644
@@ -132,6 +132,12 @@ std::vector<CLIOptionDescr> options{
     {"-dM", "Print macro definitions in -E mode instead of normal output",
      &CLI::opt_dM},

+    {"-M", "Print dependencies of the main source file",
+     &CLI::opt_M},
+
+    {"-MM", "Print dependencies of the main source file, excluding system path",
+     &CLI::opt_MM},
+
     {"-S", "Only run preprocess and compilation steps", &CLI::opt_S,
      CLIOptionVisibility::kExperimental},

---------------------------- src/frontend/cxx/cli.h ----------------------------
index 6c7d61e..9c7ec57 100644
@@ -54,6 +54,8 @@ class CLI {
   bool opt_ast_dump = false;
   bool opt_ir_dump = false;
   bool opt_dM = false;
+  bool opt_MM = false;
+  bool opt_M = false;
   bool opt_dump_symbols = false;
   bool opt_dump_tokens = false;
   bool opt_E = false;

------------------------- src/frontend/cxx/frontend.cc -------------------------
index 2197050..d51809b 100644
@@ -238,7 +238,7 @@ auto runOnFile(const CLI& cli, const std::string& fileName) -> bool {
   }

   if (auto source = readAll(fileName)) {
-    if (cli.opt_E && !cli.opt_dM) {
+    if (cli.opt_E && !(cli.opt_dM || cli.opt_M || cli.opt_MM)) {
       preprocesor->preprocess(std::move(*source), fileName, output);
       shouldExit = true;
     } else {
@@ -247,6 +247,12 @@ auto runOnFile(const CLI& cli, const std::string& fileName) -> bool {
       if (cli.opt_dM) {
         preprocesor->printMacros(output);
         shouldExit = true;
+      } else if (cli.opt_M) {
+        preprocesor->printDependencies(output, false);
+        shouldExit = true;
+      } else if (cli.opt_MM) {
+        preprocesor->printDependencies(output, true);
+        shouldExit = true;
       } else if (cli.opt_dump_tokens) {
         dumpTokens(cli, unit, output);
         shouldExit = true;

------------------------ src/parser/cxx/preprocessor.cc ------------------------
index 7fc45d0..dbc26d3 100644
@@ -556,6 +556,7 @@ struct Preprocessor::Private {
     if (sourceFiles_.size() >= 4096) {
       cxx_runtime_error("too many source files");
     }
+    //std::cout << "createSourceFile: " << fileName << std::endl;

     const int sourceFileId = static_cast<int>(sourceFiles_.size() + 1);

@@ -2262,6 +2263,22 @@ void Preprocessor::printMacros(std::ostream &out) const {
   }
 }

+void Preprocessor::printDependencies(std::ostream &out, bool noSysPath) const {
+  for (const auto &sourceFile : d->sourceFiles_) {
+    if (noSysPath) {
+      bool isSysPath = false; 
+      for (const auto &sysPath : d->systemIncludePaths_) {
+        if (sourceFile->fileName.find(sysPath) == 0) {
+          isSysPath = true;
+          break;
+        }
+      }
+      if (isSysPath) continue;
+    }
+    out << cxx::format(" {} \\\n", sourceFile->fileName);
+  }
+}
+
 void Preprocessor::getTokenStartPosition(const Token &token, unsigned *line,
                                          unsigned *column,
                                          std::string_view *fileName) const {

------------------------ src/parser/cxx/preprocessor.h ------------------------
index 5585be5..89938a0 100644
@@ -97,6 +97,8 @@ class Preprocessor {

   void printMacros(std::ostream &out) const;

+  void printDependencies(std::ostream &out, bool noSysPath) const;
+
   void getTokenStartPosition(const Token &token, unsigned *line,
                              unsigned *column,
                              std::string_view *fileName) const;
mingodad commented 9 months ago

I finished my MVP and the output matches the clang output (gcc too although gcc uses one space and clang uses two to at the beginning of each filename dependency) see here https://github.com/robertoraggi/cplusplus/pull/313 .

mingodad commented 9 months ago

This is my first step on a more ambitious feature that would dump each included file and show some stats about the context about it:

The idea is also to check if a giving file is attempted to be included more that once globally and if it has #pragma once or guard macro and the external referenced macro values have changed since it's first inclusion emit a warning/error .