====================================
Makefiles
====================================


We use `makefiles` to organize code compilation and execution. This page provides a
brief tutorial to create and work with `makefiles` for small
to medium-sized `Fortran 90/95`__ projects on `Unix/Linux OS`__. I
will introduce you to makefiles through simple fortran examples. With
some modifications, you can use makefiles for other programming
languages, such as C/C++, provided their compilers can be run with a
shell command. It is to be noted that "make" is not limited to manage
the execution of programs. It can be used to do other tasks/projects
involving multiple files, where some files must be updated
automatically whenever we modify other files. As an example, I use "make
html" to generate these course webpages.


Let us start off with the following three Fortran source files,
consisting of one main file and two subroutines:


.. csv-table::

    ".. literalinclude:: ../hpsc2020/Labs/lab2/main.f90
        :language: fortran
        :linenos:",".. literalinclude:: ../hpsc2020/Labs/lab2/sub1.f90
        :language: fortran
        :linenos:",".. literalinclude:: ../hpsc2020/Labs/lab2/sub2.f90
        :language: fortran
        :linenos:"



.. |vspace| raw:: latex

   \vspace{5mm}

|vspace|


The goal is to create a `makefile` that

 * compiles, links, and executes these three source codes;

 * makes necessary updates to some or all files if some other files are modified;

 * and pehaps does some other useful things, such as graphing.
   
In a Fortran program, the executable file is updated from object files, which are in turn made by compiling source files. Once we create a `makefile`, each time we change/modify some
source files, we can use the following shell command to execute the
`makefile` and perform all necessary recompilations and updates:

.. code-block:: none
		
 $ make -f Makefile-name

		
where `Makefile-name` stands for the name of the `makefile` file that
we want to use.
The `make` program uses the latest version of file modifications to
decide which of the files in the `makefile` need to be updated. For
example, if a subroutine file has changed, each Fortran source file
that calls this subroutine file must be recompiled as well. 


In what follows we consider and study several `makefiles` that get successively
more sophisticated to compile, link, and execute these three Fortran codes.

**Note:** You can find the three source files (`main.f90`, `sub1.f90`, `sub2.f90`) and the follwoing `makefiles` in
the course repository in "Labs/lab2" directory.




Makefile1
------------------

In the first version we write out explicitly what to do for each file:


.. literalinclude:: ../hpsc2020/Labs/lab2/Makefile1
   :language: make
   :linenos:

Notes:

 * A makefile consists of a few "rules" with the following structure:

   .. code-block:: none
		   
            TARGET : PREREQUISITE1 PREREQUISITE2 ... 
                  COMMAND1
                  COMMAND2
                  ...
	    
   A "target" is usually the name of a file that is generated by a
   program; examples of targets are executable or object files (as in
   this makefile). A target can also be the name of an action to carry out, such
   as "clean" or "graph" (see bellow).
   
   A "prerequisite" is a file that is used as input to create the target. A target often depends on several files.

   A "command" is an action that `make` carries out. A rule may have
   more than one command, each on its own line. Note that you need to
   put a tab character at the beginning of every command line. So, make
   sure you use a ``tab`` for indent, not a space.
 
 * Here, `output.txt` dependes on `code.x`, which in turn depends on
   three `.o` files, which in turn depend on three `.f90` source
   files. Dependencies are checked by date-stamp. For instance if the
   `.f90` is newer than the `.o` file, `make` recreates the `.o` file.
   
     




Makefile2
------------------

In the second version we use a single rule for creating all `.o` files from all `.f90` files:

.. literalinclude:: ../hpsc2020/Labs/lab2/Makefile2
   :language: make
   :linenos:


Makefile3
------------------

The three source files are compiled in the same way. In the previous
version we had to write out the list of `.o` files twice. This may
increase the chance of introducing errors. We can avoid this using "macros":

.. literalinclude:: ../hpsc2020/Labs/lab2/Makefile3
   :language: make
   :linenos:

      
FC and OBJECTS are macros (or makefile variables). They are used by
$(FC) and $(OBJECTS) in the rules.  


Makefile4
------------------      

In the fourth version we add a Fortran compile flag (``O3`` for level
3 optimization). We also add a phony target `clean` that removes the files created when compiling
the code (`.o` and `.exe` files) in order to facilitate cleanup.

.. literalinclude:: ../hpsc2020/Labs/lab2/Makefile4
   :language: make
   :linenos:

Notes:

 * A phony target is one that is not really the name of a file; rather
   it is just a name for a command to be executed. Here, the target
   `clean` is phony because it does not create a file named `clean`.
   
 * We execute this makefile using the following shell commands:

   .. code-block:: none
		   
		$ make -f Makefile4
		$ make -f Makefile4 clean
 

Makefile5
------------------     

We can add more tasks (as phony targets) to the makefile:

.. literalinclude:: ../hpsc2020/Labs/lab2/Makefile5
   :language: make
   :linenos:

We execute this using the follwoing shell commands:

.. code-block:: none
		
 $ make -f Makefile5
 $ make -f Makefile5 graph clean
 

|

**Further reading**:

For further information see: https://www.gnu.org/software/make/manual/make.html

__ http://math.unm.edu/~motamed/Teaching/Fall20/HPSC/fortran.html
__ http://math.unm.edu/~motamed/Teaching/Fall20/HPSC/unix.html