Two modules with the same name in one program

Well, actually 4. We are working on a single program which has 4 different Fortran modules all named
“precision”. Impossible you say? No it isn’t.

Each of these modules is used within a library. The libraries do not (at least in this project) preserve
the names of the modules, only of the routines which use them. Linking the libraries therefore does not
cause a problem. However, the code cannot be built without using libraries, and I suspect that bad things could happen in an IDE with a symbolic debugger.

This causes a serious problem for fpt ( http://simconglobal.com ) in code analysis, because fpt needs to see all of the modules and identifies them by their names. So three questions:

i. How do the other analysis tools - PlusFort, Understand Fortran etc. deal with this?

ii. What has the Fortran Standard to say about multiple modules with the same name in one program?

iii. Do we need a construct ABOVE the module level to keep duplicately named modules apart (well, I do but does anyone else)?

John.

1 Like

Some quick comments based on my understanding:

  • Re: question ii. above, the standard states in section 19, “Program units … are global entities of a program.” You will note a MODULE is a program unit. And the standard then states, “The global identifier of an entity shall not be the same as the global identifier of any other entity.” Thus it is nonconforming to have “multiple modules with the same name in one program.”

  • Re: question iii. and “Do we need a construct ABOVE the module level to keep duplicately named modules apart,” this can be among the use cases toward the namespace facility being contemplated for Fortran 202Y. I suggest you add this to this proposal at the J3-Fortran GitHub site and bring it to the attention of @certik, @sblionel et al., in their planning toward Fortran 202Y: Namespaces · Issue #87 · j3-fortran/fortran_proposals · GitHub

1 Like

Duplication of modules exporting precision variables is an issue that may come to affect fpm builds, once packages hierarchies start becoming deeper. I opened an issue on this topic some time ago: Have fpm define precision · Issue #122 · fortran-lang/fpm · GitHub

Fpm has a subroutine check_modules_for_duplicates which issues a warning in case of duplicate modules. I’m not entirely sure what happens later in the build process. There was a discussion recently on this topic: Compiling duplicate modules names to override default behaviour · Discussion #723 · fortran-lang/fpm · GitHub (cc @gnikit, @awvwgk).

Recently, I’ve been leaning towards having a system-wide include file defining my precision specifiers:

!     prec.inc (note this file works in both fixed- and free-form)
      integer :: lp,wp,hp
      parameter(lp=kind(1.0e0),wp=kind(1.0d0))
      parameter(hp=selected_real_kind(33))

This can ameliorate issues of diverging precision choices, but it doesn’t provide a solution to the duplicate module naming issue per-se.

(I consciously choose to avoid sp and dp, since they get misused. Instead there is wp as work precision, lp as lower (than work) precision, and hp for higher (than work) precision when available. When in doubt what you need stick with wp.)

Within the fpm ecosystem, there could be something like:

module fpm_kinds
implicit none
public
#ifdef FPM_KINDS      ! on by default
include "fpm_prec.inc"
#elif ...
...
#endif
end module

offering different precision families via the preprocessor, or perhaps even a built-in flag, e.g. $ fpm ... --prec-c for

      parameter(lp=c_float,wp=c_double)
      parameter(hp=c_float128)
1 Like

I think fpm enforces each library to prefix all module names with the library name, so this issue does not arise.

In general, you can’t have the same module name in the project.

A solution might be to allow nesting of modules, like in Python.

It seems like doing this is problematic in several ways.

First, if the modules are created in the same directory, then the name.mod files will overwrite each other. Only one would be available at any moment, presumably the last one created, and it would not matter if the USE statement allowed a rename, the correct name.mod file might no longer even exist.

Second, if they aren’t in the same directory, then eventually any global symbols that are generated by the name mangling will result in conflicts within the loader. Or, if the *.o files from the two directories are archived together in the same library, then subprograms in the second one would overwrite those in the first one.

Are there practical ways to work around these issues? By practical, I mean easier than just renaming the modules (and their USE statements).

Out of interest, what would the justification be for having several modules with the same name? I can define an overloaded function which uses a common name for multiple subroutines/functions using an interface:

interface print_number
   subroutine print_real(x)
   real :: x
   end subroutine print_real

   subroutine print_int(x)
   integer :: x
   end subroutine print_int
end interface print_number

So I could then just do call print_num(x) to get Fortran to pick what subroutine it wants (thinking aloud here, you all probably know this).

The situation that first comes to mind is when a programmer combines various smaller projects into one large project. There could well be modules in those various projects with the same name, particularly if they all do similar low-level things like define KIND values (KINDS_MOD) or I/O units (IO_UNITS_MOD) and things like that.

As stated in my previous post, I don’t really know a way to account for this. It seems like the easiest thing is to just rename the modules to avoid the conflicts, and in those cases where it is necessary, merge the functionality of, for example, the various KINDS_MOD into a single version.

@spreval
It is not that there is a justification for multiple modules with the same name in a single program, it is that in the current state of the language it is going to happen. The case we are dealing with is a large environmental management code which uses several libraries from different sources. By chance, the same module name occurs in different libraries. The libraries are built independently and then linked. If two libraries contained top-level subroutines or functions with the same name there would be contention. But the module names are not preserved in the libraries - the information in the modules has been used to build the components and is then discarded. So even though, as @FortranFan pointed out, the usage is illegal it is not detectable and doesn’t cause an immediate problem in building the program.

The problem occurs if an IDE or analysis tool sees the original code. We are using an analysis and re-engineering tool on this code. Hence my questions.

You do not, of course, need to use libraries to create this problem. If two modules with the same name only contain variables and parameters, they can, I believe, be used in different directories to create subroutine and function objects which can then be linked without error. But that case is perverse. The situation with libraries has occurred, and may be quite common. I suspect, and will test, that if two modules with the same name have sub-programs which therefore generate .o files on compilation the link will fail. I hope so.

The best plan we have at present is to separate the different libraries or directories into domains, and, internally in the tools, to restrict the scope of a module to its domain. We could then report information about the code as <domain_name>%<module_name> … This adds a layer of complexity outside the language and I am not happy with it, but I don’t yet see an alternative.

I don’t think that is it useful to disregard this situation simply because it is illegal. We have to analyse the code which people write and use. Nor do I think that it would be helpful in the future to embed module information in the sub-program objects to trap the situation at link-time (even if we could). This would inconvenience the authors of major libraries.

Any advice would be welcome!

John

1 Like

Usually, the module name is mangled along with the variable and subprogram names within that module. So it is typical that two different modules (with different names) could have variables or subprograms with the same names, but the mangling keeps them separate when the loader sees them. Here is a short example:

module xxx
   real :: x = 1.0
contains
   subroutine print()
   end subroutine print
end module xxx

$ gfortran -c symbol.f90 && nm symbol.o
0000000000000010 s EH_frame1
0000000000000000 T ___xxx_MOD_print
0000000000000008 D ___xxx_MOD_x
0000000000000000 t ltmp0
0000000000000008 d ltmp1
0000000000000010 s ltmp2

Notice how xxx_MOD_ is incorporated into the two external symbols for x and print. Those are both common names, so it would not be unusual at all for different modules to also have an x variable or a print subroutine, and if they did, then everything would work correctly because of the name mangling. Of course, if a fortran subroutine USEs two of these modules, then it would need to rename those things in the USE statement to keep everything straight, but that is just local to the compilation step, it does not change any of the global symbol names.

The problem occurs when two modules have the same name. Then the name mangling alone does not solve the problem, and the global symbols that are generated would conflict. In the fortran source, there is no way to rename a module in the USE statement, so both modules could not be USEd at the same time. The resolution of this would require changes to both the global symbol mangling and to the fortran syntax.

At present, fpm is not enforcing this (we did at one point in the original Haskell version I think), but we do highly encourage it. Strictly enforcing it was going to be an impediment to adoption, so we decided not to.

The irony is hard to escape since one of the functions of modules is to prevent name collisions.
Are their solutions presented by other languages that should be adopted? Some similar problems with libraries in the past were resolved by options to rename objects or to link specific objects when loading specific files (such as the COS/UNICOS segldr(1) utility) but theoretically any pure Fortran code should be able to be placed in a single file, and for that case there is no current solution. The way mod files are generated and named is not part of the standard; so although solutions are possible by changing how mod files are handled that does not currently provide a generic solution path. The simplest solutions all seem to require specifying system pathnames, which except for the Fortran INCLUDE statement Fortran has fastidiously avoided making part of the standard. Without some feature like a module always containing some kind of fixed-value UUID (sort of a self-contradictory concept) or some kind of directory file that contains pathnames to modules and an alias nothing immediately comes to mind. I cannot think of a solution used by other languages that does not involve pathnames. Anyone have any solutions?

2 Likes

We should enforce it, and provide an opt out for projects that do not want to follow this convention. I opened up an issue Enforce naming convention for modules · Issue #726 · fortran-lang/fpm · GitHub for it.

I’m of the opinion we should enforce this only on the “publishing” side, once we finally have an official registry/repository. I wouldn’t want a new user to get confused about this requirement.

2 Likes

New user to Fortran would follow the tutorial and fpm generated new project, so there would be no problem. For existing projects you would add an option to fpm.toml, and you would need some tailoring anyway. A nice error message saying “Rename a to mypackage_a” and pointing at the file is not confusing.

Here is a very simple example of duplicate modules with the same name. These 5 files go into the same directory.

! File t_duplicate_modules.f90

PROGRAM t_duplicate_modules

	USE m_duplicate

	WRITE(*,'("In PROGRAM t_duplicate_modules")')
	WRITE(*,*)module_version

	CALL s_duplicate_modules

END PROGRAM t_duplicate_modules


! File s_duplicate_modules.f90

SUBROUTINE s_duplicate_modules

	USE m_duplicate

	WRITE(*,'(/,"In SUBROUTINE s_duplicate_modules")')
	WRITE(*,*)module_version

END SUBROUTINE s_duplicate_modules


! File: m_duplicate_1.f90

MODULE m_duplicate

	CHARACTER(LEN=*),PARAMETER :: module_version = "Version 1"

END MODULE m_duplicate


! File: m_duplicate_2.f90

MODULE m_duplicate

	CHARACTER(LEN=*),PARAMETER :: module_version = "Version 2"

END MODULE m_duplicate


#!/bin/csh

# File: build.csh

gfortran -c m_duplicate_1.f90
gfortran -c t_duplicate_modules.f90

gfortran -c m_duplicate_2.f90
gfortran -c s_duplicate_modules.f90

gfortran -o t_duplicate.exe *.o

# End of build.csh


And when we run it we get:

john@gemsbok:~/projects/WinFPT/fpt/fpttest/duplicate_modules$ ./build.csh
john@gemsbok:~/projects/WinFPT/fpt/fpttest/duplicate_modules$ ./t_duplicate.exe
In PROGRAM t_duplicate_modules
 Version 1

In SUBROUTINE s_duplicate_modules
 Version 2

So we have 2 different modules with the same name in the same directory, and the compiler and linker can’t know.

As I posted earlier, this actually happened because modules with the same name were used to build 4 different libraries in the same project. I need a solution to this situation very soon, so what I propose for IDEs and analysis tools (at least for ours) is:

  1. We define “module domains” and put all primary Fortran files into domains.

ii. All top-level compilation units are tagged (internally in the tools) with their domains.

iii. The module names in MODULE and USE statements have scope limited to their domains.

This will solve simple cases like the one above. This information would be sufficient to create a Makefile.

However it will get more complicated than that. There will be overlapping domains, so we will need an hierarchy of domains.

Of course, for programs where this situation does not arise we can simply have a single default domain and there is no need for the domain construct. That is where we are now with fpt - we didn’t see this coming. We will, of course, create a command to rename the offending modules so that the code becomes standard conforming.

The coding of all this will take a day or two, so if anyone has any better ideas please tell me!

John

There are two different cases that an automatic tool needs to recognize. One is when there are two modules that both need to be used in the code that currently have the same name. In this case, the tool somehow needs to rename one or both of them, along with the corresponding USE statements. The other one is when there are several versions of the same *mod.f90 source codes in the directory. During development, it is not unusual to have several such files around, each of which might work using different algorithms, or designed toward different target environments, and so on. In this case, the programmer is responsible for compiling, loading, and executing the right combination of files, and the tool needs to be told to ignore the duplicate module names within these files.

Typically, such target-environment-dependent code might all be placed in a single source code, and the correct code blocks activated internally with conditional compilation macros. However, since fortran does not have a standard preprocessor for conditional compilation, many programmers prefer to avoid a preprocessor-based approach to this problem, and instead rely on the use of multiple files within the file system. Your automatic tool should probably attempt to accommodate both programming styles.

1 Like