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

DEC$ ATTRIBUTES DLLEXPORT attribute can not be assigned to an internal procedure

Dominic_C_1
Beginner
746 Views

Hi,

I am trying to expose some Fortran subroutines in a DLL.
I didn't write the Fortran code, and I'm having some difficulties creating the DLL.


The Fortran code is something like this (simplified):

! ===========================================================================
 
 ! Some declarations, initialisations etc
 
 contains
 
   subroutine Initialisation

   !DEC$ ATTRIBUTES DLLEXPORT::Initialisation

   !Do some stuff here   
   
   end subroutine Initialisation
   
! ===========================================================================

I keep getting this error:

DEC$ ATTRIBUTES DLLEXPORT attribute can not be assigned to an internal procedure.

I understand that this is because the subroutine is define underneath the "contains" keyword.

I've tried removing this but then I get a load more errors, so i'd rather not go down that route.

Is there an easy was of getting round this problem? I have googled for the error message but can't find a solution

Thanks

Dom

0 Kudos
1 Solution
Arjen_Markus
Honored Contributor I
746 Views

Not necessarily.

You could turn the program and the internal routine into a module. Something along these lines:

module myprogram

     ... declarations of the variables in the current main program

contains

subroutine the_old_program( only_init )

    logical :: only_init ! Use this to only initialise the variables that are needed in the internal routine

    ....

    if ( only_init ) then

       ....

   endif

   ...

end subroutine the_old_program

subroutine initialisation( .... )

   ! The current internal routine

   ...

end subroutine initialisation

end module myprogram

 

To use the_old_program subroutine in the testing context, use:

program test_myprogram

    use test_myprogram

    call the_old_program( .false. )

end program test_myprogram

 

Well, just a sketch.

 

Regards,

Arjen

 

View solution in original post

0 Kudos
8 Replies
Arjen_Markus
Honored Contributor I
746 Views

You say it is an internal routine, but from the code it is not clear whether it is an internal routine (so belonging to a function or a subroutine) or a module procedure. If it is indeed an internal routine it can only be invoked from within the containing function or subroutine - whether it is all part of a DLL or a static library. If it is a module procedure, then it can be invoked from the outside, but it has to have the public attribute (which is the default).

Since it is not entirely clear what you have exactly, here are two fragments to show both situations:
 

integer function myfunc( x )

     integer, intent(in) :: x

     call my_helper( x, myfunc )

    ...

contains

subroutine my_helper( x, y ) ! Inside the function, so invisible from the outside!

     integer :: x, y

     ... do something useful ...

end subroutine my_helper

end function myfunc

And the other one is:

module mymodule

     private :: my_helper

contains
integer function myfunc( x )

     call my_helper( x, myfunc )

    ...

end function myfunc 

...

subroutine my_helper( x, y ) ! Outside the function, but inside the module - note the private attribute

     integer :: x, y

     ... do something useful ...

end subroutine my_helper

end module mymodule

 

0 Kudos
Dominic_C_1
Beginner
746 Views

Hi, thanks for the reply

The subroutine doesn't belong to a function or a subroutine, or a module. It belongs to the program (I really am unfamiliar with Fortran, and as I say, it's not my code).

The code is something like this (in fact, you can copy this dummy code exactly to get the error message I describe):

program MY_PROGRAM 

! ===========================================================================
! ===========================================================================

  implicit none

! Lots of declarations here

! ===========================================================================
! ===========================================================================

  call Initialisation

!! ===========================================================================
!! ===========================================================================
                                                                                
 contains
                                                                                
! ===========================================================================
! ===========================================================================

   subroutine Initialisation

   !DEC$ ATTRIBUTES DLLEXPORT::Initialisation
   
   end subroutine Initialisation
   
end program MY_PROGRAM

0 Kudos
Arjen_Markus
Honored Contributor I
746 Views

Right, that is a situation I forgot about :).

Since it is part of a program, it is meant to be used in conjunction with that program. That leads me to the question why this particular routine should be used outside it? Do you want to turn the program as such into a library for use in another program or is it simply this routine? Note that whatever your answer, you will have to adjust the code to a certain extent.

Regards,

Arjen

 

 

0 Kudos
Dominic_C_1
Beginner
746 Views

Hi Arjen,

It is simply this routine that I wish to call externally (actually, there are a few more routines that I wish to use, but in the same manner).

I'm not interested in the program (the program is just really a testbed which calls the subroutines in the same way that I wish to call them externally).

 

 

 

0 Kudos
Steven_L_Intel1
Employee
746 Views

You can't do this. An internal procedure requires context of its host to be passed and that's not available if you try to make it "external".

If the internal procedures don't need to inherit variables from the main program, move them to a module and USE the module from the main program. Then you can export them.

0 Kudos
Dominic_C_1
Beginner
746 Views

Hi Steve,

Thanks for your reply

The internal procedures DO need to use variables that are declared in the main program.

I guess this is the problem I face.

I had previously been using the Silverfrost Fortran compiler to make a DLL, and that seemed to let me do what I wanted (expose internal procedures which had everything in scope when I ran them externally).

But then I ran into compile issues (because the Fortran developer who writes the code uses the Intel compiler, so I switched to Intel also).

Now I have these DLL issues. I don't really know what the best solution is to this. Probably get the Fortran developer to fix the Silverfrost compile issues and proceed from there.

Thanks

0 Kudos
Arjen_Markus
Honored Contributor I
747 Views

Not necessarily.

You could turn the program and the internal routine into a module. Something along these lines:

module myprogram

     ... declarations of the variables in the current main program

contains

subroutine the_old_program( only_init )

    logical :: only_init ! Use this to only initialise the variables that are needed in the internal routine

    ....

    if ( only_init ) then

       ....

   endif

   ...

end subroutine the_old_program

subroutine initialisation( .... )

   ! The current internal routine

   ...

end subroutine initialisation

end module myprogram

 

To use the_old_program subroutine in the testing context, use:

program test_myprogram

    use test_myprogram

    call the_old_program( .false. )

end program test_myprogram

 

Well, just a sketch.

 

Regards,

Arjen

 

0 Kudos
Dominic_C_1
Beginner
746 Views

Thanks Arjen, that worked! :-)

The DLL has been created, and dependency walker shows the exported functions in the function list.

So my current problem has been solved.

Thanks very much

Dom

0 Kudos
Reply