NAG Fortran Compiler Frequently Asked Questions
  1. How can I use CDABS, DCMPLX, DCONJG, DIMAG and DREAL? [Answer.]
  2. Are non-standard specific intrinsic functions such as CDEXP available? [Answer]
  3. Is there a DTIME or ETIME function? [Answer]
  4. Is there a FLUSH procedure? [Answer]
  5. Is there a GETENV procedure? [Answer]
  6. Is there a SYSTEM procedure? [Answer]
  7. Can I use ‘$’ in a format to suppress newline? [Answer]
  8. How can I compile a very old (Fortran 66/77) program without getting errors? [Answer]
  9. What does the warning “TAB format input” mean? [Answer]
  10. Why does the message “Byte count on numeric data type” appear? [Answer]
  11. Why do I get the message “KIND value does not specify a valid representation method” with the NAG compiler? [Answer]
  12. What does “Buffer overflow on output” mean? [Answer]
  13. Why do I get the message “Variable X size of N bytes is too big”? [Answer]
  14. How can I control the maximum size of a named constant (PARAMETER)? [Answer]
  15. When doing mixed-language programming, what are the functions f90_init and f90_io_finish? [Answer]
  16. On program termination, the warning “Floating underflow occurred”; how can I find out where this is happening? [Answer]
  17. On program termination, the warning “Floating underflow occurred”; how can I stop this warning from appearing? [Answer]
  18. How can I read unformatted files written on a system with a different file format (e.g. endianness)? [Answer]
  19. How can I write unformatted files so they can be read on a system with a different file format (e.g. endianness)? [Answer]
  20. Is it possible to redistribute applications built with the NAG Fortran Compiler? [Answer]
  21. How should RANDOM_SEED be used to initialise the random number generator? [Answer]
  22. When will Fortran NNNN feature XYZ be available?" [Answer]
  23. Do you have any performance tips? [Answer]
  24. Can I use the NAG Compiler to build OpenMPI from source (on Linux)? [Answer]
  25. How do I link libraries with the NAG Compiler within CMake? [Answer]
  26. How can I compile the versions of BLAS and LAPACK from netlib using nagfor? [Answer]

Question How can I use CDABS, DCMPLX, DCONJG, DIMAG and DREAL?
Answer These are not standard Fortran intrinsic functions, though they are a common extension. We recommend that they be converted to standard Fortran using the following table.
Specific Equivalent Modern Fortran Generic Intrinsic Function
CDABS(A) Abs(a)
DCMPLX(X,Y) Cmplx(x,y,Kind=Kind(0d0))
DCONJG(Z) Conjg(z)
DIMAG(Z) Aimag(z)
DREAL(Z) Real(z)

Release 6.1 of the NAG Fortran Compiler can perform these conversions for you using the integrated precision unifier tool (nagfor =unifyprecision -dcfuns your_file.f90 from the command line); the -dcfuns option is used to make the compiler recognise these functions.


Question Are non-standard specific intrinsic functions such as CDEXP available?
Answer

No. These functions have never been part of any Fortran standard, and there is not universal agreement on their spelling.

However, they are never needed: just use the standard generic intrinsic functions: ABS, ACOS, ASIN, ATAN, ATAN2, CONJG, COS, COSH, DIM, EXP, LOG, LOG10, MAX, MIN, SIGN, SIN, SINH, SQRT, TAN and TANH can all be applied to any precision Real (and where appropriate, Complex) data.

If you have a program that uses a specific intrinsic (non-standard or standard) that consists of a prefix in front of one of the functions listed above, removing the prefix (usually C, CD, CQ, D, Q or Z) is nearly always the right thing to do; for example, references to an intrinsic CEXP, DEXP, CDEXP, CQEXP, DCEXP, QEXP, ZEXP can all safely be replaced by EXP.

For a few functions, the rule is slightly different: xINT and xNINT, where x is one of the prefixes listed above, should be changed to AINT or ANINT respectively.

Release 6.1 of the NAG Fortran Compiler can carry out some conversions of intrinsic functions from specific to generic form for you, using the integrated precision unifier tool (nagfor =unifyprecision your_file.f90 from the command line).


Question Is there a DTIME or ETIME function?
Answer No.

