Fortran: Add support for submodule dependencies

Since commit v3.7.0-rc1~73^2~1 (Fortran: Add support for submodule
syntax in dependency scanning, 2016-09-05) we support parsing Fortran
sources that use submodule syntax, but it left addition of `.smod`
dependencies to future work.  Add it now.

The syntax

    submodule (module_name) submodule_name

means the current source requires `module_name.mod` and provides
`module_name@submodule_name.smod`.  The syntax

    submodule (module_name:submodule_name) nested_submodule_name

means the current source requires `module_name@submodule_name.smod`
provides `module_name@nested_submodule_name.smod`.

Fixes: #17017
This commit is contained in:
Brad King
2018-04-19 09:21:58 -04:00
parent 62538b2c4c
commit 402735314e
12 changed files with 126 additions and 64 deletions

View File

@@ -0,0 +1,7 @@
fortran-submodule-depends
-------------------------
* Fortran dependency scanning now supports dependencies implied by
`Fortran Submodules`_.
.. _`Fortran Submodules`: http://fortranwiki.org/fortran/show/Submodules

View File

@@ -1563,7 +1563,7 @@ yyreduce:
#line 119 "cmFortranParser.y" /* yacc.c:1646 */
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUse(parser, (yyvsp[-4].string));
cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string));
free((yyvsp[-4].string));
free((yyvsp[-2].string));
}
@@ -1574,7 +1574,7 @@ yyreduce:
#line 125 "cmFortranParser.y" /* yacc.c:1646 */
{
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUse(parser, (yyvsp[-6].string));
cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string));
free((yyvsp[-6].string));
free((yyvsp[-4].string));
free((yyvsp[-2].string));

View File

