Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29282 Discussions

Assumed-shape array arguments in DLL procedures

forall
Beginner
1,159 Views
I am creating a DLL that contains F-95 subroutines where some arguments are assumed-shape arrays, pointers, assumed-length strings, etc. This doesnt seem to work correctly.

In particular I am unable to use assumed-shape arrays as arguments in DLL procedures. Curiously the code executes but the results are wrong. I checked using CVF and results there also seem wrong (and different to IVF)

Presumably this is due to array descriptors being passed along with the arrays themselves and not being handled correctly when the DLL is loaded. Any way to resolve this? I attach a code snippet. The explicit-sized array works, but a solution allowing F-95 functionality would be vastly helpful. Help much appreciated as usual.

!*****************************************************************
module mod
implicit none
public
integer(4),SAVE::ncalls
!DEC$ ATTRIBUTES dllexport :: ncalls
contains
!----------------------------------------------------
subroutine proc_mod(n,argWorks,argFails)
!DEC$ ATTRIBUTES dllexport, c :: proc_mod
!DEC$ ATTRIBUTES reference :: argWorks,argFails
implicit none
integer(4),intent(in)::n,argWorks(n),argFails(:)

0 Kudos
1 Solution
Steven_L_Intel1
Employee
1,159 Views
Quoting - forall
1) Is all F-95 functionality (pointers, derived types, etc) available when linking via DLL interface? I assume things like temporary copies are still done for non-contiguous arrays when when ATTRIBUTES reference is specified but otherwise pass-by-reference works identically to jointly-compiled F-95 code?

2) In some cases I am unable to "step into" DLL-based code (Fortran, project on same machine, etc). This doesnt always happen, I havent got a short demo code yet - should I try to generate one or is this issue known and/or otherwise resolvable?

3) When building an application that will use a DLL, say, X.DLL, I still need the X.LIB file. This seems to contradict the advantage of using a DLL in the first place if I have to rebuild the calling code everytime the DLL is updated. Or am I missing something obvious?

4) Is it possible to specify a path for DLL files in the project settings of a specific project - to avoid copy/pastying the DLL or having to declare windows-wide or IVF-wide BIN paths for DLLs that are just being tested before moved to a designated BIN path? Its this path manipulation that cause my error leading to the previous post.

1) Yes. There is no difference between calling a DLL routine and calling a statically linked routine.

2) I step into DLL code all the time. Usually, such problems are caused by the DLL you're using not being the one that was built by the current solution.

3) If the DLL is updated, you don't NEED to rebuild the executable, and hence don't need the .LIB. If you choose to rebuild the executable, you'll need the .LIB that corresponds to the DLL you want to use. This assumes you don't break existing interfaces.

4) No, but what I do is add a post-link build step that copies the built DLL into the Debug or Release folder of the executable project, or some other common place you want to use.

View solution in original post

0 Kudos
5 Replies
Steven_L_Intel1
Employee
1,159 Views
Please show the code you're using to call this. A complete example would be helpful. The symptoms suggest the lack of an explicit interface visible to the caller - do you USE the module and is it the same .mod as created by building the DLL?
0 Kudos
forall
Beginner
1,159 Views
Steve - thanks for the quick and helpful reply - even if it leads to my embarassment.

Indeed I mixed-up the paths (debug/release) of the DLL and was loading the wrong one. Now the assumed-shape arguments work correctly - in CVF & IVF :-)

I was USEing the module and the explicit interface was visible, just the wrong files.. ouch..

I still have a couple of DLL-related questions (not sure if they warrant independent threads - what is the forums policy in this respect? - I suspect/hope you answers are one-liners):

1) Is all F-95 functionality (pointers, derived types, etc) available when linking via DLL interface? I assume things like temporary copies are still done for non-contiguous arrays when when ATTRIBUTES reference is specified but otherwise pass-by-reference works identically to jointly-compiled F-95 code?

2) In some cases I am unable to "step into" DLL-based code (Fortran, project on same machine, etc). This doesnt always happen, I havent got a short demo code yet - should I try to generate one or is this issue known and/or otherwise resolvable?

3) When building an application that will use a DLL, say, X.DLL, I still need the X.LIB file. This seems to contradict the advantage of using a DLL in the first place if I have to rebuild the calling code everytime the DLL is updated. Or am I missing something obvious?

4) Is it possible to specify a path for DLL files in the project settings of a specific project - to avoid copy/pastying the DLL or having to declare windows-wide or IVF-wide BIN paths for DLLs that are just being tested before moved to a designated BIN path? Its this path manipulation that cause my error leading to the previous post.

thanks again!
dmitri

PS - The complete code (now working) is