These functions are not standard Fortran; their functionality is provided by the standard Fortran intrinsic subroutines CPU_TIME and SYSTEM_CLOCK. If you have a package that wants to use the DTIME and/or ETIME procedures, you can add one or two of the following examples to your code. The first example provides DTIME and ETIME> written entirely in standard Fortran 95 (and thus will work on any Fortran 95 compiler); the second provides DTIME and ETIME using the NAG Fortran Compiler interface to Posix.

NOTE: By design, the DTIME and ETIME functions are not and cannot be thread-safe. If your code might be executed in a multi-threaded environment, you should use SYSTEM_CLOCK to measure elapsed time.

 

! DTIME in standard Fortran.
Real Function dtime(time)
  Real time(2)
  Double Precision,Save :: last_time = 0
  Double Precision this_time
  Intrinsic Cpu_Time
  Call Cpu_Time(this_time)
  time(1) = this_time - last_time
  time(2) = 0
  dtime = time(1)
  last_time = this_time
End Function
! DTIME via NAG Fortran Compiler Posix module.
Real Function dtime(time)
  Use F90_Unix_Env,Only:tms,times
  Real time(2)
  Type(tms),Save :: lastbuf
  Logical :: start = .True.
  Type(tms) buffer
  Integer junk
  junk = times(buffer)
  If (start) Then
    lastbuf%utime = 0
    lastbuf%stime = 0
    start = .false.
  End If
  time(1) = buffer%utime - lastbuf%utime
  time(2) = buffer%stime - lastbuf%stime
  dtime = time(1) + time(2)
  lastbuf = buffer
End Function
! ETIME in standard Fortran.
Real Function etime(time)
  Real time(2)
  Call Cpu_Time(etime)
  time(1) = etime
  time(2) = 0
End Function
! ETIME via NAG Fortran Compiler Posix module.
Real Function etime(time)
  Use F90_Unix_Env,Only:tms,times
  Real time(2)
  Type(tms) buffer
  Integer junk
  junk = times(buffer)
  time(1) = buffer%utime
  time(2) = buffer%stime
  etime = buffer%utime + buffer%stime
End Function

Question Is there a FLUSH procedure?
Answer

Yes. Fortran 2003 standardized this facility as the FLUSH statement.

Here is a simple example showing how to use it.

Program slow_dots
!
! This program prints 10 dots, one per second, then finishes.
!
  Use Iso_Fortran_Env,Only:output_unit
  Implicit None
  Integer i
  Do i = 1,10
    Write(*,'(a)',Advance='No') '.'
    Call delay
    Flush(output_unit)
  End Do
  Print *,'Done.'
Contains
  Subroutine delay
    Integer per_second,start,now
    Intrinsic System_Clock
    Call System_Clock(Count=start,Count_Rate=per_second)
    If (start==-huge(start)) Stop 'No clock.'
    Do
      Call System_Clock(Count=now)
      If (now<start .Or. now>=start+per_second) Exit
    End Do
  End Subroutine
End Program

 


Question Is there a GETENV procedure?
Answer Yes. Fortran 2003 standardized this facility as the GET_ENVIRONMENT_VARIABLE intrinsic procedure.

Here is a simple example showing how to use it.

Program environment_example
!
! This program displays the values of the environment variables FRED and
USERNAME
! (if they exist).
!
  Implicit None
  Call show('FRED')
  Call show('USERNAME')
Contains
  Subroutine show(name)
    Character(*),Intent(In) :: name
    Character(:),Allocatable :: value
    Integer len,status
    Intrinsic Get_Environment_Variable
    Call Get_Environment_Variable(name,Status=status,Length=len)
    If (status==1) Then
      Print *,'Environment variable "',name,'" does not exist.'
    Else If (status/=0) Then
      Print *,'Unexpected error',status,'for environment variable "',name,'"'
    Else
      Allocate(Character(len) :: value)
      Call Get_Environment_Variable(name,Value=value)
      Print *,'The value of environment variable "',name,'" is "',value,'".'
    End If
  End Subroutine
End Program

 


Question Is there a “SYSTEM” procedure?
Answer

Yes. Fortran 2008 standardized this facility as the EXECUTE_COMMAND_LINE intrinsic procedure.

Here is a simple example showing how to use it.

Program execute_cmd_example
  Call execute_command_line('echo Hello World!')
End Program

Question Can I use ‘$’ in a format to suppress newline?
Answer

No, the NAG Fortran Compiler does not accept this extension.

