Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Bill1
Beginner
335 Views

Submodule Linking error LNK2005

I am attempting to learn about and use modules and submodules as part of modernizing a very large FORTRAN 77 project and have run into the following linking error that I cannot figure out:

Bill1_0-1601400658448.png

I attempted to create a small sample that would replicate the problem, but of course this sample compiled fine.   This is the sample showing the module and submodules that I am trying to set up:

Main Program File:

PROGRAM MODTEST
  USE DYNAMICS_DATA
  IMPLICIT NONE
  INTEGER(4) IDUM(1)
  IDUM = 0
  CALL DYN_IN(IDUM)
  STOP
END

Module File:

MODULE DYNAMICS_DATA
!
  IMPLICIT NONE
!
  INTERFACE
    MODULE SUBROUTINE ASSEM_TIME_HIST(LINIT, ILINEAR, TBEG, TEND,
$                     TINC, NTER, INITIALD, ISTEP, TLAST, NTOTAL,
$                     MAX_MODE, RAL1, RAL2, IGDAMP, *)
      INTEGER(4), INTENT(IN) :: LINIT
      INTEGER(4), INTENT(IN) :: ILINEAR
      INTEGER(4), INTENT(INOUT) :: INITIALD
      INTEGER(4), INTENT(INOUT) :: ISTEP
      INTEGER(4), INTENT(OUT) :: NTOTAL
      INTEGER(4), INTENT(IN) :: NTER
      INTEGER(4), INTENT(IN) :: MAX_MODE
      INTEGER(4), INTENT(IN) :: IGDAMP
      REAL(8), INTENT(IN) :: TBEG, TEND, TINC
      REAL(8), INTENT(INOUT) :: TLAST
      REAL(8), INTENT(OUT) :: RAL1, RAL2
    END SUBROUTINE ASSEM_TIME_HIST
  END INTERFACE
!
CONTAINS
!
  SUBROUTINE DYN_IN(IDUM)
    INTEGER(4), INTENT(OUT) :: IDUM(1)
    INTEGER(4) ILINEAR, LINIT, MAX_MODE, NTER
    INTEGER(4) :: ISTEP = 0
    INTEGER(4) :: INITIALD = 0
    INTEGER(4) :: NTOTAL = 0
    INTEGER(4) :: IGDAMP = 0
    REAL(8) TBEG, TEND, TINC, TLAST
    REAL(8) RAL1, RAL2
!
    IDUM(1) = 1
    CALL ASSEM_TIME_HIST(LINIT,ILINEAR,TBEG,TEND,TINC,NTER,
$                        INITIALD, ISTEP, TLAST, NTOTAL,
$                        MAX_MODE, RAL1, RAL2, IGDAMP, *9930)

9930 RETURN
  END SUBROUTINE DYN_IN
END MODULE DYNAMICS_DATA

Submodule1 file:

SUBMODULE (DYNAMICS_DATA) TIMEHISTORY_DATA
  IMPLICIT NONE
  INTERFACE
    MODULE SUBROUTINE WIL_THE_NON(TBEG, TEND, TINC, NTER, MDISP,
$                     AK, AM, KM, KUL, AC, D, THETA,
$                     ND, NS, NT, NBW,
$                     TOLERANCE, MAXITER, MINITER, ASSEMITER, RELAXATION,
$                     RAL1, RAL2, KSW,
$                     INITIALD, ISTEP, TLAST, NTOTAL)
      INTEGER(4), INTENT(IN) :: ND, NS, NT
      INTEGER(4), INTENT(IN) :: NBW
      INTEGER(4), INTENT(IN) :: NTER
      INTEGER(4), INTENT(IN) :: MAXITER, MINITER, ASSEMITER
      INTEGER(4), INTENT(IN) :: MDISP(1,12)
      INTEGER(4), INTENT(OUT) :: NTOTAL
      INTEGER(4), INTENT(OUT) :: KSW(1)
      INTEGER(4), INTENT(INOUT) :: INITIALD
      INTEGER(4), INTENT(INOUT) :: ISTEP
      REAL(8), INTENT(IN) :: TBEG, TEND, TINC
      REAL(8), INTENT(IN) :: TOLERANCE
      REAL(8), INTENT(IN) :: AM(1)
      REAL(8), INTENT(IN) :: AK(1)
      REAL(8), INTENT(IN) :: RAL1, RAL2
      REAL(8), INTENT(OUT) :: D(1)
      REAL(8), INTENT(OUT) :: THETA
      REAL(8), INTENT(OUT) :: AC(1)
      REAL(8), INTENT(OUT) :: KM(1)
      REAL(8), INTENT(INOUT) :: KUL(1)
      REAL(8), INTENT(INOUT) :: RELAXATION
      REAL(8), INTENT(INOUT) :: TLAST
    END SUBROUTINE WIL_THE_NON
  END INTERFACE
