Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
Important Update: Community Platform Migration​. Learn more​>

Namespace collision

Dishaw__Jim
Beginner
1,492 Views
You have a solution with three projects in it (two libraries and an application). One library is called foo1 and the other is foo2. The foo1 library contains two modules, bar1 and baz and the foo2 library contains two modules, bar2 and baz. The baz module in each library is intended two be private to their respective library while the bar1 and bar2 would be used by some application.

The bar1 and bar2 modules use procedures from baz. Both baz modules each contain a routine called output, however the implementation of output is different.

The application is named foo and contains the following
PROGRAM foo

USE bar1, ONLY: f1_first => first
USE bar2, ONLY: f2_first => first

CALL f1_first
CALL f2_first

END PROGRAM foo

The subroutines bar1::first and bar2::first each call baz::output. The goal is that bar1::first should call baz::output that is defined in the foo1 project and bar2::first should call baz::output that is defined in the foo2 project. The baz::output namespace collides during linking and you only get one baz::output.

The description may be a bit confusing, so I have a VS solution that illustrates the issue. I can resolve the namespace collision if I maintain all the projects in the solution, however, it can be frustrating if one or more of the libraries are out of your control. Is there a method for avoiding a name space collision other than changing the name of the module? I was reading the documentation on the /EXPORT switch on lib, but I didn't see how one could specify which symbols to *not* include.


0 Kudos
4 Replies
Steven_L_Intel1
Employee
1,492 Views
Can't have two modules of the same name in an application - that's a language rule. You could isolate one of the libraries into a DLL, but perhaps that's a bit more than you want to do.
0 Kudos
Dishaw__Jim
Beginner
1,492 Views
I was hoping that having foo1 and foo2 as static libraries that it would--how is a DLL different than a static library? The problem does not appear to be within the Fortran compiler--because each library is compiled seperately, the compiler is agnostic of the other baz module. The problem, I think, appears to be in the linking stage. The procedures in the baz module have the same names, i.e.

foo1
bar1 names:
T _BAR1.
T _BAR1_mp_FIRST
U _BAZ_mp_OUTPUT

baz names:
T _BAZ.
T _BAZ_mp_OUTPUT
U _for_write_seq_lis

foo2
bar2 names
T _BAR2.
T _BAR2_mp_FIRST
U _BAZ_mp_OUTPUT

T _BAZ.
T _BAZ_mp_OUTPUT
U _for_write_seq_lis

When the linker creates the executable, only one _BAZ_mp_OUTPUT is linked in. I was hoping that the baz::output referenced in bar1 would be lexically scoped (if that is the correct phrase) within a foo1 name space before going to the global name space.
0 Kudos
Steven_L_Intel1
Employee
1,492 Views

You're right - it isn't the compiler - but you're still bound by the rule that relates to so called "class 1" global names, of which modules are such.Because the compiler uses the module name to "decorate" global symbols from the module, the rule about not having two modules with the same name means that there can't be a conflict. The linking is done in a global context and has nothing to do with lexical scope. The linker finds two object modules of the same name and picks one.

A DLL helps because all of the link-time references are resolved within the DLL. You choose which specific names to export.You still can't export BAZ::OUTPUT from two different BAZ modules, but it doesn't sound as if you want to do that.

My advice is to give up on forcing the linker to somehow include both modules and find another path. Either rename one of the modules or isolate one (or both) libraries in a DLL.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,492 Views

Try these suggestions

In each library use INTERFACE to define the interface to baz::output.

In bar1 interface to output use

!DEC$ ATTRIBUTES ALIAS 'bar1OUTPUT' :: 'OUTPUT'

In bar2 interface to output use

!DEC$ ATTRIBUTES ALIAS 'bar2OUTPUT' :: 'OUTPUT'

Or something similar.

Essentialy you are explicitly decorating OUTPUT.

The above should work for calls within the library to output. (intra library calls).

Selecting the appropriate output from outside could potentially be performed using a generic interface block

interface OUTPUT

subroutine bar1OUTPUT(foo1)
use BAR1
type(aBar1type) :: foo1
end subroutine bar1OUTPUT


subroutine bar2OUTPUT(foo2)
use BAR2
type(aBar2type) :: foo2
end subroutine bar2OUTPUT

end interface OUTPUT

The above would permit the application to use

call OUTPUT(someFoo)

and based upon the type of foo the appropriate barnOUTPUT would be called.

This does not solve the case where you want to pass intrinsic types onlye.g. integer, as there would be nothing to disambiguate the calls.

----------- Plan B (alternate method) -------------

The other route you can consider is FORTRAN permits you to have a variable of type EXTERNAL. This can be used to hold the address of a function.

Now in bar1 create a static variable of type external containing the address of the local OUTPUT. Do the same in bar2. You can now scope the variable containing the address of the function.

I have not written any test code to illustrate the pointer to function using multiple libraries.

I am writing some code now that is using pointer to function quite nicely. It works quite well even with calls between C++ and IVF.

Jim Dempsey

0 Kudos
Reply