!*****************************************************************
! this code built as DLL
module mod
implicit none
public
integer(4),SAVE::ncalls
!DEC$ ATTRIBUTES dllexport :: ncalls
contains
!----------------------------------------------------
subroutine proc_mod(n,argWorks,argFails,sumWorks,sumFails)
!DEC$ ATTRIBUTES dllexport, c :: proc_mod
!DEC$ ATTRIBUTES reference :: n,argWorks,argFails,sumWorks,sumFails
implicit none
integer(4),intent(in)::n,argWorks(n),argFails(:)
integer(4),intent(out)::sumWorks,sumFails
sumWorks=sum(argWorks); sumFails=sum(argFails)
endsubroutine proc_mod
!----------------------------------------------------
endmodule mod


!*****************************************************************
! This code built as console linking to DLL
program main
use mod,only:proc_mod,ncalls
implicit none
! Locals
integer(4),parameter::n=2
integer(4)::argWorks(n),argFails(n),sumWorks,sumFails

argWorks=(/1,10/)
argFails=argWorks

sumWorks=-999; sumFails=-999

ncalls=0 ! this is a module variable

write(*,*)n,argWorks,argFails,sumWorks,sumFails
call proc_mod(n,argWorks,argFails,sumWorks,sumFails)
write(*,*)n,argWorks,argFails,sumWorks,sumFails

endprogram main
!******************************************************************

0 Kudos
Steven_L_Intel1
Employee
1,160 Views
Quoting - forall
1) Is all F-95 functionality (pointers, derived types, etc) available when linking via DLL interface? I assume things like temporary copies are still done for non-contiguous arrays when when ATTRIBUTES reference is specified but otherwise pass-by-reference works identically to jointly-compiled F-95 code?

2) In some cases I am unable to "step into" DLL-based code (Fortran, project on same machine, etc). This doesnt always happen, I havent got a short demo code yet - should I try to generate one or is this issue known and/or otherwise resolvable?

3) When building an application that will use a DLL, say, X.DLL, I still need the X.LIB file. This seems to contradict the advantage of using a DLL in the first place if I have to rebuild the calling code everytime the DLL is updated. Or am I missing something obvious?

4) Is it possible to specify a path for DLL files in the project settings of a specific project - to avoid copy/pastying the DLL or having to declare windows-wide or IVF-wide BIN paths for DLLs that are just being tested before moved to a designated BIN path? Its this path manipulation that cause my error leading to the previous post.

1) Yes. There is no difference between calling a DLL routine and calling a statically linked routine.

2) I step into DLL code all the time. Usually, such problems are caused by the DLL you're using not being the one that was built by the current solution.

3) If the DLL is updated, you don't NEED to rebuild the executable, and hence don't need the .LIB. If you choose to rebuild the executable, you'll need the .LIB that corresponds to the DLL you want to use. This assumes you don't break existing interfaces.

4) No, but what I do is add a post-link build step that copies the built DLL into the Debug or Release folder of the executable project, or some other common place you want to use.
0 Kudos
forall
Beginner
1,159 Views
3) If the DLL is updated, you don't NEED to rebuild the executable, and hence don't need the .LIB. If you choose to rebuild the executable, you'll need the .LIB that corresponds to the DLL you want to use. This assumes you don't break existing interfaces.

Thanks Steve,

Does your point 3) above mean that the following is a safe/standard approach to building distributable EXE files that link against other people's DLLs?

0) [done on separate 'user' machine] build a file X.f90 as DLL, producing X.DLL (and X.LIB)


The following steps done on the "developer" machine

1) create a dummy X0.f90 file that contains the 'shell/interface' of procedure X, ie, just the interface with no internal content.
2) build the X0.f90 file as DLL, producing X0.LIB (and X0.DLL)
3) build application A using X0.LIB, producing A.EXE
4) when running A.EXE, dynamically link against the 'full' X.DLL

when updating..
5) when the user updates X.f90 (keeping exactly the same interface), no need to rebuild A.EXE - just need the new X.DLL (but not the new X.LIB)

Is this the standard approach or is there a better way? Just seems a bit like 'cheating' that may not work in general - unless the LIB file is guaranteed to contain only the interfaces.

thanks in advance!
d

btw - I continue to find this forum exceedingly helpful after years of use! - saves tonnes of frustrating blind experimentation time - and is more reliable because just because it works in an experiment doesnt mean it works in general!
0 Kudos
Steven_L_Intel1
Employee
1,159 Views
Here's what I recommend:

Code your routines in modules, In each routine, add a DLLEXPORT attribute. Build the DLL. For your end-users, share the .mod and the export .lib. Neither contains any code. When the end-user USEs the module, it will get all the declarations of the public routines and symbols and the DLLEXPORTs will turn into DLLIMPORTs.

You don't have to use modules, though for Fortran users I think it is best. Otherwise just share the .lib. It contains only instructions to the linker for how to resolve the DLLEXPORTed routines.

If the implementation of routines in the DLL changes but not the public interfaces, updating the DLL is all you need to do.

Thanks for your kind words about the forum!
0 Kudos
Reply