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

additional include directories in FORTRAN subroutine

Atta_O_
Beginner
2,139 Views

I have written a subroutine in FORTRAN which is compiled and used by FEM software (works fine). Now I have developed a second FORTRAN program that works flawlessly in VS and needed to be integrated into the first subroutine. Considering the fact that I have no direct access to manipulate the connection between FEM and Intel Visual Fortran, some issues that I am facing are:

1) in VS I have defined "additional include directories" in GUI (Fortran/General); is it possible to define the same thing in line? I have seen people using importdll like commands in C# and F# but so far I could not find an equivalent form for FORTRAN. 

2) a similar issue is with "additional library directories" in linker which I have defined in VS but I can't really figure out how to add it in line for the subroutine. Needless to say that for both of these issues I have tried to copy all .dll files and .lib files in directories (include/library) of the FEM software and it did not help.

3) another issue is #include "*.h" in the subroutine which works fine in VS but in the report file of the compiler what I get is warning #5117: Bad # preprocessor line  which I believe is either related to issue 1 or 2 or the fact that the visual Fortran does not activate the preprocessor option automatically. For the latter case, I doubt since in the subroutine that I had tested before I used include 'aba_param.inc'   which worked fine. 

I am not sure but since in compile of the code that I have written in VS I used "additional dependencies" in Linker/input for two *.lib files I have added them to my subroutine following Steve's comment (https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/407609) 

!DEC$ OBJCOMMENT LIB:"*.lib"
4) I am using Microsoft Visual Studio 2012 and Intel(R) Visual Fortran Intel(R) 64 Compiler XE for applications running on Intel(R) 64. I have defined in platform in project properties.

As a shot in the dark, although .vfproj is only a XML file,  is it possible to use the .vfproj of the compiled VS which includes all of these configurations in my subroutine? (https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/392388)

Thanks in advance.

0 Kudos
30 Replies
Greg_T_
Valued Contributor I
1,800 Views

Is the first subroutine (called from the FEA solver) going to call the second subroutine to do some more calculations?  If yes, I would expect that both subroutines could be in the same source file, and linked to the FEA solver as you are doing now.  That should allow the first subroutine to locate the second subroutine.  Or is the second subroutine not called by the first subroutine?

0 Kudos
Atta_O_
Beginner
1,800 Views

Dear Greg, The first subroutine updates a variable in each time increment which works fine. The second program I have written and tested in VS separately only to debug and be sure about the required configs and it is aimed to apply some changes to this variable updating procedure. Long story short, I don't need to call the second program as another subroutine but to copy the content and adapt it inside the first one, however, I get a lot of issues as I described in my previous post.

0 Kudos
TimP
Honored Contributor III
1,800 Views

ifort requires /fpp flag to process # preprocessor directives, even though OpenMP (in general) requires fpp facility.  INCLUDE does not require any compile flag (unless there are embedded #).   fpp provided with ifort is not entirely identical with "traditional cpp" from other C compilers, so some people use explicit pre-processing e.g. using gcc tradcpp (but that may be difficult inside VS).

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,800 Views

In Visual Studio, you can declare a pre-build event. This can be a command line running a program or shell script or .bat file. This file can build the text containing the list of include files as #include statements. Then your program can include the include file containing the include statements.

It may be beneficial to create  separate project that used NMAKE to conditionally build the include file include file. In this way you can reduce the number of files being built.

Jim Dempsey

0 Kudos
Atta_O_
Beginner
1,800 Views

Tim P. wrote:

ifort requires /fpp flag to process # preprocessor directives, even though OpenMP (in general) requires fpp facility.  INCLUDE does not require any compile flag (unless there are embedded #).   fpp provided with ifort is not entirely identical with "traditional cpp" from other C compilers, so some people use explicit pre-processing e.g. using gcc tradcpp (but that may be difficult inside VS).

Correct me if I'm wrong, but isn't INCLUDE an fpp for ifort(FORTRAN) for preprocessor # directives? I still don't understand the application of gcc here. 

0 Kudos
Atta_O_
Beginner
1,800 Views

jimdempseyatthecove wrote:

In Visual Studio, you can declare a pre-build event. This can be a command line running a program or shell script or .bat file. This file can build the text containing the list of include files as #include statements. Then your program can include the include file containing the include statements.

It may be beneficial to create  separate project that used NMAKE to conditionally build the include file include file. In this way you can reduce the number of files being built.

Jim Dempsey

Jim, if I understand correctly what you refer to is to collect preprocessor variables in a file. If yes, do you believe I will be able to insert 'directory' into the search path for #include files by using -Idirectory option?

0 Kudos
Atta_O_
Beginner
1,800 Views

