diff --git a/src/DynareMain.cc b/src/DynareMain.cc
index 37990b86b130ef92aa96bb674ddeb256070c2fae..06a1e547ded9cd767f4e1524d4b167169261408a 100644
--- a/src/DynareMain.cc
+++ b/src/DynareMain.cc
@@ -52,7 +52,8 @@ void main2(stringstream &in, const string &basename, bool debug, bool clear_all,
            const filesystem::path &dynareroot, bool onlymodel);
 
 void main1(const string &filename, const string &basename, istream &modfile, bool debug, bool save_macro, string &save_macro_file,
-           bool no_line_macro, bool no_empty_line_macro, const vector<pair<string, string>> &defines, const vector<string> &path, stringstream &macro_output);
+           bool no_line_macro, bool no_empty_line_macro, const vector<pair<string, string>> &defines,
+           vector<filesystem::path> &paths, stringstream &macro_output);
 
 void
 usage()
@@ -155,7 +156,7 @@ main(int argc, char **argv)
   bool compute_xrefs = false;
   bool transform_unary_ops = false;
   vector<pair<string, string>> defines;
-  vector<string> path;
+  vector<filesystem::path> paths;
   FileOutputType output_mode{FileOutputType::none};
   JsonOutputPointType json{JsonOutputPointType::nojson};
   JsonFileOutputType json_output_mode{JsonFileOutputType::file};
@@ -284,7 +285,7 @@ main(int argc, char **argv)
                    << "must not be separated from -I by whitespace." << endl;
               usage();
             }
-          path.push_back(s.substr(2));
+          paths.push_back(s.substr(2));
         }
       else if (s.substr(0, 6) == "output")
         {
@@ -409,12 +410,12 @@ main(int argc, char **argv)
   // it to paths before macroprocessing
   vector<string> config_include_paths = config_file.getIncludePaths();
   for (const auto &it : config_include_paths)
-    path.push_back(it);
+    paths.emplace_back(it);
 
   // Do macro processing
   stringstream macro_output;
   main1(filename, basename, modfile, debug, save_macro, save_macro_file, no_line_macro, no_empty_line_macro,
-        defines, path, macro_output);
+        defines, paths, macro_output);
 
   if (only_macro)
     return EXIT_SUCCESS;
diff --git a/src/DynareMain1.cc b/src/DynareMain1.cc
index 7b44da8c9697bc306ec37d0b94d7abbe4428c53e..621d178e128c05d9ff666a28138e923243d6548c 100644
--- a/src/DynareMain1.cc
+++ b/src/DynareMain1.cc
@@ -19,6 +19,7 @@
 
 #include <sstream>
 #include <fstream>
+#include <filesystem>
 
 #include "macro/Driver.hh"
 