This extension is completely obsolete with the introduction, by Fortran 90, of non-advancing input/output. Here is an example of how to produce a prompt with standard Fortran.

    Program prompting
      Character(80) name
      Write (*,90000,Advance='No')
90000 Format('What is your name? ')
      Read *, name
      Print *, 'Hello ', Trim(name)
    End Program

Question How can I compile a very old (Fortran 66/77) program without getting errors?
Answer

The NAG Fortran Compiler carries out a strict check for conformance to the Fortran standard and also carries out a large number of checks for obviously incorrect code. While this is the correct behaviour for a compiler when new code is being developed, it is sometimes necessary to reduce the stringency of error checking to allow older code written to lower standards to compile. There are a number of compiler options to compile such legacy code.

-dusty
Downgrades a number of common errors found in legacy code to warnings. Hence compilation can continue; these warnings can be suppressed by the ‘-w’ option. This option implies the ‘-mismatch_all’ option.
-mismatch
Downgrades errors resulting from mismatch in argument lists to warnings. Calls to routines in the same file must still be correct.
-mismatch_all
As ‘-mismatch’, but even incorrect calls to routines in the same file are accepted.

 


Question What does the warning “TAB format input” mean?
Answer TAB format is an extension to Fortran 77, and operates when TAB characters are found in fixed form source files. Because it is an extension, a warning message is produced. This format is a bit complicated, and not recommended for new programs (use free form source instead).

Question Why does the message “Byte count on numeric data type” appear?
Answer

This is an extension to Fortran 77 that was made obsolete by Fortran 90. Instead of specifying the number of bytes, Fortran 90 has kinds of each datatype, and intrinsic functions for choosing a kind based on the desired properties (SELECTED_INT_KIND and SELECTED_REAL_KIND). The NAG Fortran Compiler also provides a module, F90_KIND, which has named constants for convenient kind selection (the names for Integer and Real/Complex are also available from the standard intrinsic module ISO_FORTRAN_ENV). The equivalence between byte sizes and kinds using these names is as follows.

Type * Byte Size Type(Kind Name)
INTEGER*1 Integer(int8)
INTEGER*2 Integer(int16)
INTEGER*4 Integer(int32)
INTEGER*8 Integer(int64)
REAL*4 Real(real32)
REAL*8 Real(real64)
REAL*16 Real(real128)
COMPLEX*8 Complex(real32)
COMPLEX*16 Complex(real64)
COMPLEX*32 Complex(real128)

The kind of an integer or real constant is specified by appending an underscore and the kind value (or name); e.g. 120_int8 is an 8-bit integer constant, and 3.14159265358979323846264338327950288_real128 is a 128-bit real value.


Question Why do I get the message “KIND value does not specify a valid representation method” with the NAG compiler?
Answer

The interpretation of kind values depends on the compiler. There are at least two obvious methods: sequential (1 to N, where N is the number of kinds) and byte (use the number of bytes for Integer and Real type). The NAG Fortran Compiler (and some other compilers) by default uses sequential kind numbering, so single and double precision real are REAL(1) and REAL(2), not REAL(4) and REAL(8). The disadvantage of the so-called “byte” scheme is that for the Complex type, the setting is the number of bytes for each part, i.e. half the total, which can be confusing.

The compiler option ‘-kind=sequential’ (the default), ‘-kind=byte’ or '-kind=unique' selects the method.


Question What does “Buffer overflow on output” mean?
Answer

This means that your program attempted a sequential write, in a single record, with more bytes than will fit into the file buffer for that unit. For formatted input/output, please refer to the Compiler Manual for the current implementation limit; for unformatted input/output, the default is unlimited.

To change the buffer size you can use the RECL= specifier in the OPEN statement for the file you wish to write. For example:

Open(13,File="myfile",Form="Formatted",Recl=2048)
will establish a buffer size of 2048 bytes on unit 13.

 

Note that Fortran provides the IOLENGTH= specifier in the INQUIRE statement to discover the needed value for RECL= for an unformatted file. For example:

Inquire(Iolength=n) big_array
Open(13,File="dump",Form="Unformatted",Recl=N)
will establish a sufficiently large buffer for unit 13 to allow the entirety of big_array to be read or written in one input/output statement.

 

An unlimited buffer size can be established for formatted input/output by using the Fortran 2003 feature “stream access”; however, this will disable the BACKSPACE statement on that unit. For example,

Open(13,File="list",Form="Formatted",Access="Stream")
will open unit 13 for stream access, enabling formatting input/output of records of unlimited length, but disabling the ability to backspace the unit.

 


