Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28459 Discussions

Sharing module variables from one DLL to another DLL

Elias_Sabbagh
Beginner
428 Views
Hi folks:

I've got a few DLLs that I'm trying to link into a larger program, and I'm getting some LNK2001 errors.

The first DLL has some general-purpose Gaussian integration routines. There are a few modules named gausspoints and gaussweights that define arrays used in Gaussian integration:

[bash]module gausspoints
use kinds
implicit none

real(dk), parameter :: PTS2(1) = (/0.577350269189626_dk/)
real(dk), parameter ::  PTS3(2) = (/0.0_dk,0.774596669241483_dk/)
real(dk), parameter ::  PTS4(2) = (/0.339981043584856_dk,0.861136311594053_dk/)
real(dk), parameter ::  PTS5(3) = (/0.0_dk,0.538469310105683_dk,0.906179845938664_dk/)

! ...etc, etc.

end module gausspoints[/bash]

The gaussweights module is similar. There's also a module, gaussint, that USEs these "data" modules to perform the integration.

The second DLL contains a module function that is using a Gaussian integration routine found in the first DLL. Both this second DLL's function and the first DLL's integration routine are DLLEXPORT'ed. Here's the code of interest:

[bash]module hankint
use kinds
implicit none


type TSHankint_vars
	real(sk) r1
	complex(sk) a
end type TSHankint_vars
type TDHankint_vars
	real(dk) r1
	complex(dk) a
end type TDHankint_vars

interface hanki1
	module procedure hanki1,dhanki1
end interface hanki1

contains


complex(sk) function hanki1(a,r1,r2) result(res)
!DEC$ ATTRIBUTES DLLEXPORT::hanki1
use gausint
implicit none
real(sk), intent(in) :: r1 ! lower limit of integral defining hanki1
real(sk), intent(in) :: r2 ! upper limit of integral defining hanki1
complex(sk), intent(in) :: a ! complex parameter of hanki1

type(TSHankint_vars) args

args%a = a
args%r1 = r1
! Use 30 point Gauss integration to evaluate hanki1
if(.not.cgauss(30,hnkin1,r1,r2,res)) then
! FIX ME:  Handle error here.
endif

contains

  complex(sk) function hnkin1 result(res)
  use scalpack
  implicit none
  real(sk), intent(in) :: r

  integer(ik) ierr, ncount
  complex(sk) sch0 ! scaled Hankel function of order 0
  complex(sk) sch1 ! scaled Hankel function of order 1

  call schank(args%a*r,sch0,sch1,ierr,ncount)
  res = r*exp( -(0.0_sk,1.0_sk)*args%a*(r-args%r1) )*sch1
  end function hnkin1

end function hanki1


complex(dk) function dhanki1(a,r1,r2) result(res)
use gausint
implicit none
real(dk), intent(in) :: r1 ! lower limit of integral defining hanki1
real(dk), intent(in) :: r2 ! upper limit of integral defining hanki1
complex(dk), intent(in) :: a ! complex parameter of hanki1

type(TDHankint_vars) args

args%a = a
args%r1 = r1
! Use 30 point Gauss integration
if(.not.cgauss(30,dhnkin1,r1,r2,res)) then
! FIX ME:  Handle error here.
endif

contains

  complex(dk) function dhnkin1 result(res)
  use scalpack
  implicit none
  real(dk), intent(in) :: r

  integer(ik) ierr, ncount
  complex(dk) sch0 ! scaled Hankel function of order 0
  complex(dk) sch1 ! scaled Hankel function of order 1

  call schank(args%a*r,sch0,sch1,ierr,ncount)
  res = r*exp( -(0.0_dk,1.0_dk)*args%a*(r-args%r1) )*sch1
  end function dhnkin1

end function dhanki1


end module hankint[/bash]


The USE of the gaussint module drags in the dependencies on the gausspoints and gaussweights modules.

Everything compiles OK, so I'm pretty sure that my project options settings for the second DLL are set up properly -- all of the USE statements seem to be able to see the .lib file and modules modules living a few folders over in the first DLL's ./Debug folder. But when it comes time to link, I see:

