Skip to content

Commit

Permalink
[flang][driver] Add support for -J/-module-dir
Browse files Browse the repository at this point in the history
Add support for option -J/-module-dir in the new Flang driver.  This
will allow for including module files in other directories, as the
default search path is currently the working folder. This also provides
an option of storing the output module in the specified folder.

Differential Revision: https://reviews.llvm.org/D95448
  • Loading branch information
arnamoy10 authored and banach-space committed Feb 4, 2021
1 parent a83475d commit 985a42f
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 10 deletions.
7 changes: 6 additions & 1 deletion clang/include/clang/Driver/Options.td
Expand Up @@ -949,6 +949,11 @@ def dependency_dot : Separate<["-"], "dependency-dot">, Flags<[CC1Option]>,
def module_dependency_dir : Separate<["-"], "module-dependency-dir">,
Flags<[CC1Option]>, HelpText<"Directory to dump module dependencies to">,
MarshallingInfoString<DependencyOutputOpts<"ModuleDependencyOutputDir">>;
def module_dir : Separate<["-"], "module-dir">, Flags<[FlangOption,FC1Option]>, MetaVarName<"<dir>">,
HelpText<"Put MODULE files in <dir>">,
DocBrief<[{This option specifies where to put .mod files for compiled modules.
It is also added to the list of directories to be searched by an USE statement.
The default is the current directory.}]>;
def dsym_dir : JoinedOrSeparate<["-"], "dsym-dir">,
Flags<[NoXarchOption, RenderAsInput]>,
HelpText<"Directory to output dSYM's (if any) to">, MetaVarName<"<dir>">;
Expand Down Expand Up @@ -4121,7 +4126,7 @@ defm devirtualize_speculatively : BooleanFFlag<"devirtualize-speculatively">,

// Generic gfortran options.
def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>;
def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group<gfortran_Group>;
def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined,FlangOption,FC1Option]>, Group<gfortran_Group>, Alias<module_dir>;
def cpp : Flag<["-"], "cpp">, Group<gfortran_Group>;
def nocpp : Flag<["-"], "nocpp">, Group<gfortran_Group>;
def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group>;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Expand Up @@ -30,6 +30,10 @@ void Flang::AddPreprocessingOptions(const ArgList &Args,
Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I});
}

void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
Args.AddAllArgs(CmdArgs, options::OPT_module_dir);
}

