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

sharing module between dll and main program in fortran

Pam_R_
Beginner
3,129 Views

i have a problem sharing module between dll and main program

there are 2 sub programs in dll

1) chf_cor

2) module main_data

subroutine chf_cor (i, chf, correlation)
!
! Subroutine to evaluate chf using 1 of 9 different correlations
!
use main_data
!
implicit none
!
!dec$ attributes dllexport :: chf_cor
!
character(*) correlation
integer(4) i
real(8) chf
!
character(50) correlation_name(10)
!
real(8) constants(10)
!
data correlation_name(1) / 'chf correlation 0 - bur & wub ' /
!
data constants / 1.0d0, 2.0d0, 3.0d0, 4.0d0, 5.0d0, 6.0d0, 7.0d0, 8.0d0, 9.0d0, 10.0d0 /
!
num_cor = 10
write(6,*) 'num_cor = ', num_cor
chf = constants(i)*prop(i)
correlation = correlation_name(i)
!
end subroutine chf_cor

module

module main_data
!
!dec$ attributes dllexport :: num_cor
!
integer(4), save :: num_cor
!
!
real(8), save :: prop(10)
!
end module main_data

i did compile and created dll with following command

ifort /dll chf_cor.f90 main_data.f90

this created chf_cor.lib

the main program using dll looks like this

program main
use main_data
!
implicit none
!
integer(4) i
real(8) chf
character(50) correlation
!
i = 1
! num_cor = 10
call chf_cor (i, chf, correlation) ! this call initializes num_cor
!
write(6,*) 'num_cor = ', num_cor
do i = 1,10
prop(i) = i*1.0d0
end do
!
do i = 1, num_cor
!
call chf_cor (i, chf, correlation)
!
write (6,9000) i, chf, correlation
end do
!
9000 format ('numb = ',i2,' chf = ',1p, e13.5,3x,a50)
end program main

the problem starts now

when i try to link .lib with main.f90

ifort /libs:dll main.f90 chf_cor.lib

i get an error saying liking error - unresolved external symbol referenced in program main

how do i resolve this ?

the only i way i can link if i use modules main_data.f90 again in main program

ifort /libs:dll main.f90 main_data.f90 chf_cor.lib

the only problem with this is the data in module is not sharable and does not reflect changes made by dll program in main program

help needed

0 Kudos
19 Replies
anthonyrichards
New Contributor III
3,129 Views

You should include INTERFACE blocks for all routines imported from your DLL (chf_cor being the only one visible in your code). These blocks should contain DLLIMPORT attributes for the symbols imported from the DLL so that thelinker knows where to find them.

If you have created CHF_COR.DLL and its accompanying export library CHF_COR.LIB, then add CHF_COR.LIB to your MAIN program solution. This should ensure the DLL is found and included when external references are satisfied. You still need to specify DLLIMPORT for the CHF_COR subprogram. Also, make sure that CHF_COR.DLL is copied to a location where the MAIN program can find it (into the same directory as the MAIN.EXE for example)

0 Kudos
Pam_R_
Beginner
3,129 Views

thanks for the prompt reply

this works ok, i have another problem with the same program

i am trying to share character data of module between dll and main program

as i understand it creates two copies of data objects.

i declared !DEC$ ATTRIBUTES DLLEXPORT :: ibaw2 in one of the modules shared by dll and main program

when main program starts evene before initializing ibaw2 - it gets some garbage values XD00, also it does not allow it to be over written by any subroutine.

when try to access ibaw2 in dll subroutine it still has the same garbage value.

without import/export the value is blank

help needed

thanks in advance

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
A sample DLL_Shared_Data is provided that illustrates how to share data using a DLL.
0 Kudos
Pam_R_
Beginner
3,129 Views

i can not find the sample code

can you send it again

thanks

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
It's part of the installed Intel Visual Fortran product, for example,

C:Program FilesIntelCompilerFortran10.1.024samplesDLLDLL_Shared_Data