!
CONTAINS
!
  MODULE SUBROUTINE ASSEM_TIME_HIST(LINIT, ILINEAR, TBEG, TEND,
$                   TINC, NTER, INITIALD, ISTEP, TLAST, NTOTAL,
$                   MAX_MODE, RAL1, RAL2, IGDAMP, *)
    INTEGER(4), INTENT(IN) :: LINIT
    INTEGER(4), INTENT(IN) :: ILINEAR
    INTEGER(4), INTENT(INOUT) :: INITIALD
    INTEGER(4), INTENT(INOUT) :: ISTEP
    INTEGER(4), INTENT(OUT) :: NTOTAL
    INTEGER(4), INTENT(IN) :: NTER
    INTEGER(4), INTENT(IN) :: MAX_MODE
    INTEGER(4), INTENT(IN) :: IGDAMP
    REAL(8), INTENT(IN) :: TBEG, TEND, TINC
    REAL(8), INTENT(INOUT) :: TLAST
    REAL(8), INTENT(OUT) :: RAL1, RAL2


    RETURN
  END SUBROUTINE ASSEM_TIME_HIST
END SUBMODULE TIMEHISTORY_DATA

 

Submodule2 file:

SUBMODULE (DYNAMICS_DATA:TIMEHISTORY_DATA) NONLINEAR
  IMPLICIT NONE
CONTAINS
!
  MODULE SUBROUTINE WIL_THE_NON(TBEG, TEND, TINC, NTER, MDISP,
$                   AK, AM, KM, KUL, AC, D, THETA,
$                   ND, NS, NT, NBW,
$                   TOLERANCE, MAXITER, MINITER, ASSEMITER, RELAXATION,
$                   RAL1, RAL2, KSW,
$                   INITIALD, ISTEP, TLAST, NTOTAL)
    INTEGER(4), INTENT(IN) :: ND, NS, NT
    INTEGER(4), INTENT(IN) :: NBW
    INTEGER(4), INTENT(IN) :: NTER
    INTEGER(4), INTENT(IN) :: MAXITER, MINITER, ASSEMITER
    INTEGER(4), INTENT(IN) :: MDISP(1,12)
    INTEGER(4), INTENT(INOUT) :: INITIALD
    INTEGER(4), INTENT(INOUT) :: ISTEP
    INTEGER(4), INTENT(OUT) :: NTOTAL
    INTEGER(4), INTENT(OUT) :: KSW(1)
    REAL(8), INTENT(IN) :: TBEG, TEND, TINC
    REAL(8), INTENT(IN) :: TOLERANCE
    REAL(8), INTENT(INOUT) :: RELAXATION
    REAL(8), INTENT(INOUT) :: TLAST
    REAL(8), INTENT(IN) :: AM(1)
    REAL(8), INTENT(IN) :: AK(1)
    REAL(8), INTENT(IN) :: RAL1, RAL2
    REAL(8), INTENT(OUT) :: D(1)
    REAL(8), INTENT(OUT) :: THETA
    REAL(8), INTENT(OUT) :: AC(1)
    REAL(8), INTENT(OUT) :: KM(1)
    REAL(8), INTENT(INOUT) :: KUL(1)


  END SUBROUTINE WIL_THE_NON
END SUBMODULE NONLINEAR

I searched the solution for DYNAMICS_DATA to make sure it was not duplicated somewhere and cleaned and rebuilt the solution multiple times with no success.  Does anyone have any idea on what else I can do to find the cause of the linker error LNK2005?

0 Kudos
9 Replies
Johannes_Rieke
New Contributor III
321 Views

