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

XE2017 !DEC$ not permitted

DavidWhite
Valued Contributor II
559 Views
In XE2016, this code works for me, so that I can then load and call the relevant function out of a DLL:

            ABSTRACT INTERFACE
                Subroutine DragCoeff_int(Reynolds, Sphericity, Value, Units)
                    !DEC$  ATTRIBUTES STDCALL, ALIAS:'DragCoeff_int' :: DragCoeff_int
                    !DEC$  ATTRIBUTES REFERENCE :: Units
                    IMPLICIT NONE
                    Real(KIND=KIND(0D0)), INTENT(IN), DIMENSION(1) :: Reynolds, Sphericity
                    Real(KIND=KIND(0D0)), INTENT(OUT), DIMENSION(1) :: Value
                    Character(LEN=20), INTENT(INOUT) :: Units
                End Subroutine DragCoeff_int
            END INTERFACE
            
            PROCEDURE(DragCoeff_int), pointer :: DragCoeff_F

            NAME = "DragCoeff_F"
            Reynolds = 0.7083D0; Sphericity = 0.90D0; Expected = 57.35006
            p_USERFUNC = getprocaddress(hModule=dll_handle, lpProcName=TRIM(NAME)//C_NULL_CHAR)
            if (p_USERFUNC == NULL) then
                Write(*,*) "Function not found: "//TRIM(NAME)
                NumTest = NumTest + 1
            ELSE
                CALL C_F_PROCPOINTER(TRANSFER(p_USERFUNC, C_NULL_FUNPTR), DragCoeff_F)
                CALL DragCoeff_F(Reynolds, Sphericity, Value, Units)
            END IF

XE2017 objects to the !DEC$ statements.  What do I need to do to make my code compliant with XE2017?  I have used this technique 100's of tmes in my application, so changing this is going to be a major job.

Thanks,

David

0 Kudos
14 Replies
DavidWhite
Valued Contributor II
559 Views

I should note that my code is similar to the DynamicLoad example, where the comments state that the !DEC$ ATTRIBUTES directive will be required where STDCALL is used, which is the case for my DLL, since it is called from VBA as well.

XE2017 does not permit this directive.

[On a separate issue - the forum would not let me edit my post, reporting Access Denied]

David

0 Kudos
Xiaoping_D_Intel
Employee
559 Views

I tried your code and found the error message by 17.0 is against the "ALIAS" attribute.

For a procedure pointer get assigned by calling "getprocaddress" it doesn't need such an attribute in the abstract interface declaration.

 

Thanks,

Xiaoping Duan

Intel Customer Support

0 Kudos
andrew_4619
Honored Contributor II
559 Views

The forum doesn't allow edits of post #1 which has been the case for a long time....

0 Kudos
mecej4
Honored Contributor III
559 Views

Aliases are appropriate for actual procedures, not for abstract interfaces. A procedure is a specific instance of the class of possible procedures with the interface as declared in the abstract interface, so the ALIAS clause could be specified in a directive for DragCoeff_F, but not for the abstract interface DragCoeff_Int.

0 Kudos
Steven_L_Intel1
Employee
559 Views

Right - it was a bug to accept ALIAS in an ABSTRACT INTERFACE. We fixed the bug.

0 Kudos
Matteo_S_
Beginner
559 Views

Dear All,

I'm facing a similar problem with ABSTRACT INTERFACE in XE2017 using Visual Studio 2015 Community Ed.

I need to recompile a code that was originally compiled with Visual Studio 2013 Community Ed with Intel Visual Fortran Composer XE 2013 SP1.

The compiler gives me error in the 3 lines (25, 38, 56) where there is the attribute ALIAS. Having read this topic, I removed it from those 3 lines but then it gives me error in the same lines telling me that the other attributes are not valid.

MODULE OrcaFlexInterface

   USE NWTC_Library
   USE NWTC_LAPACK

   USE OrcaFlexInterface_Parameters
   USE OrcaFlexInterface_Types

   USE, INTRINSIC             :: ISO_C_Binding


   IMPLICIT NONE

   PRIVATE


   ABSTRACT INTERFACE      ! These are interfaces to the DLL

#ifdef __GFORTRAN__
      SUBROUTINE OrcaFlexUserPtfmLdInitialise(DT,TMax)   BIND(C)
#else
      SUBROUTINE OrcaFlexUserPtfmLdInitialise(DT,TMax)   !!!BIND(C)
#endif
         USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'OrcaFlexUserPtfmLdInitialise'::OrcaFlexUserPtfmLdInitialise
         !GCC$ ATTRIBUTES STDCALL :: OrcaFlexUserPtfmLdInitialise
         REAL(C_FLOAT),             INTENT(IN   )  :: DT
         REAL(C_FLOAT),             INTENT(IN   )  :: TMax
      END SUBROUTINE OrcaFlexUserPtfmLdInitialise


#ifdef __GFORTRAN__
      SUBROUTINE OrcaFlexUserPtfmLd( X, XD, ZTime, DirRoot, PtfmAM, PtfmFt) BIND(C)
#else
      SUBROUTINE OrcaFlexUserPtfmLd( X, XD, ZTime, DirRoot, PtfmAM, PtfmFt) !!!BIND(C)
#endif
         USE, INTRINSIC :: ISO_C_Binding, ONLY: C_FLOAT, C_CHAR
         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'OrcaFlexUserPtfmLd'::OrcaFlexUserPtfmLd
         !GCC$ ATTRIBUTES STDCALL :: OrcaFlexUserPtfmLd
         CHARACTER(KIND=C_CHAR),    INTENT(IN   )  :: DirRoot
         REAL(C_FLOAT),             INTENT(IN   )  :: X(6)           !< Translational and rotational displacement (m, radians) relative to inertial frame.
         REAL(C_FLOAT),             INTENT(IN   )  :: XD(6)          !< Translational and rotational velocity (m/s, radians/s) relative to inertial frame.
         REAL(C_FLOAT),             INTENT(IN   )  :: ZTime          !< Current time in seconds
         REAL(C_FLOAT),             INTENT(  OUT)  :: PtfmAM(6,6)    !< Added mass matrix (kg, kg-m, kg-m^2)
         REAL(C_FLOAT),             INTENT(  OUT)  :: PtfmFt(6)      !< Platform forces -- [3 translation (N), 3 moments (N-m)] at reference point.
      END SUBROUTINE OrcaFlexUserPtfmLd



#ifdef __GFORTRAN__
      SUBROUTINE OrcaFlexUserPtfmLdFinalise()  BIND(C)
#else
      SUBROUTINE OrcaFlexUserPtfmLdFinalise()  !!!BIND(C)
#endif
         USE, INTRINSIC :: ISO_C_BINDING
         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS: 'OrcaFlexUserPtfmLdFinalise'::OrcaFlexUserPtfmLdFinalise
         !GCC$ ATTRIBUTES STDCALL :: OrcaFlexUserPtfmLdFinalise
         ! There is no data to pass.
      END SUBROUTINE OrcaFlexUserPtfmLdFinalise

   END INTERFACE

.........

END MODULE OrcaFlexInterface

How can I fix it?

Thank you in advance.

Best regards,

Matteo Strada

 

0 Kudos
mecej4
Honored Contributor III
559 Views

It is not possible to address your question without knowing the calling conventions used by the library that you are attempting to link with. It appears to me that incompatible attributes have been piled on (for example, DEFAULT and STDCALL) in an attempt to get the compiler to accept the code without error messages. That is rarely a good strategy, since the resulting code will not run or, worse, run and give incorrect results. 

If you are able to call the library from gFortran using Fortran-C interoperability, you should be able to do the same from Intel Fortran. In other words, you should not require any #ifdef __GFORTRAN__ in your source code at all, and you should need no DEC$ directives in the code.

0 Kudos
IanH
Honored Contributor II
559 Views

I tried compiling the code in #7, with the ALIAS attributes removed, with ifort 17.0 update one, and it worked for me.

MODULE OrcaFlexInterface

!   USE NWTC_Library
!   USE NWTC_LAPACK

!   USE OrcaFlexInterface_Parameters
!   USE OrcaFlexInterface_Types

!   USE, INTRINSIC             :: ISO_C_Binding


   IMPLICIT NONE

   PRIVATE


   ABSTRACT INTERFACE      ! These are interfaces to the DLL

#ifdef __GFORTRAN__
      SUBROUTINE OrcaFlexUserPtfmLdInitialise(DT,TMax)   BIND(C)
#else
      SUBROUTINE OrcaFlexUserPtfmLdInitialise(DT,TMax)   !!!BIND(C)
#endif
         USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_FLOAT
!         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'OrcaFlexUserPtfmLdInitialise'::OrcaFlexUserPtfmLdInitialise
         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE ::OrcaFlexUserPtfmLdInitialise
         !GCC$ ATTRIBUTES STDCALL :: OrcaFlexUserPtfmLdInitialise
         REAL(C_FLOAT),             INTENT(IN   )  :: DT
         REAL(C_FLOAT),             INTENT(IN   )  :: TMax
      END SUBROUTINE OrcaFlexUserPtfmLdInitialise


#ifdef __GFORTRAN__
      SUBROUTINE OrcaFlexUserPtfmLd( X, XD, ZTime, DirRoot, PtfmAM, PtfmFt) BIND(C)
#else
      SUBROUTINE OrcaFlexUserPtfmLd( X, XD, ZTime, DirRoot, PtfmAM, PtfmFt) !!!BIND(C)
#endif
         USE, INTRINSIC :: ISO_C_Binding, ONLY: C_FLOAT, C_CHAR
!         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'OrcaFlexUserPtfmLd'::OrcaFlexUserPtfmLd
         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE ::OrcaFlexUserPtfmLd
         !GCC$ ATTRIBUTES STDCALL :: OrcaFlexUserPtfmLd
         CHARACTER(KIND=C_CHAR),    INTENT(IN   )  :: DirRoot
         REAL(C_FLOAT),             INTENT(IN   )  :: X(6)           !< Translational and rotational displacement (m, radians) relative to inertial frame.
         REAL(C_FLOAT),             INTENT(IN   )  :: XD(6)          !< Translational and rotational velocity (m/s, radians/s) relative to inertial frame.
         REAL(C_FLOAT),             INTENT(IN   )  :: ZTime          !< Current time in seconds
         REAL(C_FLOAT),             INTENT(  OUT)  :: PtfmAM(6,6)    !< Added mass matrix (kg, kg-m, kg-m^2)
         REAL(C_FLOAT),             INTENT(  OUT)  :: PtfmFt(6)      !< Platform forces -- [3 translation (N), 3 moments (N-m)] at reference point.
      END SUBROUTINE OrcaFlexUserPtfmLd



#ifdef __GFORTRAN__
      SUBROUTINE OrcaFlexUserPtfmLdFinalise()  BIND(C)
#else
      SUBROUTINE OrcaFlexUserPtfmLdFinalise()  !!!BIND(C)
#endif
         USE, INTRINSIC :: ISO_C_BINDING
!         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS: 'OrcaFlexUserPtfmLdFinalise'::OrcaFlexUserPtfmLdFinalise
         !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE ::OrcaFlexUserPtfmLdFinalise
         !GCC$ ATTRIBUTES STDCALL :: OrcaFlexUserPtfmLdFinalise
         ! There is no data to pass.
      END SUBROUTINE OrcaFlexUserPtfmLdFinalise

   END INTERFACE

END MODULE OrcaFlexInterface

 

>ifort /c /fpp /warn:all "2017-01-12 alias.f90"
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on IA-32, Version 17.0.1.143 Build 20161005
Copyright (C) 1985-2016 Intel Corporation.  All rights reserved.

I don't think the decorate attribute is likely to be relevant for abstract interfaces anyway - you can probably delete it.  DEFAULT is only relevant if you are using wacky command line options or similar, in which case, stop using wacky command line options and then you can delete it too.

Note with the code as presented, I think there are going to be significant differences between the calling conventions used by gfortran and ifort. 

  • For ifort and gfortran, if BIND(C) is specified, regardless of STDCALL, then scalar arguments are passed by reference unless explicitly specified otherwise.  This is what your code does for gfortran.
  • For ifort, if STDCALL is specified without BIND(C), then scalar arguments are passed by value unless explicitly specified otherwise.  This is what your code does for ifort.
  • For gfortran, if STDCALL is specified without BIND(C), then scalar arguments are passed by reference unless explicitly specified otherwise.

Note that ifort as of some recent version (2016??) supports the use of BIND(C) and attributes STDCALL together, and (as far as I can tell, I'm not so familiar with gfortran) behaviour is consistent with gfortran when things are specified that way.

0 Kudos
Matteo_S_
Beginner
559 Views

Dear All

Thank you for your quick and accurate replies.

Now I have compiled the code that IanH posted and it worked. The problem was that I removed in a bad way the attribute ALIAS. 

IanH I would like to thank you for your patience in explaining me all of this, I really appreciate.

Best Regards,

Matteo Strada

0 Kudos
mecej4
Honored Contributor III
558 Views

You can modify the source code of your module and compile without error the modified code, but that is of little significance. What really matters is that the compiled code should conform with what the vendor library expects regarding the ABI. In particular, does the vendor library expect scalar arguments to be passed by value or address? What about its expectations regarding name decoration?

Is there a reason to use an abstract interface instead of a straightforward (i.e., concrete) interface? The following code, for example, makes use of the abstract interface but, if myInit() is the only routine with that interface, a simple interface would suffice and also be easier to understand.

program drvr
   use OrcaFlexInterface, only : OrcaFlexUserPtfmLdInitialise
   USE, INTRINSIC :: ISO_C_Binding, ONLY: C_FLOAT
   real (c_float) :: dtm, tmx
   procedure (OrcaFlexUserPtfmLdInitialise) :: myInit

   dtm = 1.5; tmx=7.5
   call myInit(dtm,tmx)
   write(*,*) dtm,tmx

end program

If, furthermore, the initialisation routine is actually named "OrcaFlexUserPtfmLdInitialise", there is no need to use an abstract interface at all.

0 Kudos
Matteo_S_
Beginner
558 Views

Dear mecej4,

Thank you for your reply.

I am sorry but I can't answer to your questions since I don't know how this part of the program works. I am working to another part of it. Furthermore this is an optional functionality of the program and I don't need it.

Nevertheless I need this module to be present in the source code since if I decided to eliminate this part, I would have been forced to modify a very large part of the whole program and this is not the case. 

So I just need to be able to compile the code, even if this part could be wrong.

I am sorry if I didn't have specified this before but I thought it would have had little importance.

Please tell me if this could impact the behaviour of the program, even if I don't use this part.

Thank you again.

Best regards,

Matteo Strada

0 Kudos
mecej4
Honored Contributor III
558 Views

To me the "first, do no harm (primum non nocere)" principle comes to mind. Since your module code, as shown, contains only declarations, i.e., no CONTAINS followed by subprogram code, there is no module code to be executed at all, so the question of correct/incorrect code does not apply. On the other hand, the module has probably a justification for its existence: it is probably USEd in some part of the code that you use when you build, even if you are not concerned with what that code does. If you modify the module source, you may cause that code to misbehave, and you will be held culpable. In effect, you could be hiding a small bomblet in the code.

I hope that there is some "project manager" who can decide and document how to proceed. Even if that project manager is just you, some discussion and documentation is definitely recommended.

0 Kudos
mecej4
Honored Contributor III
558 Views

In that case, I would place "Stop 'subroutine xxx entered unexpectedly' " statements as the first executable statement in each of those contained subroutines.

0 Kudos
Matteo_S_
Beginner
558 Views

Dear mecej4

The MODULE has a CONTAINS section just after the END INTERFACE line. I have omitted that section since it is very long: there are many subroutines that are used in the program ONLY IF I decide to use this functionality. Every call of one of these subroutines has to pass an "IF" control that checks if I decided to use it. For this reason I told you that I need this module to be in the code, otherwise I had to parse the whole source code excluding all those CALLs, and for the moment it is an hard work.

Best Regards,

Matteo Strada

EDIT:

Maybe I could be misunderstood. The main program calls these subroutines in this way:

 IF (Module_Orca) THEN
            
      CALL Orca_Init( ....)

 END IF
0 Kudos
Reply