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

Preprocessor conditional compilation

ereisch
New Contributor II
2,188 Views

Hello all, I have a general question regarding Fortran syntax (not this forum?).  I have a series of include files that set up memory structures, and those include files may also chain-include other files.....in this case, some "parameter definition" files.  For example:

INCLUDE 'MEMORY_PARMS.TEXT'

STRUCTURE    /SOME_ARRAY/
    INTEGER*4    ID
    REAL*4    SOMEVARX(COUNT)
    REAL*4    SOMEVARY(COUNT)
END STRUCTURE

...and 'MEMORY_PARMS.TEXT' contains the following:

!DIR$ IF .NOT. DEFINED(_MEMORY_PARMS_TEXT_)
!DIR$ DEFINE _MEMORY_PARMS_TEXT_

  INTEGER*4  COUNT
  PARAMETER (COUNT = 1000)
!DIR$ ENDIF

This is just a small example -- we are trying to use a single "parameters" file to tune the scalability of our program, rather than having to go through dozens of source files to change hundreds of array sizes, etc.  This works great for single-routine files, but the problem is when someone codes a file that has more than one subroutine definition inside.....the first routine that includes the common block chain-includes the MEMORY_PARMS.TEXT file, defines the COUNT variable, and works.  The second routine, however, includes the same common block, but the preprocessor dutifully doesn't redefine the COUNT variable (since _MEMORY_PARMS_TEXT_ was defined by the first pass through while compiling the first routine), and the compilation fails.  The goal of the preprocessor directives was to avoid variable redefinition errors if multiple INCLUDEd files brought in the same params file in the same routine, however we didn't consider the case of how to "reset" this behavior in the case of a subsequent subroutine in the same compilation unit.  I was hoping there would be a preprocessor macro called something like __MODULE__ or __ROUTINE__ which some fancy fpp DEFINE logic can compare-test and then set if it's different, but alas, there appears to be no such macro.

Anyone have any thoughts?

Thanks.

0 Kudos
7 Replies
Steven_L_Intel1
Employee
2,188 Views

Perhaps I'm missing something, but I'd think that using modules and definitions in the modules would be a preferable approach. I'll note that you're using a compiler-specific preprocessor syntax rather than the more common cpp-style, but that's just an observation and not relevant to your problem.

If you're writing new code, I'd very strongly recommend making use of the language features designed for information sharing. (And perhaps module variables rather than COMMON blocks, though I'll comment that both make it difficult to parallelize your application.)

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,188 Views

Consider using the FPP preprocessor (and preprocessor directives). These are the C style preprocessing directives.

Your attempt to use the Compiler Directive !DIR$ as if it were equivalent to the C preprocessor is giving you problems. Using the FPP (C-like) will provide the same functionality.

Jim Dempsey

0 Kudos
ereisch
New Contributor II
2,188 Views

When I change the PARAMETER entries to:

#define COUNT 1000

...and compile with "ifort -fpp myfile.for", I receive a "warning #5117: Bad # preprocessor line", and a number of errors I interpret to mean the preprocessor definitions are not being honored.

0 Kudos
Steven_L_Intel1
Employee
2,188 Views

Can you show a sample source, the command line and output? The error you describe is what I would expect to see if fpp was not enabled.

0 Kudos
ereisch
New Contributor II
2,188 Views

Sure.  Rename "defines.f" to "defines.text", which the uploader won't allow.

I used "ifort -fpp test.for".  Output:

$ ifort -fpp test.for 
./defines.text(1): warning #5117: Bad # preprocessor line
#ifndef __defines_inc__
-^
./defines.text(2): warning #5117: Bad # preprocessor line
#define __defines_inc__
-^
./defines.text(4): warning #5117: Bad # preprocessor line
#define COUNT 1000
-^
./defines.text(6): warning #5117: Bad # preprocessor line
#endif
-^
test.for(10): error #6219: A specification expression object must be a dummy argument, a COMMON block object, or an object accessible through host or use association   [COUNT]
        REAL*4          TEST2(COUNT)
------------------------------^
test.for(10): error #6591: An automatic object is invalid in a main program.   [TEST2]
        REAL*4          TEST2(COUNT)
------------------------^
test.for(11): error #6591: An automatic object is invalid in a main program.   [TEST3]
        INTEGER*4       TEST3(COUNT), I
------------------------^
compilation aborted for test.for (code 1)

 

0 Kudos
JVanB
Valued Contributor II
2,188 Views

I have taken the risk of replying without looking at your attached files. The cpp # syntax does not mix well with Fortran code. It firstly requires you to throw out all instances of INCLUDE and replace them with #include because the # compiler directives are applied before the Fortran processor makes a pass through the file, so by the time a chunk of code is inserted with INCLUDE, the C preprocessor isn't available to figure out the # directives in the INCLUDEd chunk any more.

Instead of changing everything to C, it seems to me to make much more sense to use modules to set values globally. That way everything is in transportable Fortran and you don't have to keep second-guessing the C preprocessor to get your code right.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,188 Views

You can still use the Fortran INCLUDE  *** as long as they do not contain any FPP directives nor contain FPP declared macros.

You are correct in that the easiest way is to use the FPP "#include ..." in these circumstances.

For the OP's tuning requirement I agree with Steve's recommendation of placing these into a module file, then insert USE ... in the appropriate places.

Jim Dempsey

0 Kudos
Reply