Module files emitted by this Fortran compiler are valid Fortran source files. Symbols that are USE-associated into modules are represented in their module files with USE statements and special comments with hash codes in them to ensure that those USE statements resolve to the same modules that were used to build the module when its module file was generated. This scheme prevents unchecked module file growth in large applications by not emitting USE-associated symbols redundantly. This problem can be especially bad when derived type definitions must be repeated in the module files of their clients, and the clients of those modules, and so on. However, this scheme has the disadvantage that clients of modules must be compiled with dependent modules in the module search path. This new -fhermetic-module-files option causes module file output to be free of dependences on any non-intrinsic module files; dependent modules are instead emitted as part of the module file, rather than being USE-associated. It is intended for top level library module files that are shipped with binary libraries when it is not convenient to collect and ship their dependent module files as well. Fixes https://github.com/llvm/llvm-project/issues/97398.
111 lines
3.7 KiB
C++
111 lines
3.7 KiB
C++
//===-- lib/Semantics/mod-file.h --------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef FORTRAN_SEMANTICS_MOD_FILE_H_
|
|
#define FORTRAN_SEMANTICS_MOD_FILE_H_
|
|
|
|
#include "flang/Semantics/attr.h"
|
|
#include "flang/Semantics/symbol.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <string>
|
|
|
|
namespace Fortran::parser {
|
|
class CharBlock;
|
|
class Message;
|
|
class MessageFixedText;
|
|
} // namespace Fortran::parser
|
|
|
|
namespace llvm {
|
|
class raw_ostream;
|
|
}
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
using SourceName = parser::CharBlock;
|
|
class Symbol;
|
|
class Scope;
|
|
class SemanticsContext;
|
|
|
|
class ModFileWriter {
|
|
public:
|
|
explicit ModFileWriter(SemanticsContext &context) : context_{context} {}
|
|
bool WriteAll();
|
|
void WriteClosure(llvm::raw_ostream &, const Symbol &,
|
|
UnorderedSymbolSet &nonIntrinsicModulesWritten);
|
|
ModFileWriter &set_hermeticModuleFileOutput(bool yes = true) {
|
|
hermeticModuleFileOutput_ = yes;
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
SemanticsContext &context_;
|
|
// Buffers to use with raw_string_ostream
|
|
std::string needsBuf_;
|
|
std::string usesBuf_;
|
|
std::string useExtraAttrsBuf_;
|
|
std::string declsBuf_;
|
|
std::string containsBuf_;
|
|
// Tracks nested DEC structures and fields of that type
|
|
UnorderedSymbolSet emittedDECStructures_, emittedDECFields_;
|
|
UnorderedSymbolSet usedNonIntrinsicModules_;
|
|
|
|
llvm::raw_string_ostream needs_{needsBuf_};
|
|
llvm::raw_string_ostream uses_{usesBuf_};
|
|
llvm::raw_string_ostream useExtraAttrs_{
|
|
useExtraAttrsBuf_}; // attrs added to used entity
|
|
llvm::raw_string_ostream decls_{declsBuf_};
|
|
llvm::raw_string_ostream contains_{containsBuf_};
|
|
bool isSubmodule_{false};
|
|
bool hermeticModuleFileOutput_{false};
|
|
|
|
void WriteAll(const Scope &);
|
|
void WriteOne(const Scope &);
|
|
void Write(const Symbol &);
|
|
std::string GetAsString(const Symbol &);
|
|
void PrepareRenamings(const Scope &);
|
|
void PutSymbols(const Scope &, UnorderedSymbolSet *hermetic);
|
|
// Returns true if a derived type with bindings and "contains" was emitted
|
|
bool PutComponents(const Symbol &);
|
|
void PutSymbol(llvm::raw_ostream &, const Symbol &);
|
|
void PutEntity(llvm::raw_ostream &, const Symbol &);
|
|
void PutEntity(
|
|
llvm::raw_ostream &, const Symbol &, std::function<void()>, Attrs);
|
|
void PutObjectEntity(llvm::raw_ostream &, const Symbol &);
|
|
void PutProcEntity(llvm::raw_ostream &, const Symbol &);
|
|
void PutDerivedType(const Symbol &, const Scope * = nullptr);
|
|
void PutDECStructure(const Symbol &, const Scope * = nullptr);
|
|
void PutTypeParam(llvm::raw_ostream &, const Symbol &);
|
|
void PutSubprogram(const Symbol &);
|
|
void PutGeneric(const Symbol &);
|
|
void PutUse(const Symbol &);
|
|
void PutUseExtraAttr(Attr, const Symbol &, const Symbol &);
|
|
llvm::raw_ostream &PutAttrs(llvm::raw_ostream &, Attrs,
|
|
const std::string * = nullptr, bool = false, std::string before = ","s,
|
|
std::string after = ""s) const;
|
|
void PutDirective(llvm::raw_ostream &, const Symbol &);
|
|
};
|
|
|
|
class ModFileReader {
|
|
public:
|
|
ModFileReader(SemanticsContext &context) : context_{context} {}
|
|
// Find and read the module file for a module or submodule.
|
|
// If ancestor is specified, look for a submodule of that module.
|
|
// Return the Scope for that module/submodule or nullptr on error.
|
|
Scope *Read(SourceName, std::optional<bool> isIntrinsic, Scope *ancestor,
|
|
bool silent);
|
|
|
|
private:
|
|
SemanticsContext &context_;
|
|
|
|
parser::Message &Say(SourceName, const std::string &,
|
|
parser::MessageFixedText &&, const std::string &);
|
|
};
|
|
|
|
} // namespace Fortran::semantics
|
|
#endif
|