@@ -28,14 +29,13 @@ bool compareNewline (int i, int j) {
 
 void
 main1(const string &filename, const string &basename, istream &modfile, bool debug, bool save_macro, string &save_macro_file,
-      bool no_line_macro_arg, bool no_empty_line_macro, const vector<pair<string, string>> &defines, const vector<string> &path,
-      stringstream &macro_output)
+      bool no_line_macro_arg, bool no_empty_line_macro, const vector<pair<string, string>> &defines,
+      vector<filesystem::path> &paths, stringstream &macro_output)
 {
   // Do macro processing
   macro::Environment env = macro::Environment();
-  vector<string> paths;
-  macro::Driver m(env, paths, no_line_macro_arg);
-  m.parse(filename, basename, modfile, macro_output, debug, defines, path);
+  macro::Driver m(env, no_line_macro_arg);
+  m.parse(filename, basename, modfile, macro_output, debug, defines, paths);
   if (save_macro)
     {
       if (save_macro_file.empty())
diff --git a/src/macro/Directives.cc b/src/macro/Directives.cc
index b7c09e74d8655801049a17d7a3656f4f8745b497..899399b6e1fd6afaabc65d578c65f018d68bf295 100644
--- a/src/macro/Directives.cc
+++ b/src/macro/Directives.cc
@@ -25,7 +25,7 @@
 using namespace macro;
 
 void
-Eval::interpret(ostream &output, bool no_line_macro)
+Eval::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   try
     {
@@ -43,44 +43,37 @@ Eval::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-Include::interpret(ostream &output, bool no_line_macro)
+Include::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
-#ifdef _WIN32
-  string FILESEP = "\\";
-#else
-  string FILESEP = "/";
-#endif
+  using namespace filesystem;
   try
     {
       StringPtr msp = dynamic_pointer_cast<String>(expr->eval());
       if (!msp)
         throw StackTrace("File name does not evaluate to a string");
-      string filename = msp->to_string();
+      path filename = msp->to_string();
       ifstream incfile(filename, ios::binary);
       if (incfile.fail())
         {
-          ostringstream dirs;
-          dirs << "." << FILESEP << endl;
-          for (const auto & path : paths)
+          for (auto file : paths)
             {
-              string testfile = path + FILESEP + filename;
-              incfile = ifstream(testfile, ios::binary);
+              file /= filename;
+              incfile = ifstream(file, ios::binary);
               if (incfile.good())
                 break;
-              dirs << path << endl;
             }
           if (incfile.fail())
-            error(StackTrace("@#includepath", "Could not open " + filename +
-                             ". The following directories were searched:\n" + dirs.str(), location));
+            {
+              ostringstream errmsg;
+              errmsg << "   * " << current_path().string() << endl;
+              for (auto & dir : paths)
+                errmsg << "   * " << absolute(dir).string() << endl;
+              error(StackTrace("@#includepath", "Could not open " + filename.string() +
+                               ". The following directories were searched:\n" + errmsg.str(), location));
+            }
         }
-
-      string basename = filename;
-      size_t pos = basename.find_last_of('.');
-      if (pos != string::npos)
-        basename.erase(pos);
-
-      Driver m(env, paths, no_line_macro);
-      m.parse(filename, basename, incfile, output, false, vector<pair<string, string>>{}, paths);
+      Driver m(env, no_line_macro);
+      m.parse(filename, filename.stem(), incfile, output, false, vector<pair<string, string>>{}, paths);
     }
   catch (StackTrace &ex)
     {
@@ -94,13 +87,19 @@ Include::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-IncludePath::interpret(ostream &output, bool no_line_macro)
+IncludePath::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
+  using namespace filesystem;
   try
     {
       StringPtr msp = dynamic_pointer_cast<String>(expr->eval());
       if (!msp)
         throw StackTrace("File name does not evaluate to a string");
+      path ip = static_cast<string>(*msp);
+      if (!is_directory(ip))
+        throw StackTrace(ip.string() + " does not evaluate to a valid directory");
+      if (!exists(ip))
+        warning(StackTrace("@#includepath", ip.string() + " does not exist", location));
       paths.emplace_back(*msp);
     }
   catch (StackTrace &ex)
@@ -115,7 +114,7 @@ IncludePath::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-Define::interpret(ostream &output, bool no_line_macro)
+Define::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   try
     {
@@ -138,7 +137,7 @@ Define::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-Echo::interpret(ostream &output, bool no_line_macro)
+Echo::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   try
     {
@@ -157,7 +156,7 @@ Echo::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-Error::interpret(ostream &output, bool no_line_macro)
+Error::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   try
     {
@@ -175,7 +174,7 @@ Error::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-EchoMacroVars::interpret(ostream &output, bool no_line_macro)
+EchoMacroVars::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   if (save)
     env.print(output, vars, location.begin.line, true);
@@ -185,7 +184,7 @@ EchoMacroVars::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-For::interpret(ostream &output, bool no_line_macro)
+For::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   ArrayPtr ap;
   try
@@ -234,14 +233,14 @@ For::interpret(ostream &output, bool no_line_macro)
               statement->printLineInfo(output, no_line_macro);
               printLine = false;
             }
-          statement->interpret(output, no_line_macro);
+          statement->interpret(output, no_line_macro, paths);
         }
     }
   printEndLineInfo(output, no_line_macro);
 }
 
 void
-If::interpret(ostream &output, bool no_line_macro)
+If::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   for (auto & it : expr_and_body)
     try
@@ -254,7 +253,7 @@ If::interpret(ostream &output, bool no_line_macro)
                            "The condition must evaluate to a boolean or a double", location));
         if ((bp && *bp) || (dp && *dp))
           {
-            interpretBody(it.second, output, no_line_macro);
+            interpretBody(it.second, output, no_line_macro, paths);
             break;
           }
       }
@@ -271,7 +270,7 @@ If::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-If::interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro)
+If::interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   bool printLine = !no_line_macro;
   for (auto & statement : body)
@@ -281,12 +280,12 @@ If::interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_lin
           statement->printLineInfo(output, no_line_macro);
           printLine = false;
         }
-      statement->interpret(output, no_line_macro);
+      statement->interpret(output, no_line_macro, paths);
     }
 }
 
 void
-Ifdef::interpret(ostream &output, bool no_line_macro)
+Ifdef::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   for (auto & it : expr_and_body)
     {
@@ -294,7 +293,7 @@ Ifdef::interpret(ostream &output, bool no_line_macro)
       if (dynamic_pointer_cast<BaseType>(it.first)
           || (vp && env.isVariableDefined(vp->getName())))
         {
-          interpretBody(it.second, output, no_line_macro);
+          interpretBody(it.second, output, no_line_macro, paths);
           break;
         }
     }
