Fortran stop code and Linux tee

If I compile this program in my Linux Ubuntu system,

program teststop
  print "(A)",'Running now.'
  stop 'Stopping now.'
end program teststop

and run its object code ./a.out with this command:

./a.out | tee teststop.out

then, on compiling with ifort my terminal says

Running now.
Stopping now.

but on compiling with gfortran my terminal says

STOP Stopping now.
Running now.

With each compiler, teststop.out has only one line: ‘Running now.’ Three questions arise.

  1. Does this reveal a bug in either compiler?
  2. Does this reveal a bug in the operating system?
  3. If the answer to questions 1 and 2 is No, then how does one make the stop code appear in teststop.out?
1 Like
  • 1 - stdout, the standard output stream.
  • 2 - stderr, the standard error stream.

./a.out > teststop.out 2>&1

Redirect stderr to stdout

2 Likes

Alternatively, …

Since a message on the STOP directive typically goes to stderr, if you want the message to go to stdout I would generally avoid putting a message on the STOP and just write the message with a PRINT or WRITE followed by a STOP. For those who want the message to go to stderr another issue is that the messages might not appear in the order generated by the program, as you are writing to two separate files (stdout and stderr) that may be buffered or flushed independently. In general the FLUSH directive will ensure the lines appear in the terminal window in the order generated by the program, although there might be a compiler out there that does not have a PRINT write to the same logical unit that OUTPUT_UNIT points to; which is a reason to use a WRITE statement instead of a print. So you might want to do something like:

program main
use,intrinsic :: iso_fortran_env, only : &
   & stderr=>ERROR_UNIT, &
   & stdin=>INPUT_UNIT, &
   & stdout=>OUTPUT_UNIT
implicit none
  write(stdout,"(A)")'Running now.'
  write(stdout,"(A)")'Stopping now'
  flush(stdout) ! make sure output appears before any default STOP message
  stop 1
end program main

Although it can be more verbose, it is more portable to avoid using an asterisk for the LUN in the WRITE statement and messages on the STOP, and to use a WRITE instead of a PRINT. So if you really want the same behavior and full control I suggest using WRITE statements for messages. Note even then if you add an exit number to the STOP that some compilers will print different messages (nothing, “STOP 1” “STOP”, … and so on).

Newer versions of STOP and ERROR STOP allow for better control, adding a QUIET option and allowing for processor dependent options like providing a traceback or not, but most Fortran compilers do not fully implement the latest version of STOP so for the time being those features may not be portable to all the programming environments you might want to support

  R1162 stop-stmt                             is   STOP[stop-code ] [ , QUIET = scalar-logical-expr]
  R1163 error-stop-stmt                       is   ERROR STOP[stop-code ] [ , QUIET = scalar-logical-expr]
  R1164 stop-code                             is   scalar-default-char-expr
                                              or scalar-int-expr
  C1176 (R1164) The scalar-int-expr shall be of default kind.
  Execution of a STOP statement initiates normal termination of execution. Execution of an ERROR STOP
  statement initiates error termination of execution.
  When an image is terminated by a STOP or ERROR STOP statement, its stop code, if any, is made available
  in a processor-dependent manner. If the stop-code is an integer, it is recommended that the value be used as
  the process exit status, if the processor supports that concept. If the stop-code in a STOP statement is of type
  character or does not appear, or if an end-program-stmt is executed, it is recommended that the value zero be
  supplied as the process exit status, if the processor supports that concept. If the stop-code in an ERROR STOP
  statement is of type character or does not appear, it is recommended that a processor-dependent nonzero value
  be supplied as the process exit status, if the processor supports that concept.
  If QUIET= is omitted or the scalar-logical-expr has the value false:
      • if any exception (17) is signaling on that image, the processor shall issue a warning indicating which
         exceptions are signaling, and this warning shall be on the unit identified by the named constant ERROR_-
         UNIT from the intrinsic module ISO_FORTRAN_ENV (16.10.2.9);
      • if a stop code is specified, it is recommended that it be made available by formatted output to the same
         unit.
  If QUIET= appears and the scalar-logical-expr has the value true, no output of signaling exceptions or stop code
  shall be produced.
  NOTE1
   When normal termination occurs on more than one image, it is expected that a processor-dependent summary
   of any stop codes and signaling exceptions will be made available.
  NOTE2
  If the integer stop-code is used as the process exit status, the processor might be able to interpret only values
  within a limited range, or only a limited portion of the integer value (for example, only the least-significant 8
  bits).

 
3 Likes

I usually attach & after |, such that stderr is also redirected to the log file

./a.out |& tee teststop.out

which seems a shorthand for

./a.out 2>&1 | tee teststop.out

(according to the bash man page). RE why STOP Stopping now appears first when using tee + gfortran + no &, I have no idea, but if I try to guess… it might be partly because of the overhead of tee…? (if it receives the data to stdout via pipe and then prints it to terminal, while stderr is directly printed w/o buffering before pipe?) But it doesn’t explain the difference from ifort, so not sure… :melting_face:

Thank you @septc - changing | to |& solved my problems. It needed no change to teststop.f90, it made teststop.out contain both lines of output, and it put both compilers’ output to the screen in the same order without having to use flush(stdout). I used tee instead of redirecting because in a different project I wanted my dialogue with the terminal while running a program to be available again later. Checking what it would do led to my query.

1 Like