Question Why do I get the message “Variable X size of N bytes is too big”?
Answer

This means that your variable is larger than the maximum object size supported by the NAG Fortran Compiler's current mode.

Please refer to the Compiler's Manual for a list of its current implementation limits.


Question How can I control the maximum size of a named constant (PARAMETER)?
Answer

The maximum size of a named constant is controlled with the -max_parameter_size= option. This takes a limit in megabytes (MB); the default is -max_parameter_size=50.


Question When doing mixed-language programming, what are the functions f90_init and f90_io_finish?
Answer

These functions are needed when the main program is in C instead of Fortran. The f90_init function initialises the Fortran environment, including the floating-point status, command-line arguments, and input/output subsystem. The f90_io_finish function writes the contents of all the Fortran output buffers to their files, and closes all the Fortran files. The following example shows how to use these functions.

int main(int argc,char *argv[])
{
  f90_init(argc,argv);
  /* At this point Fortran routines can be safely called. */
  f90_io_finish();
  return 0;
}

Question On program termination, the warning “Floating underflow occurred”; how can I find out where this is happening?
Answer

Floating underflow is quite common in programs, and is rarely a problem. If it is a problem, you can set the IEEE halting mode for underflow to cause the program to stop when it happens; note that you should also set the “Traceback for runtime errors (-gline)” option so that the location will be reported.

The following program shows how to use IEEE halting mode to cause termination on underflow.

Program underflow_halt
  Use Ieee_Exceptions
  Implicit None
  Call Ieee_Set_Halting_Mode(Ieee_Underflow, .True.)
  Call make_underflow(0.5)
Contains
  Subroutine make_underflow(x)
    Real, Intent(In) :: x
    Real :: y
    Integer :: n
    y = x
    n = 1
    Do
      y = y**2
      If (y==0) Exit
      n = n + 1
      Print *, 'Step', n, 'value', y
    End Do
    Print *, 'Zero reached at step', n
  End Subroutine
End Program

Question On program termination, the warning “Floating underflow occurred”; how can I stop this warning from appearing?
Answer

The Floating underflow warning can be suppressed in two ways:

  • the underflow flag can be set to false before program termination;
  • the link-time option -no_underflow_warning can be used.

     

    The following program shows how to use IEEE halting mode to turn the underflow flag off prior to program termination.

    Program turn_underflow_flag_off
      Use Ieee_Exceptions
      Implicit None
      Call make_underflow(0.5)
      Call Ieee_Set_Flag(Ieee_Underflow, .False.)
    Contains
      Subroutine make_underflow(x)
        Real, Intent(In) :: x
        Real :: y
        Integer :: n
        y = x
        n = 1
        Do
          y = y**2
          If (y==0) Exit
          n = n + 1
          Print *, 'Step', n, 'value', y
        End Do
        Print *, 'Zero reached at step', n
      End Subroutine
    End Program

Question How can I read unformatted files written on a system with a different file format (e.g. endianness)?
How can I write unformatted files so they can be read on a system with a different file format (e.g. endianness)?
Answer

Unformatted file conversion is provided by three mechanisms:

  • the -convert= option;
  • the CONVERT= specifier on the OPEN statement;
  • the FORT_CONVERTn environment variable.

     

    Unformatted file conversion affects both reading and writing, so the same mechanism provides the answer for both questions.

    The most common conversion requirement is for big-endian files with all floating-point data in IEEE format; this is provided by the “-convert=big_ieee” option.

    For full details of the conversion mechanisms please refer to the Compiler Manual.


Question Is it possible to redistribute applications built with the NAG Fortran Compiler?
Answer

Yes, it is possible. The easiest way to do this is to link the NAG Fortran Compiler run time library statically using the -unsharedrts option.

If you link the NAG Fortran Compiler run time library dynamically, the recipient of the executable must have their own copy of the Compiler's runtime. In general, the installation directories will differ, so the recipient must arrange for the received executable to be able to discover the new location of the Compiler's runtime.

On Linux, this is usually achieved by adding the appropriate directory to the LD_LIBRARY_PATH environment variable.

On macOS, this can be achieved by adding the appropriate directory to the DYLD_LIBRARY_PATH environment variable. On later versions of macOS, a more reliable method is to use install_name_tool(1) on a copy of the received executable. Use otool(1) to discover the location held within the executable. Then use install_name_tool -change to update the executable with the location of the library on the recipient's machine.