Dear Jim, I have read about pre-build events using .bat files which you have mentioned and it may solve both of my issues 1 and 2 in my original post. I was looking at the Path in environmental variables of the system and found two .bat files: vcvars64.bat and ifortvars.bat and by looking at their content, I found:

@if not "%WindowsSdkDir%" == "" (
    @set "PATH=%WindowsSdkDir%bin\x64;%WindowsSdkDir%bin\x86;%PATH%"
    @set "INCLUDE=%WindowsSdkDir%include\shared;%WindowsSdkDir%include\um;%WindowsSdkDir%include\winrt;%INCLUDE%"
    @set "LIB=%WindowsSdkDir%lib\win8\um\x64;%LIB%"
    @set "LIBPATH=%WindowsSdkDir%References\CommonConfiguration\Neutral;%ExtensionSDKDir%\Microsoft.VCLibs\11.0\References\CommonConfiguration\neutral;%LIBPATH%"

I have never done this before, but do you think I can add some directories to "INCLUDE" and "LIB" values?

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,800 Views

From my read of the posts were you had two issues:

a) A directory path wasn't present for some search (include, lib, etc...).
b) You have a unknown list of "*.h" files, in a specific folder, you wish to include (#include) into your program.

I was addressing b)

The proper place for your compile time paths is inside the Solution.
And, the proper place to runvcvars64.bat and/or ifortvars.bat is before running the VS IDE or ifort command line.

Typically, you should not do:

Start | Run | cmd

to launch a console window and then run ifort, etc...

You should:

Start | All Programs | Intel Parallel Studio XE 2016 | Compilers and Performance Libraries | Command Prompt with Intel Compiler 16.0 Update 1 | Intel Visual Studio 2013 environment

That will set the environment variables (you choose the appropriate compiler version and VS environment)

Now, when you get tired of doing that, instead of Left-Clicking on the last of the list, do a Right-Click, and Pin to the Task Bar or Start Menu.

Jim Dempsey

0 Kudos
Atta_O_
Beginner
1,800 Views

jimdempseyatthecove wrote:

From my read of the posts were you had two issues:

a) A directory path wasn't present for some search (include, lib, etc...).
b) You have a unknown list of "*.h" files, in a specific folder, you wish to include (#include) into your program.

I was addressing b)

Thanks Jim. I forgot to mention that I am using fixed format .for subroutine which is the cause of #5117: Bad # preprocessor line error. Based on your comment (https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/270192) I checked my code again and I am totally confused now.

Previously I used #include "fintrf.h" which had its own issues and I took the content and now this is my .for subroutine

c     user amplitude subroutine
      Subroutine uamp(
C          passed in for information and state variables
     *     ampName, time, ampValueOld, dt, nProps, props, nSvars, svars,
     *     lFlagsInfo, nSensor, sensorValues, sensorNames, 
     *     jSensorLookUpTable, 
C          to be defined
     *     ampValueNew, 
     *     lFlagsDefine,
     *     AmpDerivative, AmpSecDerivative, AmpIncIntegral,
     *     AmpIncDoubleIntegral)
      
      include 'aba_param.inc'

!DEC$ OBJCOMMENT LIB:"libeng.lib"
!DEC$ OBJCOMMENT LIB:"libmx.lib"  

#define mwPointer integer*8

...

Now I get  #5117 for the last line. I am totally confused at this moment.

0 Kudos
IanH
Honored Contributor II
1,800 Views

Atta O. wrote:

...

Previously I used #include "fintrf.h" which had its own issues and I took the content and now this is my .for subroutine

c     user amplitude subroutine
      Subroutine uamp(
C          passed in for information and state variables
     *     ampName, time, ampValueOld, dt, nProps, props, nSvars, svars,
     *     lFlagsInfo, nSensor, sensorValues, sensorNames, 
     *     jSensorLookUpTable, 
C          to be defined
     *     ampValueNew, 
     *     lFlagsDefine,
     *     AmpDerivative, AmpSecDerivative, AmpIncIntegral,
     *     AmpIncDoubleIntegral)
      
      include 'aba_param.inc'

!DEC$ OBJCOMMENT LIB:"libeng.lib"
!DEC$ OBJCOMMENT LIB:"libmx.lib"  

#define mwPointer integer*8

...

Now I get  #5117 for the last line. I am totally confused at this moment.

As Tim said in #4, you need /fpp to process the C preprocessor style source macros (the directives which start with #).  Are you compiling with that option?