@@ -302,7 +301,7 @@ Ifdef::interpret(ostream &output, bool no_line_macro)
 }
 
 void
-Ifndef::interpret(ostream &output, bool no_line_macro)
+Ifndef::interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths)
 {
   for (auto & it : expr_and_body)
     {
@@ -310,7 +309,7 @@ Ifndef::interpret(ostream &output, bool no_line_macro)
       if (!(dynamic_pointer_cast<BaseType>(it.first)
             || (vp && env.isVariableDefined(vp->getName()))))
         {
-          interpretBody(it.second, output, no_line_macro);
+          interpretBody(it.second, output, no_line_macro, paths);
           break;
         }
     }
diff --git a/src/macro/Directives.hh b/src/macro/Directives.hh
index 045caa6a6733e365c2b527901a906460f97cb94c..d3cb71479dd40830e79d6a98108bd66a14739f6e 100644
--- a/src/macro/Directives.hh
+++ b/src/macro/Directives.hh
@@ -22,6 +22,8 @@
 
 #include "Expressions.hh"
 
+#include <filesystem>
+
 namespace macro
 {
   class Directive : public Node
@@ -30,7 +32,7 @@ namespace macro
   public:
     Directive(Environment &env_arg, Tokenizer::location location_arg) : Node(env_arg, move(location_arg)) { }
     // Directives can be interpreted
-    virtual void interpret(ostream &output, bool no_line_macro) = 0;
+    virtual void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) = 0;
   };
 
 
@@ -44,7 +46,7 @@ namespace macro
   public:
     TextNode(string text_arg, Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), text{move(text_arg)} { }
-    inline void interpret(ostream &output, bool no_line_macro) override { output << text; }
+    inline void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override { output << text; }
   };
 
 