Dear Bill, I put your code into a VS solution and your code builds fine, if and only if I remove the obsolete alternate return (this * in parameter list) for PSXE2020u2 (19.1.2, Windows OS). The formal use of submodules is fine as far as I see. I don't know if the alternate return causes the issues. I found no switch for ifort to accept this feature, but that means not, that it does't exist. Maybe it just does not work with submodules. Anyways, alternate return should be avoided IMHO, if you are modernizing.

Johannes_Rieke
New Contributor III
320 Views

Maybe helpful, the VS solution as zip.

andrew_4619
Honored Contributor I
309 Views

In reply to the OP, I find the structure rather strange particularly nesting submodule with a submodule. The main point of submodules over modules is that it separates the interfaces from the routine so that you avoid dependencies and hence build cascades.  The common implementation is a module with (maybe) some global data and a set of interfaces only. The submodules then have contained the routines only.  Routines that are only called from within the same submodule do not need interfaces as they are known within that submodule. 

Steve_Lionel
Black Belt Retired Employee
291 Views

I took your ZIP file and built it with the current compiler version (19.1.2). It linked without error.

There's nothing wrong with nesting submodules, and it can be useful.

Johannes_Rieke
New Contributor III
284 Views

Hi Steve, I've removed the alternate return from the interfaces of the original thread opener's code and converted it to free format. Bill might has encountered a different link error.

Has you tried to comment these lines in? It was not linking for me with alternate return. Since it's an obsolete feature, I would not expect, that this is tested with submodules nor would I think one should use alternate return in submodules.

But maybe it's still supported by ifort with an additional switch...

e.g.

MODULE SUBROUTINE ASSEM_TIME_HIST(LINIT, ILINEAR, TBEG, TEND,
$                     TINC, NTER, INITIALD, ISTEP, TLAST, NTOTAL,
$                     MAX_MODE, RAL1, RAL2, IGDAMP, *)

 

andrew_4619
Honored Contributor I
275 Views

"There's nothing wrong with nesting submodules, and it can be useful." Steve I would agree with that but I didn't say is was wrong. It did think it was odd (strange) within the context of the example used which seems overly complicated and more difficult to follow (IMO). The whole module /submodule structure only has one routine  used externally and that one doesn't make use of submodule functionality at all.

Steve_Lionel
Black Belt Retired Employee
268 Views

I had missed that the zip wasn't Bill's original code. I took Bill's code as-is (after fixing the issues caused by pasting fixed-form code directly into the forum) - it compiled and linked without error using compiler 19.1.2.

I must admit that the combination of nested submodules and alternate return gives me the shivers....

Bill1
Beginner
258 Views

Thanks for all of the replies.  The actual source code in these subroutines is thousands of lines long (contained in single files), which is why I am trying to split them up.  I copied and pasted the interfaces and module subroutine calls into the sample code but this modified code unfortunately does not produce the linker error.  I left the alternate return in for now as it does not seem to be the cause of the problem, although I realize it is obsolete.  I have struggled for hours trying to figure out how DYNAMICS_DATA can be defined twice.  If I remove DYNAMICS_DATA from the SUBMODULE (DYNAMICS_DATA:TIMEHISTORY_DATA) NONLINEAR statement I get the expected error #8765 Error in opening the compiled ancestor module file [TIMEHISTORY_DATA].  I am hoping that perhaps someone may have run into this as well previously and may have some ideas on where to look for the cause of the error.  Would the problem more likely be within MODULE DYNAMICS_DATA or within SUBMODULE TIMEHISTORY_DATA?

andrew_4619
Honored Contributor I
249 Views

One way is to have a module with all the interfaces and only interfaces, no contains section. You can then have as many submodules of that module as you want they can all see the interfaces and there are no conflicts. That structure is also quite easy to follow. If you have a submodule routine that uniquely calls some helper routines put them all in the same submodule, they will be a subroutine/functions rather than "module subroutine/function" as no external interface is needed and they will all see implict interfaces to each other within that submodule.  Personally I don't like lots of separate files I tend to have a lot of routines of the same tribe in a single submodule file and only have  sibling  submodules if it gets to more than say 10000 lines of code.

Reply