(INCLUDE (no leading #) is standard Fortran - it does not require the C preprocessor)

Those last lines looks like you are referencing the matlab libraries.  I have a module that provides Fortran bindings to a good chunk of those libraries without requiring the preprocessor.  It isn't a drop in replacement for source written to the mathworks documented interfaces (mainly because they require the preprocessor), but it is pretty close.

0 Kudos
Atta_O_
Beginner
1,800 Views

ianh wrote:

Quote:

As Tim said in #4, you need /fpp to process the C preprocessor style source macros (the directives which start with #).  Are you compiling with that option?

(INCLUDE (no leading #) is standard Fortran - it does not require the C preprocessor)

Those last lines looks like you are referencing the matlab libraries.  I have a module that provides Fortran bindings to a good chunk of those libraries without requiring the preprocessor.  It isn't a drop in replacement for source written to the mathworks documented interfaces (mainly because they require the preprocessor), but it is pretty close.

Now I have replaced all of the preprocessing directives with their actual values. 

      !DEC$ OBJCOMMENT LIB:"libeng.lib"
      !DEC$ OBJCOMMENT LIB:"libmx.lib"  


      integer*8 mwPointer
      integer*8 mwSize
      integer*8 mwindex
      integer*8 mwSignedIndex

However, although this solves  #5117: Bad # preprocessor line error, apparently the required libraries are still missing or the include directories and I get error LNK2019.

Regarding the compiling option, I found the following environmental options (***.env) that are being used:

compile_fortran=['ifort',
                 '/c','/DABQ_WIN86_64', '/extend-source',
                 '/iface:cref', '/recursive', '/Qauto-scalar',
                 '/QxSSE3', '/QaxAVX', 
                 '/heap-arrays:1', 
                 # '/Od', '/Ob0'   # <-- Optimization 
                 # '/Zi',          # <-- Debugging
                 '/include:%I']

link_sl=['LINK',
         '/nologo', '/NOENTRY', '/INCREMENTAL:NO', '/subsystem:console', '/machine:AMD64',
         '/NODEFAULTLIB:LIBC.LIB', '/NODEFAULTLIB:LIBCMT.LIB',
         '/DEFAULTLIB:OLDNAMES.LIB', '/DEFAULTLIB:LIBIFCOREMD.LIB', '/DEFAULTLIB:LIBIFPORTMD', '/DEFAULTLIB:LIBMMD.LIB',
         '/DEFAULTLIB:kernel32.lib', '/DEFAULTLIB:user32.lib', '/DEFAULTLIB:advapi32.lib', '/DEFAULTLIB:libeng.lib',
         '/DEFAULTLIB:libmx.lib',
         '/FIXED:NO', '/dll',
         '/def:%E', '/out:%U', '%F', '%A', '%L', '%B', 
         'oldnames.lib', 'user32.lib', 'ws2_32.lib', 'netapi32.lib', 'advapi32.lib', 'libeng.lib', 'libmx.lib']

As you may see even adding the required libraries for compiling that last line didn't help and I still get "error LNK2019: unresolved external symbol engopen referenced in function"

For your second comment, yes exactly; I am trying to start the Matlab Engine and I successfully done that in VS but only after I applied those configurations in my original post. Can you be more specific about the libraries of Matlab without preprocessing? Can I test them?

0 Kudos
Steven_L_Intel1
Employee
1,800 Views

From what I can see in a Google search, the routine you are trying to call is named "engOpen", mixed-case. You can't get there with just /iface:cref.

I would suggest taking out /iface:cref. In the routine where you are calling engOpen, add this in the declarations:

!DEC$ ATTRIBUTES DECORATE,ALIAS:"engOpen" :: engopen

I also note that engOpen takes a null-terminated string and returns a pointer. How are you calling it?

 

0 Kudos
Atta_O_
Beginner
1,800 Views

Steve Lionel (Intel) wrote:

From what I can see in a Google search, the routine you are trying to call is named "engOpen", mixed-case. You can't get there with just /iface:cref.

I would suggest taking out /iface:cref. In the routine where you are calling engOpen, add this in the declarations:

!DEC$ ATTRIBUTES DECORATE,ALIAS:"engOpen" :: engopen

I also note that engOpen takes a null-terminated string and returns a pointer. How are you calling it?

 

Steve, unfortunately, I got error #7794: Only a function or subroutine subprogram may have the DEC$ ATTRIBUTES directive DECORATE specifier.   [ENGOPEN]

I call it as:

      ep = engOpen('matlab') 


 

0 Kudos
Steven_L_Intel1
Employee
1,800 Views

Ok - try it this way...

interface
  function engOpen (command) bind(C,name="engOpen")
  integer(INT_PTR_KIND()) :: engOpen
  character, dimension(*), intent(in) :: command
  end function engOpen
end interface

Make sure that "ep" is declared as integer(INT_PTR_KIND()) and that you remove any other declaration of engOpen.

Are there other Matlab routines you call?

0 Kudos
Atta_O_
Beginner
1,800 Views

Steve Lionel (Intel) wrote:

Ok - try it this way...

interface
  function engOpen (command) bind(C,name="engOpen")
  integer(INT_PTR_KIND()) :: engOpen
  character, dimension(*), intent(in) :: command
  end function engOpen
end interface

Make sure that "ep" is declared as integer(INT_PTR_KIND()) and that you remove any other declaration of engOpen.

Thank you Steve. That solved the problem. But I wonder why do I need interface block; can it be because I am calling C from Fortran the whole time without me noticing?

Steve Lionel (Intel) wrote:

Are there other Matlab routines you call?

Yes and actually a lot of them, and this made me think. Do I have to define all of the Matlab routines that I will use inside the interface block? 

Steve, why didn't I need to add this when I was using the VS?

0 Kudos
Steven_L_Intel1
Employee
1,800 Views

C is case-sensitive, Fortran is not. In order to call C routines with mixed-case names from Fortran, you have to do one of three things:

  • Declare the routine in an interface block with the standard BIND(C) attribute specifying the mixed-case name
  • Add a !DEC$ ATTRIBUTES ALIAS directive specifying the mixed-case name (DECORATE also needed)
  • Use /names:as_is (NOT! recommended)

I don't know what you did in VS, but my guess is that it was /names:as_is. By default in Intel Fortran for Windows, all names are converted to upper case. My rule on this is that if you use /names, you're doing it wrong. /iface:cref forces names to lowercase - just as bad,

Yes, you will need appropriate declarations of the other Matlab routines. Writing complete interface blocks is preferable, but more time-consuming as you have to look up each routine and figure out what the appropriate Fortran declaration is for each argument. (And also don't fall into the trap of using CHARACTER(*) in a BIND(C) interface unless you know that the called routine expects a "C descriptor" from Fortran. Otherwise, use CHARACTER, DIMENSION(*).)

If you want to take a shortcut, just add the ATTRIBUTES directive as I suggested earlier plus an EXTERNAL declaration for the routine. If it is a function, be sure to declare the proper return type.

0 Kudos
Atta_O_
Beginner
1,800 Views

Steve Lionel (Intel) wrote:

If you want to take a shortcut, just add the ATTRIBUTES directive as I suggested earlier plus an EXTERNAL declaration for the routine. If it is a function, be sure to declare the proper return type.

Thank you again Steve. May I ask what should I do then for statements (without output) like:

     call mxCopyReal8ToPtr(A, B, C)

(Explicit interface checking problem)

0 Kudos
Steven_L_Intel1
Employee
1,800 Views

Then it's a subroutine, not a function, and you don't have to declare a return type.

0 Kudos
IanH
Honored Contributor II
1,800 Views

Steve Lionel (Intel) wrote:

From what I can see in a Google search, the routine you are trying to call is named "engOpen", mixed-case. You can't get there with just /iface:cref.

I think for calls from Fortran the libraries also provides the symbol (or a wrapper) as ENGOPEN (and perhaps a separate(?) STDCALL variant too).

>dumpbin /exports libeng.lib
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file libeng.lib

File Type: LIBRARY

     Exports

       ordinal    name

                  _ENGCLOSE
                  _ENGCLOSE@4
                  _ENGEVALSTRING
                  _ENGEVALSTRING@12
                  _ENGGETVARIABLE
                  _ENGGETVARIABLE@12
                  _ENGOPEN
                  _ENGOPEN@8
                  _ENGOUTPUTBUFFER
                  _ENGOUTPUTBUFFER@12
                  _ENGPUTVARIABLE
                  _ENGPUTVARIABLE@16
                  _engClose
                  _engEvalString
                  _engGetVariable
                  _engGetVisible
                  _engOpen
                  _engOpenSingleUse
                  _engOutputBuffer
                  _engPutVariable
                  _engSetVisible

To the OP - the mathworks provided approach to interfacing with their routines requires the pre-processor (/fpp) (and for some types of interfaces, a need to compile things using a perl script).  If you don't enable the preprocessor then you need to set things up yourself.

I found the Mathworks provided interface irritating, so I put together some modules that provided Fortran 2003 BIND(C) interfaces into the C library components.  With these interfaces you still need to be mindful around things like terminating strings with NULL's etc, so I also put together a helper module that wraps those C interfaces and makes them more Fortran friendly (perhaps).  I did not cover the engine API - just the mat file and matrix routines.  It has been a while since I looked at this - things may be incomplete, there will be errors, I see that my enthusiasm for documentation declined exponentially with source file length, etc.  Anyway - the interfaces in MatlabMatFile.f90 and MatlabMatrix.f90 may be useful.

 

0 Kudos
JVanB
Valued Contributor II
1,640 Views

I don't have the 32-bit version of Matlab installed to check, but since those names are decorated for STDCALL, shouldn't you have

!DEC$ ATTRIBUTES STDCALL :: engOpen

and similar in other interface bodies?

 

0 Kudos
Reply