void Flang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const char *LinkingOutput) const {
Expand Down Expand Up @@ -87,6 +91,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,

AddFortranDialectOptions(Args, CmdArgs);

// Add other compile options
AddOtherOptions(Args, CmdArgs);

if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.h
Expand Up @@ -39,6 +39,13 @@ class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
/// \param [out] CmdArgs The list of output command arguments
void AddPreprocessingOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
/// Extract other compilation options from the driver arguments and add them
/// to the command arguments.
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
void AddOtherOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;

public:
Flang(const ToolChain &TC);
Expand Down
5 changes: 5 additions & 0 deletions flang/include/flang/Frontend/CompilerInstance.h
Expand Up @@ -30,6 +30,8 @@ class CompilerInstance {

std::shared_ptr<Fortran::parser::Parsing> parsing_;

std::unique_ptr<Fortran::semantics::SemanticsContext> semanticsContext_;

/// The stream for diagnostics from Semantics
llvm::raw_ostream *semaOutputStream_ = &llvm::errs();

Expand Down Expand Up @@ -100,6 +102,9 @@ class CompilerInstance {
/// }
/// @name Semantic analysis
/// {
Fortran::semantics::SemanticsContext &semanticsContext() const {
return *semanticsContext_;
}

/// Replace the current stream for verbose output.
void set_semaOutputStream(llvm::raw_ostream &Value);
Expand Down
12 changes: 12 additions & 0 deletions flang/include/flang/Frontend/CompilerInvocation.h
Expand Up @@ -11,6 +11,7 @@
#include "flang/Frontend/FrontendOptions.h"
#include "flang/Frontend/PreprocessorOptions.h"
#include "flang/Parser/parsing.h"
#include "flang/Semantics/semantics.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/Option/ArgList.h"
Expand Down Expand Up @@ -60,6 +61,11 @@ class CompilerInvocation : public CompilerInvocationBase {
// of options.
Fortran::parser::Options parserOpts_;

/// Semantic options
// TODO: Merge with or translate to frontendOpts_. We shouldn't need two sets
// of options.
std::string moduleDir_ = ".";

public:
CompilerInvocation() = default;

Expand All @@ -69,6 +75,9 @@ class CompilerInvocation : public CompilerInvocationBase {
Fortran::parser::Options &fortranOpts() { return parserOpts_; }
const Fortran::parser::Options &fortranOpts() const { return parserOpts_; }

std::string &moduleDir() { return moduleDir_; }
const std::string &moduleDir() const { return moduleDir_; }

/// Create a compiler invocation from a list of input options.
/// \returns true on success.
/// \returns false if an error was encountered while parsing the arguments
Expand All @@ -87,6 +96,9 @@ class CompilerInvocation : public CompilerInvocationBase {
/// Set the Fortran options to user-specified values.
/// These values are found in the preprocessor options.
void setFortranOpts();

/// Set the Semantic Options
void setSemanticsOpts(Fortran::semantics::SemanticsContext &);
};

} // end namespace Fortran::frontend
Expand Down
8 changes: 6 additions & 2 deletions flang/lib/Frontend/CompilerInstance.cpp
Expand Up @@ -24,8 +24,10 @@ CompilerInstance::CompilerInstance()
: invocation_(new CompilerInvocation()),
allSources_(new Fortran::parser::AllSources()),
allCookedSources_(new Fortran::parser::AllCookedSources(*allSources_)),
parsing_(new Fortran::parser::Parsing(*allCookedSources_)) {

parsing_(new Fortran::parser::Parsing(*allCookedSources_)),
semanticsContext_(new Fortran::semantics::SemanticsContext(
*(new Fortran::common::IntrinsicTypeDefaultKinds()),
*(new common::LanguageFeatureControl()), *allCookedSources_)) {
// TODO: This is a good default during development, but ultimately we should
// give the user the opportunity to specify this.
allSources_->set_encoding(Fortran::parser::Encoding::UTF_8);
Expand Down Expand Up @@ -144,6 +146,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &act) {
invoc.SetDefaultFortranOpts();
// Update the fortran options based on user-based input.
invoc.setFortranOpts();
// Set semantic options
invoc.setSemanticsOpts(this->semanticsContext());

// Run the frontend action `act` for every input file.
for (const FrontendInputFile &fif : frontendOpts().inputs_) {
Expand Down
36 changes: 36 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Expand Up @@ -221,6 +221,25 @@ static void parsePreprocessorArgs(
opts.searchDirectoriesFromDashI.emplace_back(currentArg->getValue());
}

/// Parses all semantic related arguments and populates the variables
/// options accordingly.
static void parseSemaArgs(std::string &moduleDir, llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {

auto moduleDirList =
args.getAllArgValues(clang::driver::options::OPT_module_dir);
// User can only specify -J/-module-dir once
// https://gcc.gnu.org/onlinedocs/gfortran/Directory-Options.html
if (moduleDirList.size() > 1) {
const unsigned diagID =
diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
"Only one '-module-dir/-J' option allowed");
diags.Report(diagID);
}
if (moduleDirList.size() == 1)
moduleDir = moduleDirList[0];
}

bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
llvm::ArrayRef<const char *> commandLineArgs,
clang::DiagnosticsEngine &diags) {
Expand Down Expand Up @@ -250,6 +269,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
ParseFrontendArgs(res.frontendOpts(), args, diags);
// Parse the preprocessor args
parsePreprocessorArgs(res.preprocessorOpts(), args);
// Parse semantic args
parseSemaArgs(res.moduleDir(), args, diags);

return success;
}
Expand Down Expand Up @@ -314,6 +335,7 @@ void CompilerInvocation::setFortranOpts() {
auto &fortranOptions = fortranOpts();
const auto &frontendOptions = frontendOpts();
const auto &preprocessorOptions = preprocessorOpts();
auto &moduleDirJ = moduleDir();

if (frontendOptions.fortranForm_ != FortranForm::Unknown) {
fortranOptions.isFixedForm =
Expand All @@ -327,4 +349,18 @@ void CompilerInvocation::setFortranOpts() {
fortranOptions.searchDirectories.end(),
preprocessorOptions.searchDirectoriesFromDashI.begin(),
preprocessorOptions.searchDirectoriesFromDashI.end());

// Add the directory supplied through -J/-module-dir to the list of search
// directories
if (moduleDirJ.compare(".") != 0)
fortranOptions.searchDirectories.emplace_back(moduleDirJ);
}

void CompilerInvocation::setSemanticsOpts(
Fortran::semantics::SemanticsContext &semaCtxt) {
auto &fortranOptions = fortranOpts();
auto &moduleDirJ = moduleDir();
semaCtxt.set_moduleDirectory(moduleDirJ)
.set_searchDirectories(fortranOptions.searchDirectories);
return;
}
8 changes: 1 addition & 7 deletions flang/lib/Frontend/FrontendActions.cpp
Expand Up @@ -109,10 +109,6 @@ void PrintPreprocessedAction::ExecuteAction() {
void ParseSyntaxOnlyAction::ExecuteAction() {
CompilerInstance &ci = this->instance();

// TODO: These should be specifiable by users. For now just use the defaults.
common::LanguageFeatureControl features;
Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;

// Parse. In case of failure, report and return.
ci.parsing().Parse(llvm::outs());

Expand All @@ -132,10 +128,8 @@ void ParseSyntaxOnlyAction::ExecuteAction() {
auto &parseTree{*ci.parsing().parseTree()};

// Prepare semantics
Fortran::semantics::SemanticsContext semanticsContext{
defaultKinds, features, ci.allCookedSources()};
Fortran::semantics::Semantics semantics{
semanticsContext, parseTree, ci.parsing().cooked().AsCharBlock()};
ci.semanticsContext(), parseTree, ci.parsing().cooked().AsCharBlock()};

// Run semantic checks
semantics.Perform();
Expand Down
1 change: 1 addition & 0 deletions flang/test/Flang-Driver/driver-help-hidden.f90
Expand Up @@ -30,6 +30,7 @@
! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics
! CHECK-NEXT: -help Display available options
! CHECK-NEXT: -I <dir> Add directory to the end of the list of include search paths
! CHECK-NEXT: -module-dir <dir> Put MODULE files in <dir>
! CHECK-NEXT: -o <file> Write output to <file>
! CHECK-NEXT: -test-io Run the InputOuputTest action. Use for development and testing only.
! CHECK-NEXT: -U <macro> Undefine macro <macro>
Expand Down
2 changes: 2 additions & 0 deletions flang/test/Flang-Driver/driver-help.f90
Expand Up @@ -30,6 +30,7 @@
! HELP-NEXT: -fno-color-diagnostics Disable colors in diagnostics
! HELP-NEXT: -help Display available options
! HELP-NEXT: -I <dir> Add directory to the end of the list of include search paths
! HELP-NEXT: -module-dir <dir> Put MODULE files in <dir>
! HELP-NEXT: -o <file> Write output to <file>
! HELP-NEXT: -U <macro> Undefine macro <macro>
! HELP-NEXT: --version Print version information
Expand All @@ -49,6 +50,7 @@
! HELP-FC1-NEXT: -ffree-form Process source files in free form
! HELP-FC1-NEXT: -help Display available options
! HELP-FC1-NEXT: -I <dir> Add directory to the end of the list of include search paths
! HELP-FC1-NEXT: -module-dir <dir> Put MODULE files in <dir>
! HELP-FC1-NEXT: -o <file> Write output to <file>
! HELP-FC1-NEXT: -U <macro> Undefine macro <macro>
! HELP-FC1-NEXT: --version Print version information
Expand Down
19 changes: 19 additions & 0 deletions flang/test/Flang-Driver/include-module.f90
Expand Up @@ -7,12 +7,26 @@
!--------------------------
! RUN: not %flang-new -fsyntax-only -I %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED
! RUN: not %flang-new -fsyntax-only -I %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE
! RUN: not %flang-new -fsyntax-only -I %S/Inputs -J %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED
! RUN: not %flang-new -fsyntax-only -J %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE
! RUN: not %flang-new -fsyntax-only -I %S/Inputs -module-dir %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED
! RUN: not %flang-new -fsyntax-only -module-dir %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE
! RUN: not %flang-new -fsyntax-only -J %S/Inputs/module-dir -J %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=DOUBLEINCLUDE
! RUN: not %flang-new -fsyntax-only -J %S/Inputs/module-dir -module-dir %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=DOUBLEINCLUDE
! RUN: not %flang-new -fsyntax-only -module-dir %S/Inputs/module-dir -J%S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=DOUBLEINCLUDE

!-----------------------------------------
! FRONTEND FLANG DRIVER (flang-new -fc1)
!-----------------------------------------
! RUN: not %flang-new -fc1 -fsyntax-only -I %S/Inputs -I %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED
! RUN: not %flang-new -fc1 -fsyntax-only -I %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE
! RUN: not %flang-new -fc1 -fsyntax-only -I %S/Inputs -J %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED
! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE
! RUN: not %flang-new -fc1 -fsyntax-only -I %S/Inputs -module-dir %S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED
! RUN: not %flang-new -fc1 -fsyntax-only -module-dir %S/Inputs %s 2>&1 | FileCheck %s --check-prefix=SINGLEINCLUDE
! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs/module-dir -J %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=DOUBLEINCLUDE
! RUN: not %flang-new -fc1 -fsyntax-only -J %S/Inputs/module-dir -module-dir %S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=DOUBLEINCLUDE
! RUN: not %flang-new -fc1 -fsyntax-only -module-dir %S/Inputs/module-dir -J%S/Inputs/ %s 2>&1 | FileCheck %s --check-prefix=DOUBLEINCLUDE

!-----------------------------------------
! EXPECTED OUTPUT FOR MISSING MODULE FILE
Expand All @@ -22,6 +36,11 @@
! SINGLEINCLUDE-NOT:error: Derived type 't1' not found
! SINGLEINCLUDE:error: Derived type 't2' not found

!-----------------------------------------
! EXPECTED OUTPUT FOR MISSING MODULE FILE
!-----------------------------------------
! DOUBLEINCLUDE:error: Only one '-module-dir/-J' option allowed

!---------------------------------------
! EXPECTED OUTPUT FOR ALL MODULES FOUND
!---------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions flang/test/Flang-Driver/write-module.f90
@@ -0,0 +1,10 @@
! RUN: mkdir -p %t/dir-f18 && %f18 -fparse-only -I tools/flang/include/flang -module %t/dir-f18 %s 2>&1
! RUN: ls %t/dir-f18/testmodule.mod && not ls %t/testmodule.mod

! RUN: mkdir -p %t/dir-flang-new && %flang-new -fsyntax-only -module-dir %t/dir-flang-new %s 2>&1
! RUN: ls %t/dir-flang-new/testmodule.mod && not ls %t/testmodule.mod

module testmodule
type::t2
end type
end

0 comments on commit 985a42f

Please sign in to comment.