$ otool -l a.out |grep -e libf.*rts
          name /opt/NAG_Fortran/lib/libf62rts.dylib (offset 24)

$ install_name_tool -change /opt/NAG_Fortran/lib/libf62rts.dylib 
/shared/NP62/NAG_Fortran/lib/libf62rts.dylib a.out

$ otool -l a.out |grep -e libf.*rts
          name /shared/NP62/NAG_Fortran/lib/libf62rts.dylib (offset 24)

Question How should RANDOM_SEED be used to initialise the random number generator?
Answer
  • RANDOM_SEED is not necessary to initialise the random number generator, provided you are happy to get a different sequence with each execution. When you use RANDOM_NUMBER the generator will be initialised automatically.

    Here is an example:

    Program unique_sequences
      Implicit None
      Print *,'First sequence'
      Call show_random(8)
      Print *,'Second (different) sequence'
      Call show_random(8)
    Contains
      Subroutine show_random(n)
        Integer,Intent(In) :: n
        Real x(n)
        Call Random_Number(x)
        Print 1,x
    1   Format(99F8.5)
      End Subroutine
    End Program
    
  • RANDOM_NUMBER is the Mersenne Twister; this generator has a large amount of state (630 32-bit integers) and incorrect initialisation can result in poor quality numbers being generated. Therefore, it is recommended that RANDOM_SEED only be used to replay a previous sequence.

    Here is an example:

    Program sequence_restarting
      Implicit None
      Integer rsize
      Integer,Allocatable :: rseed(:)
      Call Random_Seed(Size=rsize) ! Get the size of the seed (630 for NAG).
      Allocate(rseed(rsize))       ! Allocate an array to save it.
      Call Random_Seed(Get=rseed)  ! Save it.
      Print *,'First sequence'
      Call show_random(8)
      Call Random_Seed(Put=rseed)  ! Restart the sequence at the saved state.
      Print *,'Second (restarted) sequence'
      Call show_random(8)
    Contains
      Subroutine show_random(n)
        Integer,Intent(In) :: n
        Real x(n)
        Call Random_Number(x)
        Print 1,x
    1   Format(99F8.5)
      End Subroutine
    End Program
    
  • In the case of wanting the same sequence with every execution, you can use RANDOM_SEED with your own seed data. The Mersenne Twister state is a random bit sequence and it should therefore have approximately equal numbers of zero and one bits. If you do not have 630 32-bit integers worth of random data, you should set the remaining elements of the seed array to zero so that the generator will know that these do not contain any useful entropy.

    Here is an example:

    Program repeatable_sequences
      Implicit None
      Integer rsize
      Integer,Allocatable :: rseed(:)
      Call Random_Seed(Size=rsize) ! Get the seed size.
      Allocate(rseed(rsize))       ! Allocate the seed.
      rseed(1) = Int(z'1f2d3b5a')  ! Assign the "random" values we have.
      rseed(2:) = 0                ! Set the rest to zero.
      Call Random_Seed(Put=rseed)  ! Initialise the generator.
      Print *,'First sequence (always the same)'
      Call show_random(8)
      Call Random_Seed(Put=rseed)  ! Re-initialise the generator.
      Print *,'Second sequence (also always the same)'
      Call show_random(8)
    Contains
      Subroutine show_random(n)
        Integer,Intent(In) :: n
        Real x(n)
        Call Random_Number(x)
        Print 1,x
    1   Format(99F8.5)
      End Subroutine
    End Program
    

Question When will Fortran NNNN feature XYZ be available?
Answer

We are implementing features from all revisions of the Fortran standard as soon as possible, concentrating on the ones most frequently requested. If you are interested in feature XYZ please send an expression of your interest to support@nag.co.uk and it will be passed on to the compiler developers.


Question Do you have any performance tips?
Answer Always try to use -O3 or -O4 (instead of just -O). This will lengthen compile time (sometimes substantially with -O4), but runtime performance is usually improved.

 

If you use assumed-shape arrays and you know that the actual arguments are always contiguous (i.e. you do not pass array slices using section notation), use -Oassumed=always_contig. With this option, a runtime error occurs if a non-contiguous actual argument is detected (so it is also useful for discovering whether you use such array sections).

If you are not 100% sure, but you think that this is true all or almost all of the time, use -Oassumed. With this option, non-contiguous actual arguments will be accepted though access to them will be slow.