[bash]Error	1	 error LNK2001: unresolved external symbol _GAUSSWEIGHTS_mp_WTS32	hankint.obj	
Error	2	 error LNK2001: unresolved external symbol _GAUSSPOINTS_mp_PTS32	hankint.obj	
Error	3	 error LNK2001: unresolved external symbol _GAUSSWEIGHTS_mp_WTS30	hankint.obj	
Error	4	 error LNK2001: unresolved external symbol _GAUSSPOINTS_mp_PTS30	hankint.obj	
.
. (etc)
.
Error	19	 error LNK2001: unresolved external symbol _GAUSSWEIGHTS_mp_WTS3	hankint.obj	
Error	20	 error LNK2001: unresolved external symbol _GAUSSPOINTS_mp_PTS3	hankint.obj	
Error	21	 error LNK2001: unresolved external symbol _GAUSSWEIGHTS_mp_WTS2	hankint.obj	
Error	22	 error LNK2001: unresolved external symbol _GAUSSPOINTS_mp_PTS2	hankint.obj	
Error	23	 fatal error LNK1120: 22 unresolved externals	Debug/besshankint.dll	
[/bash]

I'm a little confused as to whats going on here! I didn't think that I'd need to DLLEXPORT the "private" data that the first DLL is using, just to call one of its functions from a function in the second DLL.

Any ideas?

Thanks,

Elias Sabbagh
Victor Technologies, LLC
0 Kudos
1 Solution
Steven_L_Intel1
Employee
428 Views
As you found, PARAMETER constants, which are not variables, cannot be DLLEXPORTed. By removing the PARAMETER attribute you make them into initialized variables, which are exportable.

View solution in original post

0 Kudos
4 Replies
Elias_Sabbagh
Beginner
428 Views
Hi folks:

OK, things get better if I remove the "parameter" attribute from the type definitions in the gausspoints module. At that point, everything links up fine.

Thanks,

Elias Sabbagh
Victor Technologies, LLC
0 Kudos
Steven_L_Intel1
Employee
429 Views
As you found, PARAMETER constants, which are not variables, cannot be DLLEXPORTed. By removing the PARAMETER attribute you make them into initialized variables, which are exportable.
0 Kudos
jimdempseyatthecove
Honored Contributor III
428 Views
As you found, PARAMETER constants, which are not variables, cannot be DLLEXPORTed. By removing the PARAMETER attribute you make them into initialized variables, which are exportable.

Steve, having an odd thought here

Shared PARAMETERs are typically contained in a module, then USE'd by the interested parites. For an application solution where all sources could potentially get re-compiled a dependency check can notice a change in module containingPARAMETER and thus recompile the module, and then the dependencies of that module. For a DLL that is not sourced in the solution this would not be possible (dependency recompile). Therefore, a PARAMETER in the DLL might differ from that in the application .AND. there would be no link time indication that there is a difference. (Never mind the fact that if you change parameter in a module used by a DLL that you ought to recompile the DLL too.)

Consider then if a PARAMETER is marked for DLLEXPORT that a name/content mangled entity could be created that is functionally (to the linker) equivalent to a template created function bodyfor C++. In C++ normal linking rules inhibit multiple functions with the same signature. However, code generated with templates can (usually do) have multiple files generate the same function w/ same signature. To "fix" this, the linker was changed to recognize template generated functions and for those functions the function body was used as a comparand. Should the multiple (template)functions with the same signature have the same contents for function body, then the linker would ignore the additional instance. Should the contents of the function body differ then an error is reported (i.e. template code changed between compiles of different sources using the template).

What my suggestion means is, with this change: DLLEXPORTed PARAMETERS are ASSERTED equal by the linker (else link fails with appropriate error message).

Jim Dempsey
0 Kudos
Elias_Sabbagh
Beginner
428 Views
Steve-

Thanks for the reply. I should have mentioned that I'm using version 12.1 of the compiler. The origianl code (which included the PARAMETER attributes) actually compiled and linked up fine using the old IVF 8.* compiler, so obviously something's been tightened up (or loosened!) since then.

I've got a lot of Fortran 2003/2008 to learn...

Elias Sabbagh
Victor Technologies, LLC
0 Kudos
Reply