Source file extension question

I prefer the .f extension over the other longer ones. Meanwhile, I also prefer to use the modern and free-form Fortran coding style.

What GFortran flags should I use if I would like to use the free form with the .f extension?

From: GFortranGettingStarted - GCC Wiki

“[…]Of course, you can override gfortran’s default, with options -ffree-form and -ffixed-form (many gfortran options are named -f’’=option-name '. For example, if you have a free-form code named bessel.f, you can compile it with[…]”

program fixed_form
print*, "fixed-form"
end program fixed_form

gfortran’s default
gfortran fixed_form.f -o fixed_form


    1 | program fixed_form
      | 1
Error: Non-numeric character in statement label at (1)

    2 | print*, "fixed-form"
      | 1
Error: Non-numeric character in statement label at (1)

    3 | end program fixed_form
      | 1
Error: Non-numeric character in statement label at (1)

override gfortran’s default
gfortran -ffree-form fixed_form.f -o fixed_form


If you are interested in using a compiler other than gfortran in the future, here is a list of the options in various Fortran compilers:

Compiler Fixed-form Free-form Invoke (C) preprocessor
gfortran -ffixed-form -ffree-form -cpp
ifort -fixed -free -fpp
ifort (Windows) /fixed /free /fpp
nvfortran -Mfixed -Mfree -Mpreprocess
nagfor -fixed -free -fpp
Cray -f fixed -f free -eP, -eZ
IBM -qfixed -qfree, -k -qpreprocess
g95 -ffixed-form -ffree-form -cpp
flang -Mfixed -Mfreeform -Mpreprocess
oracle f95 -fixed -free -fpp or -xpp=fpp (cpp)

Nice! I think that -cpp also works in most of these compilers?

LFortran currently treats any file as free form. You have to use the option --fixed-form to enable fixed form. Rationale: fixed form should not be used for new projects; for old projects one enables with a compiler option.

The same with the C preprocessor: currently no file is preprocessed by default, but you can enable it with the --cpp flag. Motivation: there are other preprocessors, e.g., fypp is gaining traction. We plan to support fypp and other preprocessors natively also. For that reason, the C preprocessor is ran separately (it is not integrated with the prescanner), and in the future we can run fypp instead or in addition to cpp. I found some projects using both cpp and fypp…; To enable fypp, I would imagine an option --fypp would be natural. It seems it makes sense to not preprocess by default, and let the user select when and which preprocessors to use.

Regarding flags: I thought the modern way is to use the -c --long-option style, where short option has one dash, and long option has two dashes. As the above table shows, compilers traditionally do not use this convention. However, Clang actually uses both -long-option and --long-option.

Let me know any feedback that you have.


Would it be possible to use .f (or other preferred extensions) regardless of the form, and make the compilers automatically identify what the form is according to the code rather than the extension? What is the technical difficulty in doing so?

.f90 is fine now, but imagine that we are in 2040 — we do hope Fortran to be still in active use 20 years later, right? At that time, .f90 will probably become another source of complaints because it sounds antique.

1 Like

The complaints began in 1991 :slight_smile:


We used to use a “generic” compiler command that coincidentally was called “f90” that used the value of an environment variable (COMPILER) and would build using different compilers and different flags (ie. COMPILER=ifort9.1_debug) that would look for comments in the source file that contained file-specific compiler flags by default. We typically only used four different compilers but often needed specific compiler versions for specific files. That is a much rarer case now than in the past, luckily.

In many ways fpm(1) now gives some of those same features back, except the requirements are/will be in an external configuration file instead of in the source files.

There have been discussions about creating a new generic compiler wrapper several times in Fortran forums, but fpm(1) is the closest there is to such a utility.

When free format was first introduced and when single-file compiles were required for many optimizations (inlining in particular) several vendors supplied their own directives for options like free-format. Especially when INCLUDE files were much more common the CRAY approach (still supported today) was appreciated; but it did not become a standard practice and so it made files non-portable:


The FREE and FIXED directives specify whether the source code in the program unit is written
 in free source form or fixed source form. The FREE and FIXED directives override the -f 
option, if specified, on the command line.These directives apply to the source file in which they
 appear, and they allow for switching source forms within a source file.Source form can be 
changed from within an INCLUDE file. After the INCLUDE file has been processed, the source 
form reverts back to the source form that was being used prior to processing of the INCLUDE 
1 Like

Yes, exactly. If you want to help, please go ahead and upvote this issue:

P.S. I know it might be hard to believe, but we are much closer to 2040 than we are to 1990, roughly 1.6x closer. So if .f90 was fine for 31 years, it will be fine for the next 19 years also. I don’t think it will look significantly more antique than it looks now. Anyway, my point is that it is time to move away from fixed form, and indeed using the .f extension is a great choice. So that should be the default.


If it makes the proposal more acceptable, the association of the .f file extension with free form could be tied to the choice of a compiler option or default such as Gfortran’s -std= .

Before actually doing the calculation, I did not realize it :joy: Mathematicians are generally not good are calculating numbers (precisely).

Totally agree.

I did not find a voting button for the proposal on GitHub, but I wrote a supporting comment. Hope that it helps a bit.

1 Like

Thanks @ivanpribec. It would be nice to have a comprehensive table showing equivalent compiler options. On Windows the options to compile in strict Fortran 2018 mode are -stand:f18 or /stand:f18 for Intel and -std=f2018 for gfortran. Another detail a table could list is the default name of an executable. On Windows it is a.exe for gfortran and g95, and for Intel it is foo.exe if the command is ifort foo.f90 bar.f90. Ideally a script would exist to translate compiler options and fpm could accept generic compiler options that are specialized to the compiler used.

You can press the “thumbs up” button at the issue.

Anyway, totally agree with you and thank you for bringing this up!

1 Like

Hi @kargl, thank you for the explanation! I understand it better now. There will be difficulties if the user provides a piece of code that is neither fixed nor free, in other words, incorrect code.

Probably not. Certainly not in ifort. Note that use of straight cpp will tend to break Fortran code - compilers that use cpp as a preprocessor supply an option to make it more “Fortran-friendly”.

Hmm… At least nvfortran, ifort and gfortran allow to use -cpp. Here’s one compiled with ifort:

program p
#ifdef _USE_CPP
$ ifort -cpp -D_USE_CPP print.f90 && ./a.out
$ ifort --version
ifort (IFORT) 2021.1 Beta 20201112
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.

According to the Intel Fortran compiler documentation on the -fpp option:

Alternate options:
Linux and macOS*: -cpp (this is a deprecated option) [emphasis added]

See fpp Preprocessing for a description of the differences with respect to the C preprocessors.

Click here for the list of ifort preprocessor options (cpp is not shown among them)
$ ifort -help preprocessor


          define macro
-nodefines, -noD
          specifies that any -D macros go to the preprocessor only, and not to
          the compiler
-U<name>  remove predefined macro
-allow nofpp-comments
          If a Fortran end-of-line comment is seen within a #define, treat it
          as part of the definition.  Default is allow:fpp-comments
-E        preprocess to stdout
-EP       preprocess to stdout, omitting #line directives
-P        preprocess to file, omitting #line directives
          same as -P
-[no]keep  keep/remove preprocessed file generated by preprocessor as input to
           compiler stage.  Not affected by -save-temps.  Default is -nokeep
-[no]fpp   run Fortran preprocessor on source files prior to compilation

           Name an alternate preprocessor executable.  The name can
           include the full path.
-module path
           specify path where mod files should be placed and first location to
           look for mod files
-I<dir>   add directory to include file search path
          add directory to the second include file search path (after -I)
          add directory to the start of the system include path
-X, -nostdinc
          remove standard directories from include file search path
          find libraries, headers and executables in <prefix>
          generate dependency information.
          If no filename is specified, output is to stdout.
           Similar to -MD or -MMD
          If a filename is specified, output is to filename.
           Similar to -MF filename
          do not generate dependency information (default)
          control what dependency information is output.
          [no]intr_mod   Intrinsic modules.  Default is nointr_mod.
          generate dependency information in the specified format.
          One of:  make, nmake
1 Like

In this post, “klausler” wrote:

I think that it’s necessary to have an integrated preprocessing facility in the same part of the compiler that’s handling INCLUDE statements, line continuation, case normalization, &c. It’s not hard to implement and it should be standardized.

If I understood his example correctly, by running the preprocessor integrated with the compiler allows for more accurate error messages.

I thought that too, but you don’t have to have it integrated and you still get accurate error messages. You simply maintain a mapping for each character of the generated code to the original code, and you do this for the preprocessor as well as the prescanner. So if preprocessor is enabled, you have to remap twice instead of once. That seems to be the only penalty.

1 Like