[flang] Implement a directory search path for INCLUDE lines.
authorpeter klausler <pklausler@nvidia.com>
Tue, 13 Feb 2018 23:24:43 +0000 (15:24 -0800)
committerGitHub <noreply@github.com>
Thu, 15 Feb 2018 23:58:44 +0000 (15:58 -0800)
Original-commit: flang-compiler/f18@62129e56008acc02c894c3cf2b936f76dbfa0060
Reviewed-on: https://github.com/flang-compiler/f18/pull/9
Tree-same-pre-rewrite: false

flang/lib/parser/prescan.cc
flang/lib/parser/provenance.cc
flang/lib/parser/provenance.h
flang/lib/parser/source.cc
flang/lib/parser/source.h
flang/tools/f18/f18.cc

index 5aaf39f..a006a4c 100644 (file)
@@ -426,7 +426,14 @@ bool Prescanner::IncludeLine(const char *p) {
   std::stringstream error;
   Provenance provenance{GetProvenance(start)};
   AllSources *allSources{cooked_->allSources()};
+  const SourceFile *currentFile{allSources->GetSourceFile(provenance)};
+  if (currentFile != nullptr) {
+    allSources->PushSearchPathDirectory(DirectoryName(currentFile->path()));
+  }
   const SourceFile *included{allSources->Open(path, &error)};
+  if (currentFile != nullptr) {
+    allSources->PopSearchPathDirectory();
+  }
   if (included == nullptr) {
     messages_->Put({provenance, error.str()});
     anyFatalErrors_ = true;
index 2417766..d942b26 100644 (file)
@@ -75,9 +75,20 @@ const char &AllSources::operator[](Provenance at) const {
   return origin[at - origin.start];
 }
 
+void AllSources::PushSearchPathDirectory(std::string directory) {
+  // gfortran and ifort append to current path, PGI prepends
+  searchPath_.push_back(directory);
+}
+
+std::string AllSources::PopSearchPathDirectory() {
+  std::string directory{searchPath_.back()};
+  searchPath_.pop_back();
+  return directory;
+}
+
 const SourceFile *AllSources::Open(std::string path, std::stringstream *error) {
   std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>()};
-  if (source->Open(path, error)) {
+  if (source->Open(LocateSourceFile(path, searchPath_), error)) {
     return ownedSourceFiles_.emplace_back(std::move(source)).get();
   }
   return nullptr;
index 1817f86..4fbd59e 100644 (file)
@@ -75,6 +75,8 @@ public:
   size_t size() const { return bytes_; }
   const char &operator[](Provenance) const;
 
+  void PushSearchPathDirectory(std::string);
+  std::string PopSearchPathDirectory();
   const SourceFile *Open(std::string path, std::stringstream *error);
 
   ProvenanceRange AddIncludedFile(const SourceFile &, ProvenanceRange);
@@ -122,6 +124,7 @@ private:
   size_t bytes_{0};
   std::map<char, Provenance> compilerInsertionProvenance_;
   std::vector<std::unique_ptr<SourceFile>> ownedSourceFiles_;
+  std::vector<std::string> searchPath_;
 };
 
 class CookedSource {
index 533c00d..6a75b4a 100644 (file)
@@ -5,11 +5,13 @@
 #include <cerrno>
 #include <cstring>
 #include <fcntl.h>
+#include <iostream>  // TODO pmk rm
 #include <memory>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <vector>
 
 // TODO: Port to Windows &c.
 
@@ -36,6 +38,26 @@ static std::vector<size_t> FindLineStarts(const char *source, size_t bytes) {
   return result;
 }
 
+std::string DirectoryName(std::string path) {
+  auto lastSlash = path.rfind("/");
+  return lastSlash == std::string::npos ? path : path.substr(0, lastSlash);
+}
+
+std::string LocateSourceFile(
+    std::string name, const std::vector<std::string> &searchPath) {
+  if (name.empty() || name == "-" || name[0] == '/') {
+    return name;
+  }
+  for (const std::string &dir : searchPath) {
+    std::string path{dir + '/' + name};
+    struct stat statbuf;
+    if (stat(path.c_str(), &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) {
+      return path;
+    }
+  }
+  return name;
+}
+
 bool SourceFile::Open(std::string path, std::stringstream *error) {
   Close();
   path_ = path;
@@ -48,8 +70,7 @@ bool SourceFile::Open(std::string path, std::stringstream *error) {
     error_path = "'"s + path + "'";
     fileDescriptor_ = open(path.c_str(), O_RDONLY);
     if (fileDescriptor_ < 0) {
-      *error << "could not open '" << error_path
-             << "': " << std::strerror(errno);
+      *error << "could not open " << error_path << ": " << std::strerror(errno);
       return false;
     }
   }
index 33d22e9..95e8521 100644 (file)
 namespace Fortran {
 namespace parser {
 
+std::string DirectoryName(std::string path);
+std::string LocateSourceFile(
+    std::string name, const std::vector<std::string> &searchPath);
+
 class SourceFile {
 public:
   SourceFile() {}
   ~SourceFile();
-  bool Open(std::string path, std::stringstream *error);
-  void Close();
   std::string path() const { return path_; }
   const char *content() const { return content_; }
   size_t bytes() const { return bytes_; }
   size_t lines() const { return lineStart_.size(); }
+
+  bool Open(std::string path, std::stringstream *error);
+  void Close();
   std::pair<int, int> FindOffsetLineAndColumn(size_t) const;
 
 private:
index ec23c33..3d563e7 100644 (file)
@@ -56,6 +56,8 @@ int main(int argc, char *const argv[]) {
   bool enableOldDebugLines{false};
   int columns{72};
 
+  Fortran::parser::AllSources allSources;
+
   while (!args.empty()) {
     if (args.front().empty()) {
       args.pop_front();
@@ -79,6 +81,11 @@ int main(int argc, char *const argv[]) {
         dumpCookedChars = true;
       } else if (flag == "-ed") {
         enableOldDebugLines = true;
+      } else if (flag == "-I") {
+        allSources.PushSearchPathDirectory(args.front());
+        args.pop_front();
+      } else if (flag.substr(0, 2) == "-I") {
+        allSources.PushSearchPathDirectory(flag.substr(2, std::string::npos));
       } else {
         std::cerr << "unknown flag: '" << flag << "'\n";
         return 1;
@@ -97,7 +104,6 @@ int main(int argc, char *const argv[]) {
     }
   }
 
-  Fortran::parser::AllSources allSources;
   std::stringstream error;
   const auto *sourceFile = allSources.Open(path, &error);
   if (!sourceFile) {
@@ -129,7 +135,6 @@ int main(int argc, char *const argv[]) {
   state.set_strictConformance(standard);
   state.set_columns(columns);
   state.set_enableOldDebugLines(enableOldDebugLines);
-  state.PushContext("source file '"s + path + "'");
   Fortran::parser::UserState ustate;
   state.set_userState(&ustate);