Question Can I use the NAG Compiler to build OpenMPI from source (on Linux)?
Answer Yes, with OpenMPI 3.0.0 but some manual intervention is required for earlier versions.
 
The following script has been used to successfully build OpenMPI 2.1.0 on Fedora 25:
#!/bin/sh -eu

MAKEOPTS="-j"

FC=nagfor
export FC

# Some MPI procedures are called in the Fortran interface with
# mismatching data types. Let the compiler allow these:
FCFLAGS="-mismatch"
export FCFLAGS

# Hook in a temporary nagfor wrapper to convert unrecognized '-pthread'
# option, supplied by libtool when linking libraries, into
# '-Wl,-pthread'
current_nagfor=$(which nagfor)
tmp_wrap_dir=$(mktemp -d)
echo "#!/bin/sh -eu" > "${tmp_wrap_dir}"/nagfor
echo '"'"${current_nagfor}"'"' \
 '$(echo $* | sed -e "s% -pthread% -Wl,-pthread%g")' >> "${tmp_wrap_dir}"/nagfor
chmod u+x "${tmp_wrap_dir}"/nagfor

# (Specify your own installation prefix here if desired;
#  see the OpenMPI README)
install_prefix="${HOME}"/.local
(
  PATH="${tmp_wrap_dir}":$PATH
  export PATH
  ./configure --prefix="${install_prefix}"

  make ${MAKEOPTS} all
)

# Run the tests without the temporary nagfor wrapper on the PATH:
make ${MAKEOPTS} check

(
  PATH="${tmp_wrap_dir}":$PATH
  export PATH
  make ${MAKEOPTS} install
)

rm "${tmp_wrap_dir}"/nagfor
rmdir "${tmp_wrap_dir}"

# Supplying arguments to ld via nagfor requires double -Wl indirection;
# postprocess the installed OpenMPI Fortran wrappers to correct this,
# and to apply the -pthread transformation from above:
echo "Postprocessing Fortran wrappers..."
tmp_wrappers_list=$(mktemp)
find "${install_prefix}"/share/openmpi \
  -name '*fort*wrapper*.txt' > "${tmp_wrappers_list}"
while read -r wrapper
do
  orig_file="$(dirname "${wrapper}")/$(basename "${wrapper}").orig"
  if test ! -f "${orig_file}"
  then
    cp "${wrapper}" "${orig_file}"
  fi
  sed -e "s%\(-Wl,\)%\1\1,%" -e "s%\-pthread%-Wl,-pthread%g" < "${orig_file}" > "${wrapper}"
done < "${tmp_wrappers_list}"
rm "${tmp_wrappers_list}"

# Run a quick final test:
echo "Running Fortran sanity check..."
tmp_fortran_file=$(mktemp --suffix .f90)
cat <<EOF> "${tmp_fortran_file}"
Program foo
  Print '(A)', 'Hello MPI World!'
End Program
EOF
tmp_exe=$(mktemp --suffix .exe)
"${install_prefix}"/bin/mpif90 "${tmp_fortran_file}" -o "${tmp_exe}"
if test "$(${tmp_exe})" != "Hello MPI World!"
then
  echo "FAILed Fortran execution"
  exit_stat=1
else
  echo "Fortran executed OK:"
  ${tmp_exe}
  exit_stat=0
fi
rm "${tmp_fortran_file}" "${tmp_exe}"

exit ${exit_stat}

Question How do I link libraries with the NAG Compiler within CMake?
Answer The NAG Fortran Compiler uses the host system's C compiler (e.g. gcc) as its linker. Consequently, the nagfor switch -Wl,-option causes the -option switch to be passed to the host's C compiler.
 
Software systems such as CMake assume when linking that the driving compiler is communicating directly with the system linker (e.g. ld), and they use the switch -Wl,-option for passing the option -option to this linker. Therefore, to communicate -option from a nagfor link line to the system's linker one must escape the switch twice: -Wl,-Wl,,-option.
 
As a more complicated example, to use the start/end grouping option in GNU ld supply nagfor with the switch
-Wl,-Wl,,--start-group,foo1,foo2,-Wl,,--end-group You can verify at any time that the ultimate linker is receiving the switch(es) you are expecting it to receive by running the respective nagfor line with the -dryrun switch added.
 