@@ -58,7 +60,7 @@ namespace macro
   public:
     Eval(ExpressionPtr expr_arg, Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -66,11 +68,10 @@ namespace macro
   {
   private:
     const ExpressionPtr expr;
-    vector<string> &paths;
   public:
-    Include(ExpressionPtr expr_arg, Environment &env_arg, vector<string> &paths_arg, Tokenizer::location location_arg) :
-      Directive(env_arg, move(location_arg)), expr{move(expr_arg)}, paths{paths_arg} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    Include(ExpressionPtr expr_arg, Environment &env_arg, Tokenizer::location location_arg) :
+      Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -78,11 +79,10 @@ namespace macro
   {
   private:
     const ExpressionPtr expr;
-    vector<string> &paths;
   public:
-    IncludePath(ExpressionPtr expr_arg, Environment &env_arg, vector<string> &paths_arg, Tokenizer::location location_arg) :
-      Directive(env_arg, move(location_arg)), expr{move(expr_arg)}, paths{paths_arg} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    IncludePath(ExpressionPtr expr_arg, Environment &env_arg, Tokenizer::location location_arg) :
+      Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -101,7 +101,7 @@ namespace macro
            ExpressionPtr value_arg,
            Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), func{move(func_arg)}, value{move(value_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -113,7 +113,7 @@ namespace macro
     Echo(ExpressionPtr expr_arg,
          Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -125,7 +125,7 @@ namespace macro
     Error(ExpressionPtr expr_arg,
           Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -141,7 +141,7 @@ namespace macro
     EchoMacroVars(bool save_arg, vector<string> vars_arg,
                   Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), save{save_arg}, vars{move(vars_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -158,7 +158,7 @@ namespace macro
         Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), index_vec{move(index_vec_arg)},
       index_vals{move(index_vals_arg)}, statements{move(statements_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -178,9 +178,9 @@ namespace macro
     If(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
        Environment &env_arg, Tokenizer::location location_arg) :
       Directive(env_arg, move(location_arg)), expr_and_body{move(expr_and_body_arg)} { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   protected:
-    void interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro);
+    void interpretBody(const vector<DirectivePtr> &body, ostream &output, bool no_line_macro, vector<filesystem::path> &paths);
   };
 
 
@@ -190,7 +190,7 @@ namespace macro
     Ifdef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
           Environment &env_arg, Tokenizer::location location_arg) :
       If(move(expr_and_body_arg), env_arg, move(location_arg)) { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 
 
@@ -200,7 +200,7 @@ namespace macro
     Ifndef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
            Environment &env_arg, Tokenizer::location location_arg) :
       If(move(expr_and_body_arg), env_arg, move(location_arg)) { }
-    void interpret(ostream &output, bool no_line_macro) override;
+    void interpret(ostream &output, bool no_line_macro, vector<filesystem::path> &paths) override;
   };
 }
 #endif
diff --git a/src/macro/Driver.cc b/src/macro/Driver.cc
index 49553d1a916ca4b7ee3413c56e2dda458f536334..2661091afd429fd069438f6a9f0bd547c5b489e8 100644
--- a/src/macro/Driver.cc
+++ b/src/macro/Driver.cc
@@ -24,11 +24,10 @@ using namespace macro;
 void
 Driver::parse(const string &file_arg, const string &basename_arg, istream &modfile,
               ostream &output, bool debug, const vector<pair<string, string>> &defines,
-              vector<string> paths_arg)
+              vector<filesystem::path> &paths)
 {
   file = file_arg;
   basename = basename_arg;
-  paths = move(paths_arg);
 
   if (!defines.empty())
     {
@@ -47,7 +46,7 @@ Driver::parse(const string &file_arg, const string &basename_arg, istream &modfi
             else
               command_line_defines_with_endl << "@#define " << define.first << " = \"" << define.second << "\"" << endl;
           }
-      Driver m(env, paths, true);
+      Driver m(env, true);
       istream is(command_line_defines_with_endl.rdbuf());
       m.parse("command_line_defines", "command_line_defines", is, output, debug, vector<pair<string, string>>{}, paths);
     }
@@ -72,7 +71,7 @@ Driver::parse(const string &file_arg, const string &basename_arg, istream &modfi
           statement->printLineInfo(output, no_line_macro);
           printLine = false;
         }
-      statement->interpret(output, no_line_macro);
+      statement->interpret(output, no_line_macro, paths);
     }
 }
 
diff --git a/src/macro/Driver.hh b/src/macro/Driver.hh
index 26d5ea7280e565cfb56c0ea3eed071b18293690f..c6997cdedfa57fbc85eab29d8c43565855955d01 100644
--- a/src/macro/Driver.hh
+++ b/src/macro/Driver.hh
@@ -29,6 +29,7 @@
 #include "Expressions.hh"
 
 #include <stack>
+#include <filesystem>
 
 // Declare TokenizerFlexLexer class
 #ifndef __FLEX_LEXER_H
@@ -63,15 +64,13 @@ namespace macro
   {
   public:
     Environment &env;
-    //! The paths to search when looking for .mod files
-    vector<string> &paths;
   private:
     bool no_line_macro;
     vector<DirectivePtr> statements;
     stack<vector<DirectivePtr>> directive_stack;
   public:
-    Driver(Environment &env_arg, vector<string> &paths_arg, bool no_line_macro_arg) :
-      env{env_arg}, paths{paths_arg}, no_line_macro(no_line_macro_arg) { }
+    Driver(Environment &env_arg, bool no_line_macro_arg) :
+      env{env_arg}, no_line_macro(no_line_macro_arg) { }
     Driver(const Driver &) = delete;
     Driver(Driver &&) = delete;
     Driver & operator=(const Driver &) = delete;
@@ -90,7 +89,7 @@ namespace macro
     //! Starts parsing a file, returns output in out
     void parse(const string &file_arg, const string &basename_arg, istream &modfile,
                ostream &output, bool debug, const vector<pair<string, string>> &defines,
-               vector<string> paths_arg);
+               vector<filesystem::path> &paths_arg);
 
     //! Name of main file being parsed
     string file;
diff --git a/src/macro/Expressions.hh b/src/macro/Expressions.hh
index a82607001e51aa3f60886260123c18cb9081bd31..fdc3843a78a8b76610eb1dddf26096ac3416110e 100644
--- a/src/macro/Expressions.hh
+++ b/src/macro/Expressions.hh
@@ -94,6 +94,10 @@ namespace macro
       cerr << endl << "Macro-processing error: backtrace..." << endl << e.trace();
       exit(EXIT_FAILURE);
     }
+    inline void warning(const StackTrace &e) const noexcept
+    {
+      cerr << endl << "Macro-processing warning: backtrace..." << endl << e.trace();
+    }
     inline void printLineInfo(ostream &output, bool no_line_macro) const noexcept
     {
       if (!no_line_macro)
diff --git a/src/macro/Parser.yy b/src/macro/Parser.yy
index 51b2524576d30eef6c0c37d5985ee05c2ab5b308..b84009af4dd727985b8ee7d869efdadddfb68b63 100644
--- a/src/macro/Parser.yy
+++ b/src/macro/Parser.yy
@@ -126,9 +126,9 @@ directive : directive_one_line EOL
           ;
 
 directive_one_line : INCLUDE expr
-                     { $$ = make_shared<Include>($2, driver.env, driver.paths, @$); }
+                     { $$ = make_shared<Include>($2, driver.env, @$); }
                    | INCLUDEPATH expr
-                     { $$ = make_shared<IncludePath>($2, driver.env, driver.paths, @$); }
+                     { $$ = make_shared<IncludePath>($2, driver.env, @$); }
                    | DEFINE symbol EQUAL expr
                      { $$ = make_shared<Define>($2, $4, driver.env, @$); }
                    | DEFINE function EQUAL expr