@@ -118,13 +118,13 @@ stmt:
}
| SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUse(parser, $3);
cmFortranParser_RuleSubmodule(parser, $3, $5);
free($3);
free($5);
}
| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT {
cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
cmFortranParser_RuleUse(parser, $3);
cmFortranParser_RuleSubmoduleNested(parser, $3, $5, $7);
free($3);
free($5);
free($7);

View File

@@ -31,6 +31,8 @@ static void cmFortranModuleAppendUpperLower(std::string const& mod,
std::string::size_type ext_len = 0;
if (cmHasLiteralSuffix(mod, ".mod")) {
ext_len = 4;
} else if (cmHasLiteralSuffix(mod, ".smod")) {
ext_len = 5;
}
std::string const& name = mod.substr(0, mod.size() - ext_len);
std::string const& ext = mod.substr(mod.size() - ext_len);
@@ -283,7 +285,8 @@ void cmDependsFortran::MatchRemoteModules(std::istream& fin,
if (line[0] == ' ') {
if (doing_provides) {
std::string mod = line;
if (!cmHasLiteralSuffix(mod, ".mod")) {
if (!cmHasLiteralSuffix(mod, ".mod") &&
!cmHasLiteralSuffix(mod, ".smod")) {
// Support fortran.internal files left by older versions of CMake.
// They do not include the ".mod" extension.
mod += ".mod";
@@ -486,7 +489,7 @@ bool cmDependsFortran::CopyModule(const std::vector<std::string>& args)
if (args.size() >= 5) {
compilerId = args[4];
}
if (!cmHasLiteralSuffix(mod, ".mod")) {
if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod")) {
// Support depend.make files left by older versions of CMake.
// They do not include the ".mod" extension.
mod += ".mod";

View File

@@ -45,6 +45,13 @@ void cmFortranParser_RuleLineDirective(cmFortranParser* parser,
void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name);
void cmFortranParser_RuleModule(cmFortranParser* parser,
const char* module_name);
void cmFortranParser_RuleSubmodule(cmFortranParser* parser,
const char* module_name,
const char* submodule_name);
void cmFortranParser_RuleSubmoduleNested(cmFortranParser* parser,
const char* module_name,
const char* submodule_name,
const char* nested_submodule_name);
void cmFortranParser_RuleDefine(cmFortranParser* parser, const char* name);
void cmFortranParser_RuleUndef(cmFortranParser* parser, const char* name);
void cmFortranParser_RuleIfdef(cmFortranParser* parser, const char* name);

View File

@@ -245,6 +245,50 @@ void cmFortranParser_RuleModule(cmFortranParser* parser,
}
}
void cmFortranParser_RuleSubmodule(cmFortranParser* parser,
const char* module_name,
const char* submodule_name)
{
if (parser->InPPFalseBranch) {
return;
}
// syntax: "submodule (module_name) submodule_name"
// requires: "module_name.mod"
// provides: "module_name@submodule_name.smod"
//
// FIXME: Some compilers split the submodule part of a module into a
// separate "module_name.smod" file. Whether it is generated or
// not depends on conditions more subtle than we currently detect.
// For now we depend directly on "module_name.mod".
std::string const& mod_name = cmSystemTools::LowerCase(module_name);
std::string const& sub_name = cmSystemTools::LowerCase(submodule_name);
parser->Info.Requires.insert(mod_name + ".mod");
parser->Info.Provides.insert(mod_name + "@" + sub_name + ".smod");
}
void cmFortranParser_RuleSubmoduleNested(cmFortranParser* parser,
const char* module_name,
const char* submodule_name,
const char* nested_submodule_name)
{
if (parser->InPPFalseBranch) {
return;
}
// syntax: "submodule (module_name:submodule_name) nested_submodule_name"
// requires: "module_name@submodule_name.smod"
// provides: "module_name@nested_submodule_name.smod"
std::string const& mod_name = cmSystemTools::LowerCase(module_name);
std::string const& sub_name = cmSystemTools::LowerCase(submodule_name);
std::string const& nest_name =
cmSystemTools::LowerCase(nested_submodule_name);
parser->Info.Requires.insert(mod_name + "@" + sub_name + ".smod");
parser->Info.Provides.insert(mod_name + "@" + nest_name + ".smod");
}
void cmFortranParser_RuleDefine(cmFortranParser* parser, const char* macro)
{
if (!parser->InPPFalseBranch) {

View File

@@ -1 +1,20 @@
add_executable(submod main.f90 provide.f90)
# The program units in this file consist of a module/submodule
# tree represented by the following graph:
#
# parent
# |
# / \
# / \
# child sibling
# |
# grandchild
#
# where the parent node is a module and all other nodes are submodules.
add_executable(submod
main.f90
parent.f90
child.f90
grandchild.f90
sibling.f90
)

View File

@@ -0,0 +1,10 @@
! Test the notation for a 1st-generation direct
! descendant of a parent module
submodule ( parent ) child
implicit none
contains
module function child_function() result(child_stuff)
logical :: child_stuff
child_stuff=.true.
end function
end submodule child

View File

@@ -0,0 +1,8 @@
! Test the notation for an Nth-generation descendant
! for N>1, which necessitates the colon.
submodule ( parent : child ) grandchild
contains
module subroutine grandchild_subroutine()
print *,"Test passed."
end subroutine
end submodule grandchild

View File

@@ -0,0 +1,17 @@
module parent
implicit none
interface
! Test Fortran 2008 "module function" syntax
module function child_function() result(child_stuff)
logical :: child_stuff
end function
! Test Fortran 2008 "module subroutine" syntax
module subroutine grandchild_subroutine()
end subroutine
end interface
end module parent

View File

@@ -1,57 +0,0 @@
! The program units in this file consist of a
! module/submodule tree represented by the following
! graph:
!
! parent
! |
! / \
! / \
! child sibling
! |
! grandchild
!
! where the parent node is a module and all other
! nodes are submodules.
module parent
implicit none
interface
! Test Fortran 2008 "module function" syntax
module function child_function() result(child_stuff)
logical :: child_stuff
end function
! Test Fortran 2008 "module subroutine" syntax
module subroutine grandchild_subroutine()
end subroutine
end interface
end module parent
! Test the notation for a 1st-generation direct
! descendant of a parent module
submodule ( parent ) child
implicit none
contains
module function child_function() result(child_stuff)
logical :: child_stuff
child_stuff=.true.
end function
end submodule child
! Empty submodule for checking disambiguation of
! nodes at the same vertical level in the tree
submodule ( parent ) sibling
end submodule sibling
! Test the notation for an Nth-generation descendant
! for N>1, which necessitates the colon.
submodule ( parent : child ) grandchild
contains
module subroutine grandchild_subroutine()
print *,"Test passed."
end subroutine
end submodule grandchild

View File

@@ -0,0 +1,4 @@
! Empty submodule for checking disambiguation of
! nodes at the same vertical level in the tree
submodule ( parent ) sibling
end submodule sibling