Within CMake the -Wl, indirection can be integrated with the target_link_libraries function as follows:
#Use cmake's find library function to assign library paths to variables
find_library(naglib NAMES libnag_mkl.a PATHS ${nagdir}/lib)
find_library(mkllp64 NAMES libmkl_intel_lp64.a PATHS ${mkllib})
find_library(mklgnu NAMES libmkl_gnu_thread.a PATHS ${mkllib})
find_library(mklcore NAMES libmkl_core.a PATHS ${mkllib})

#link libraries. Note quotations are just used for line continuation
target_link_libraries(foo ${linker_flags} "-Wl,-Wl,,--start-group,\
${mkllp64},${mklgnu},${mklcore},-Wl,,--end-group"  ${naglib})

Question How can I compile the versions of BLAS and LAPACK from netlib using nagfor?
Answer

It's not difficult to compile LAPACK using the NAG compiler. Here's how to do it on a Linux machine, using LAPACK 3.9.0 as an example.

First, obtain the lapack distribution from netlib

http://www.netlib.org/

Note that the distribution also contains a reference implementation of the BLAS.

Unpack the lapack distribution tar file in a convenient place:

   mkdir lapack_build
   cd lapack_build
   tar zxvf lapack-3.9.0.tar.gz
   cd lapack-3.9.0
	 

As explained in instructions in the README.md file that you find in the lapack-3.9.0 directory, copy the example make include file and edit to use the compiler of your choice, in our case nagfor.

   cp make.inc.example make.inc

In make.inc, change these four lines:

   FC = gfortran
   FFLAGS = -O2 -frecursive
   FFLAGS_DRV = $(FFLAGS)
   FFLAGS_NOOPT = -O0 -frecursive

to

   FC = nagfor
   FFLAGS = -O2 -ieee=full -dcfuns
   FFLAGS_DRV = $(FFLAGS)
   FFLAGS_NOOPT = -O0 -ieee=full -dcfuns

Also in make.inc, find the line

   #TIMER = INT_CPU_TIME

and remove the comment:

   TIMER = INT_CPU_TIME

(There is a comment just above this line saying that it is suitable for use by the NAG compiler).

These are the only changes you should need to make to the file make.inc. What do the compiler flags mean?

(i) -dcfuns
This switch tells nagfor to allow use of non-standard double precision complex functions. Such functions have never been part of any version of the Fortran standard, but were commonly used in old Fortran 77 code because of their usefulness. By default nagfor does not accept them in order to encourage you to use modern Fortran equivalents, but this switch lets you avoid having to modify old code.

(ii) -ieee=full
IEEE standard arithmetic allows software to raise exceptions such as overflow, division by zero and other illegal operations without interrupting or halting the flow of the program. This is often a useful thing to do, and LAPACK code assumes it to be the case. However, more often than not, such conditions occur due to accidental programming mistakes. The NAG compiler takes the defensive view that it is better to stop when encountering such exceptions, so that the programmer knows they occurred; otherwise a program can continue, producing end results that are meaningless but may look sensible. Contributors to LAPACK know what they are doing, and intentionally want some code to be allowed to raise exceptions without halting. The codes are capable of detecting that an exception was raised, and will take remedial action at run time. The -ieee=full switch tells nagfor that you know what you are doing, and there is no need to stop.

(At LAPACK 3.9.0 and some earlier versions) there is a small bug in one of the test data files, lapack-3.9.0/TESTING/dbal.in which contains an extraneous semicolon right at the end. Edit dbal.in to remove the semicolon, which causes a read error when one of the test programs tries to read the file.

After you've changed these two files, building BLAS and LAPACK is simply a matter of typing "make". Use the -j switch to make to build faster if you have a multi-core machine:

   make -j

This will create BLAS and LAPACK libraries, and run various test programs. If you have a fast machine it should only take a few minutes, and you should see results something like these:

                         -->   LAPACK TESTING SUMMARY  <--
                 Processing LAPACK Testing output found in the TESTING directory
SUMMARY                 nb test run     numerical error         other error
================        ===========     =================       ================
REAL                    1308195         0       (0.000%)        0       (0.000%)
DOUBLE PRECISION        1309007         0       (0.000%)        0       (0.000%)
COMPLEX                 768366          0       (0.000%)        0       (0.000%)
COMPLEX16               769178          0       (0.000%)        0       (0.000%)

--> ALL PRECISIONS      4154746         0       (0.000%)        0       (0.000%)