From 10a36336df3cb2e792e23375636c6efc43eb6806 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Tue, 13 Feb 2018 15:24:43 -0800 Subject: [PATCH] [flang] Implement a directory search path for INCLUDE lines. 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 | 7 +++++++ flang/lib/parser/provenance.cc | 13 ++++++++++++- flang/lib/parser/provenance.h | 3 +++ flang/lib/parser/source.cc | 25 +++++++++++++++++++++++-- flang/lib/parser/source.h | 9 +++++++-- flang/tools/f18/f18.cc | 9 +++++++-- 6 files changed, 59 insertions(+), 7 deletions(-) diff --git a/flang/lib/parser/prescan.cc b/flang/lib/parser/prescan.cc index 5aaf39fb..a006a4c 100644 --- a/flang/lib/parser/prescan.cc +++ b/flang/lib/parser/prescan.cc @@ -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; diff --git a/flang/lib/parser/provenance.cc b/flang/lib/parser/provenance.cc index 2417766..d942b26 100644 --- a/flang/lib/parser/provenance.cc +++ b/flang/lib/parser/provenance.cc @@ -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 source{std::make_unique()}; - if (source->Open(path, error)) { + if (source->Open(LocateSourceFile(path, searchPath_), error)) { return ownedSourceFiles_.emplace_back(std::move(source)).get(); } return nullptr; diff --git a/flang/lib/parser/provenance.h b/flang/lib/parser/provenance.h index 1817f86..4fbd59e 100644 --- a/flang/lib/parser/provenance.h +++ b/flang/lib/parser/provenance.h @@ -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 compilerInsertionProvenance_; std::vector> ownedSourceFiles_; + std::vector searchPath_; }; class CookedSource { diff --git a/flang/lib/parser/source.cc b/flang/lib/parser/source.cc index 533c00d..6a75b4a 100644 --- a/flang/lib/parser/source.cc +++ b/flang/lib/parser/source.cc @@ -5,11 +5,13 @@ #include #include #include +#include // TODO pmk rm #include #include #include #include #include +#include // TODO: Port to Windows &c. @@ -36,6 +38,26 @@ static std::vector 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 &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; } } diff --git a/flang/lib/parser/source.h b/flang/lib/parser/source.h index 33d22e9..95e8521 100644 --- a/flang/lib/parser/source.h +++ b/flang/lib/parser/source.h @@ -13,16 +13,21 @@ namespace Fortran { namespace parser { +std::string DirectoryName(std::string path); +std::string LocateSourceFile( + std::string name, const std::vector &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 FindOffsetLineAndColumn(size_t) const; private: diff --git a/flang/tools/f18/f18.cc b/flang/tools/f18/f18.cc index ec23c33..3d563e7 100644 --- a/flang/tools/f18/f18.cc +++ b/flang/tools/f18/f18.cc @@ -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); -- 2.7.4