Ezf -- a tool that makes it easy to compile and launch a Fortran program

I made a little tool to make it easy to work with smaller Fortran projects. I started Fortran around two weeks ago, and currently I create lots of small projects to try out the features of the language. I didn’t want to create fpm projects for these tiny/small projects. Here is the GitHub link of the tool: GitHub - jabbalaci/ezf: Easily compile and run Fortran programs


ezf

Eazily compile and run Fortran programs.

ezf is a tool that makes it easy to compile and launch a Fortran program. The program to be compiled can use several modules. Modules can be in the same file, in the current directory and/or in the src/ subdirectory. The script tries to compile the source files (and the imported modules) in the correct order.

*.mod files are stored in a separate subdirectory: mod/.

Rationale

In Java, when your project consists of several files, it’s enough to compile just the main file (javac Main.java), and the compiler will find and compile all the necessary sources. D Lang. has a similar feature: when you compile the main file with the -i switch (dmd -i main.d), all
the necessary modules are compiled.

I wanted something similar for Fortran. I have a simple project, I use some modules, and I want to be able to compile the project easily. I only want to specify the main file, nothing else.

If you work on a larger project, you should use fpm, the Fortran Package Manager. However, for very simple projects, I find fpm to be an overkill.

Help

$ ezf --help
ezf - easily compile and run Fortran programs

Usage: ezf [options] main.f90 [-- arguments]
Options:
-h, --help          this help
-i, --info          show all info (don't compile; don't run)
-c                  compile
-r                  run
-cr                 compile and run (default if no options are given)
  • options are for the script
  • arguments are passed to the program to be compiled in the form of command-line arguments

Examples

$ cd demo1
$ ezf main.f90
# gfortran -Jmod -Imod src/jtypes.f90 src/jassert.f90 src/jstringbuffer.f90 src/jconstants.f90 src/jsys.f90 src/jstring.f90 main.f90 && ./a.out

It’s enough to provide the name of the main file. The default operation is compile & run. The script discovers the dependencies among the used modules, and compiles them in the correct order. At the end, the compiled executable is launched.

$ cd demo3
$ ezf main.f90 -- aa 2026 bb END
# gfortran -Jmod -Imod jsys.f90 main.f90 && ./a.out "aa" "2026" "bb" "END"
0: ./a.out
1: aa
2: 2026
3: bb
4: END

Arguments provided after “--” are passed to the program, not to the script.

Project discovery

The script can provide useful information about the modules of the project.

$ ezf -i main.f90
Dependencies:
=============
{'jconstants.f90': ['jtypes.f90'],
 'jstring.f90': ['jconstants.f90',
                 'jassert.f90',
                 'jsys.f90',
                 'jstringbuffer.f90'],
 'jstringbuffer.f90': ['jtypes.f90', 'jassert.f90'],
 'main.f90': ['jstringbuffer.f90', 'jstring.f90']}
---
Dependency graph visualization:
===============================
See `deps.png`
# dot -T png deps.dot -o deps.png

Dependencies are visualized with graphviz:

Compilation order:
==================
['jtypes.f90', 'jassert.f90', 'jstringbuffer.f90', 'jconstants.f90', 'jsys.f90', 'jstring.f90', 'main.f90']
with paths:
['src/jtypes.f90', 'src/jassert.f90', 'src/jstringbuffer.f90', 'src/jconstants.f90', 'src/jsys.f90', 'src/jstring.f90', 'main.f90']

Correct compilation order is determined.

Unused source files:
====================
Maybe you can delete them?
['src/unused.f90']

Unused source files are listed. Useful if you copy over a library that consists of several files but you use just a subset of it.

Compile and run:
================
# gfortran -Jmod -Imod src/jtypes.f90 src/jassert.f90 src/jstringbuffer.f90 src/jconstants.f90 src/jsys.f90 src/jstring.f90 main.f90
# ./a.out

Compile (and run) instructions are printed on the screen. They can be copied to a Makefile.

Demos

You can find some demo projects here (see the demo*/ folders). They use my jflib library, which is under development. These demos include an older version of this library. Check out the GitHub page of jflib for the newest version.

  • demo1 is the largest project, consisting of several modules
  • demo2 demonstrates that
    you can also use modules in the same file
  • demo3 demonstrates that you can pass command-line
    arguments to the program via the script

Usage tips

It was tested under Linux only with the gfortran compiler.

I suggest putting an alias on ezf.py, and then you can call it easily.

