forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

How to link code compiled by FTN95-64 with third-party DLLs

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> 64-bit
View previous topic :: View next topic  
Author Message
mecej4



Joined: 31 Oct 2006
Posts: 739

PostPosted: Thu Mar 16, 2017 12:53 pm    Post subject: How to link code compiled by FTN95-64 with third-party DLLs Reply with quote

I claimed in another thread that one could use routines contained in third-party DLLs from code compiled by FTN95-64. John Campbell asked me by private mail to provide a recipe, and I am responding here so that other readers interested in the topic can also see.

I give a how-to description using a very simple example. More complicated cases may respond to the same procedure, but you may run into difficulties if the DLL routines do I/O or the DLL was built with a different calling convention than the standard Windows-64 ABI (CDECL, first four arguments in RCX, RDX, R8 and R9, the rest on the stack, etc.), or there are descriptors to be passed, optional arguments are passed, there is global shared data, etc. Note also that it may be next to impossible to debug the mixed-pedigree program that you produce. It is best to test and debug the DLL routine in some native environment first.

Here is the example. A driver main program compiled with FTN95 calls a routine compiled with Gfortran which returns a vector that contains the elements of an input vector but in reverse order.

The code for the DLL, file rvec.f90:

Code:
subroutine reverse_vec(x,y,n)
implicit none
integer, intent(in) :: n
real, dimension(n), intent(in) :: x
real, dimension(n), intent(out) :: y
integer :: i

do i=1,n
   y(n+1-i) = x(i)
end do

return
end subroutine reverse_vec

We compile this into a DLL using Gfortran 6.2-64bit:
Code:
gfortran -shared -o rvec.dll rvec.f90


The driver program, tvec.f90:

Code:
program tvec
implicit none
C_EXTERNAL reverse_vec 'reverse_vec_'
real :: x(4) = [1,2,3,4], y(4)
write(*,*)x
call reverse_vec(x,y,4)
write(*,*)y
end program tvec


Compile and link the driver using FTN95:

Code:
ftn95 tvec.f90 /64
slink64 tvec.obj rvec.dll /file:tvec


You may note that the DLL is quite big. That is because it has a fixed overhead of having to contain the parts of the Gfortran runtime that the DLL routine needs.

Also note that the DLL does not have to be produced from Fortran code or be generated using Gfortran.
Back to top
View user's profile Send private message
John-Silver



Joined: 30 Jul 2013
Posts: 628

PostPosted: Fri Mar 17, 2017 6:55 pm    Post subject: Reply with quote

so basically it's just a question of declaring the dll outine via C:EXTERNAL in the calling program ?

Of course the called DLL must be 64 bit also I assume.

There's some documentation about using for calling a C++ DLL here .....

http://silverfrost.com/ftn95-help/mixlan/callingc_c__fromftn95.aspx
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 739

PostPosted: Fri Mar 17, 2017 8:17 pm    Post subject: Re: Reply with quote

John-Silver wrote:
so basically it's just a question of declaring the dll outine via C:EXTERNAL in the calling program ?

Even that is unnecessary if the external program uses the same name decoration that FTN95 does (all uppercase, no underscore appended). One should also note that "C" does not really mean that the external code has to be written in C, but that it must behave in the same way as C code compiled with a certain Fortran-compatible C compiler.

Quote:
Of course the called DLL must be 64 bit also I assume.

Of course.
Back to top
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 1833
Location: Sydney

PostPosted: Mon Mar 20, 2017 1:45 am    Post subject: Reply with quote

mecej4,

Thanks very much for your example. I have it working.

Now to experiment with what can be placed in the .dll and how to transfer information between the FTN95 memory and the .dll.

Functionality like multi-threading and some write reporting could be good.
Must this .dll be self sufficient or can it call FTN95 supplied routines ?

One thing I can't do is get an equivalent to Slink64's /map:tvec for the list of symbols in the .dll. When expanding the capabilities of "rcec.dll", it would be good to have a list of:
# what symbols are available to tvec.f90 from the .dll,
# what symbols are included in the rvec.dll build (library routines) and
# what other .dll's are required by rvec.dll

John
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 739

PostPosted: Mon Mar 20, 2017 3:26 am    Post subject: Reply with quote

It is easiest if you restrict yourself to passing data as routine arguments. Sharing global variables between a DLL and an EXE is complicated and errorprone. If more than one EXE may be running that depends on a DLL, you have to arrange for locks, etc. on those variables.

You can use the MS DUMPBIN utility or the GNU utility NM to display the symbols exported by a DLL. You can use Dependency Walker to list the other DLLs that are used by a specific DLL.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> 64-bit All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group