This particular sample uses a single DLL whose variables are write-shared among two separate executables. This may be a bit more complex than you need, but the basic principles are similar as to how you declare things. If you're not sharing data among programs, just within a single program, then you don't need the linker option for read-write sharing.
0 Kudos
Brett_B_
Beginner
3,129 Views

Steve,

The example you reference indicates that the variables in the module to be shared must be initialized:

real

:: shared_variable = 999.0 ! Must initialize to non-zero value

! in order to be placed in .data section

I am trying to share an allocatable array,which is in a module, between a main program and a DLL. For instance:

MODULE KMODELT

INTEGER, ALLOCATABLE :: MODID(:)

!DEC$ ATTRIBUTES DLLEXPORT :: MODID

ENDMODULE KMODELT

I cannot initialize MODID as it is allocatable. So, is there a way to share a allocatable array in a modulein a DLL?

Thanks.

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
The comment in the example applies only when you are sharing data in a DLL between two or more separately running executables. Are you doing this?

An ALLOCATABLE array does not require anything special to be shared across EXEs in a DLL. A POINTER should be initialized to NULL() if shared.
0 Kudos
Brett_B_
Beginner
3,129 Views

Hi Steve,

No, I am just running one executable. I am trying to be able to access the MODID(:) array in the DLL via a USE statement.MODID has been allocated and assigned values in the the main program. When I call the subroutine that is part of the DLL, it seems not to know that the array has been allocated, and I get the error:

forrtl: severe (408): fort: (2): Subscript #1 of the array MODID has value 1 which is greater than the upper bound of -1

So, in my case, with just one executable, do I not need the /section:data,RWS liner command line directive?

Is there something else I need to do to be able to access the array in the DLL? Maybe a DLLIMPORT directive in the subroutine within the DLL?

Thanks for your help.

Brett Bednarcyk

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,129 Views

>>An ALLOCATABLE array does not require anything special to be shared across EXEs in a DLL.

!!???!!

Explain please why if the array descriptor "lives" in the DLL address space .AND. if one EXE of potentially several EXE's issues an allocate then how does the descriptor point globally (to all DLL users) allocated memory as opposed to memory within the EXE that performed the allocation?

It would seem like you would want to export the array descriptor in the EXE and import it (in EXE context) into the DLL. The the allocations are local to the EXE by visible to the DLL on an EXE by EXE basis. (each EXE has seperate area of memory with same name in DLL)

Alternately, with descriptor inside DLL you could perform a call from the EXE to the DLL with instructions to allocate memory from a pool mapable inside the DLL while addressable from EXE's using the DLL copy of the descriptor. This would not be a standard allocate as it would require specifying a seperate heap (one that grows in the DLL). (shared memory)

If you want shared memory amongst several processes consider using a memory mapped file from within the EXE and building descriptors to the memory mapped file. The function to perform this would be in the DLL. In this manner, each application gets its own array descriptor pointing at the same memory mapped file but which may reside at different virtual addresses within each process. If the process dies the processes handle(s) to the memory mapped file are closed and things are cleaned up. If you hack something into a common array descriptor inside the DLL you would not get this cleanup capability.

Jim Dempsey

0 Kudos
Brett_B_
Beginner
3,129 Views

Steve,

Apparently I do not know how to make any data in a module accessible in a DLL as I just changed things to try to access a REAL rather than the allocatable array and it did not work either - the value is wrong inside the DLL. Perhaps you could just outline how to access data in a module through the USE statement in a DLL, or point me to where I can find this.

One note - I have the module code in both the main program and the DLL projects - is this wrong? I needed to do this in order to get the DLL to link.

Thanks,

Brett

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
Yes, it is wrong to have the module code in both projects. Here is what to do.

The module source belongs in the DLL project. Add ATTRIBUTES DLLEXPORT directives for any items you want exported.

For the executable project, add the "output" folder of the DLL project (the Debug or Release) folder to the list of INCLUDE folders. Add a USE of the module to the executable project sources. It will pick up the .mod file from the DLL project.
0 Kudos
Reinaldo
Beginner
3,129 Views

Steve:

I have a similar problem, and I try to do what you suggest. However, still I am doing something wrong.

I have a Fortran EXE and a Fortran DLL. I need to access allocatable arrays from both. I wrote this module:

MODULE MODFLOW_GLOBAL
INTEGER, ALLOCATABLE, DIMENSION(:) :: MFL_COL
INTEGER, ALLOCATABLE, DIMENSION(:) :: MFL_ROW
CHARACTER(200) :: MFL_FILENAME
!DEC$ ATTRIBUTES DLLEXPORT :: MFL_COL, MFL_ROW
!DEC$ ATTRIBUTES DLLEXPORT :: MFL_FILENAME

END MODULE MODFLOW_GLOBAL

That I added as part of the DLL project. I then have the include directory where the correspoding MOD is in the EXE file.

I read the character variable in the EXE and allocate the arrays, butitis notright. THe values are not correct.

Couldyou help?

Thanks

Reinaldo

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
Reinaldo, I responded in your separate thread.
0 Kudos
Brett_B_
Beginner
3,129 Views

Steve,

Thank you for your excellent help - things seem to be working for me now.

I have a couple more quick questions that I hope you can answer:

1) Do the modules have to be in the DLL project? Is it not possible to put them in the EXE project and, within the DLL project,get the .mod files through the INCLUDE directory specification?

2) Is there a way to make all variables in a file or a module default to ATTRIBUTES DLLEXPORT without having to explicitly type the directive for each variable? I have hundreds of modules with thousands of variables, and it would help a lot to have short cut like this.

Thanks,

-----Brett

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
1) No - the modules have to be in the DLL project as that is where the variables and routines from the module are defined. The EXE is referencing them.

2) No. We have a wish-list item for this and I will add your request to it.
0 Kudos
jimdempseyatthecove
Honored Contributor III
3,129 Views

Brett,

<>

You could encapsulate the variables in a moduleinto a user declared type and create one instance of that type which is exported.

module mod_foo
type Type_mod_foo
real :: A,B,C
...
end Type_mod_foo
cDEC$ ATTRIBUTES DLLEXPORT :: FOO
type(Type_mod_foo) :: FOO

However, this will require you to specify the container when referencing the variables

FOO%A

This can be hidden using the preprocessor FPP

#define A FOO%a
#defineB FOO%b

place the above in an include file that is not part of the module and is included in your source files.

But then debugging is a bit awkward (intellipoint won't work and you have to watch FOO%A instead of A)

Steve,

Can you look at extending the USE mapping capability to map fields of declared defined types to local variables

use mod_foo, FOO%A => A

Then a user such as Brett could accomplish the mapping with an ugly Fortran include file.

Alternately, extend EQUIVALENCE to accept a similar syntax (take plenty of barf bags to the next committee meeting when you suggest this).

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
Jim,

What you're asking for is sort of like the ASSOCIATE construct in F2003. The syntax looks like this:

ASSOCIATE (A => FOO%A)
... do things with A that are really FOO%A
END ASSOCIATE

Intel Fortran 10.1 does not support this, but it will come in the next major release, whenever that is....
0 Kudos
Brett_B_
Beginner
3,129 Views

I tried building the DLL in CVF rather than ifort, and it compiled and linked, but it is not running correctly when calling it from the ifort EXE project - I am getting an error about allocating an array that has already been allocated. This is with everything the same, only now building the DLL with CVF. I am using the CVF calling convention in the ifort projects. Also, because the subroutine in the DLL calls subroutines in the EXE, I had exposed these subroutines in the EXE with DLLEXPORT and included the resulting .LIB in the DLL project. As I said,this worked for the ifort DLL.Could this .LIB be the problem, or maybe the .MODS now being generated by the CVF DLL project? Or should this work and maybe I have an alignment issue or something screwing up the memory?

Thanks,

----Brett

0 Kudos
Steven_L_Intel1
Employee
3,129 Views
Did you set the "use runtime libraries" setting in the EXE project to the DLL libraries? It should work if you recompiled everything.
0 Kudos
Reply