Add this line to the end of your ~/.bashrc file:

alias ezf="path/to/ezf.py"

ezf is written in a single file, and it uses just the standard library of Python.

Dependencies

  • It was tested with the gfortran compiler only.
  • For the graph visualization, install the graphviz package. (Under Arch-based distros: sudo pacman -S graphviz). This package is not obligatory though. If it’s missing, you’ll get just a warning.
4 Likes

It points out a feature lacking in fpm, which leads to wondering if it could be modified to be an fpm plugin that complemented fpm instead of solving the problem with an independent utility. If you had a version that gathered up the required files and did an “fpm new” in a scratch directory and populated it with copies of the file you could leverage fpm capabilities like preconfigured options for a plethora of compilers, an ability to install (perhaps the default being a location just used for test programs instead of the current fpm defaults), growing OpenMP and MPI integration, … ?
A plugin can be more complicated and use the fpm API but all it has to be is something executable called “fpm-$NAME”. Your app could stay as-is but include an option to output the list of identified files and a little script that used that to populate the scratch fpm project. If it proved popular enough I think something like what you provide would ultimately lead to the fpm “new” subcommand having a functionality to populate the new project and perhaps use a fpm.toml file with predefined dependencies and options as a template. I have used my own utility (called “ccall”) which has functionality similar to ezf for a very long time, and miss that functionality a lot when using fpm even though doing something like “fpm new /tmp/trying; cp somefiles.f90” /tmp/tryit;cd tryit;fpm run" is not theoretically super-difficult.

5 Likes

@jabuci Thanks for sharing the tool. From my understanding this tool is made to run small fortran projects, Just a thought,can the tool be modified to make static and dynamic library. This feature can be helpful to make shared libraries which can be used independently with fortran or other languages.

1 Like

@apoorv01 Yes, it’s made to compile and run small projects where the project uses some modules. The tool figures out the compilation order, we just need to specify the main file. The tool calls the compiler (currently: gfortran) in an external process. If you know how to make static and dynamic libraries with your compiler (i.e., you know how to do it in the terminal), then you can add a new option to the tool.

1 Like

Makefile support was added (see here).
Update: Windows support was also added.

It’s so incredibly easy to use FPM even for smaller projects. The more features you add to this new tool you are just going to end up reinventing FPM. Why not help us improve FPM (which is very capable, but still a young project with lots of room for improvement)?

4 Likes

I’m not against FPM. On the contrary, it’s an awesome tool. I’ve already tried FPM, and I’d use it for a bigger project or for making a library. But I needed a simple tool quickly and I could put it together in 2-3 days. First I had a basic version, then I redesigned it and added some more features. Since I’m a beginner in Fortran, I couldn’t have added these features to FPM at the moment. But, in the future, when I get to know Fortran better, I’d be happy to contribute to FPM. Or, one can also take ideas from this project (if there is any good idea in it at all) and add it to FPM. I made a tool for myself and decided to share it. I have this bad habit that I like building my own tools.

How is it different from FPM (as I see it)?

  • As I noticed, fpm requires you to put your main program in the app/ folder. My tool doesn’t require it. For a simple program, I prefer to leave the main program in the project’s root folder.
  • I wanted to know which source files are unused. My tool can list those files.
2 Likes

Hi @jabuci , nice tool you have here.
I just wanted to add some precisions regarding your two points. Concerning the first, you can always be more explicit and change the default behavior (see the doc):

[library]
source-dir="src"

[[ executable ]]
name="math_constants"
source-dir="app"
main="main.f90"

And for your second point, `fpm` prints the compiled files to the standard output. So a diff between that output and your file system is straightforward. Alternatively, you can dump the build tree (`fpm build --dump tree.json`) and use it in a third party tool.

So, I kind of agree with @jacobwilliams on this, and that thread echoes the post by @ivanpribec (see here). Let’s join the efforts and improve the Fortran ecosystem. Just food for thought, but a plugin for Makefile support would be nice for instance.

5 Likes

@jabuci good idea. This was the first thing we did with LFortran many years ago:

$ lfortran examples/expr2.f90
25

and I miss it when other compilers don’t automatically execute the binary. Once you have more files, currently fpm is the best bet. Often times you end up with some extra options, maybe some special linking, or dependencies, etc.

If you want to have your own tool — why not follow the fpm conventions? Or help us improve the conventions. So you take any fpm project, and use ezf on it and it will just work.

2 Likes