How to create a simple Makefile in linux
We learn how to write a Makefile to automate the compilation of our source code. We will use one example from Fortran.
Why we need a Makefile?
-
If you have multiple source files in C, Fortran, C++ or any other compilable languages, we have to do them separately. That’s where makefile becomes important. By simply running the makefile, one can compile the whole source code with multiple scripts.
-
Imagine that we have a module that contains a subroutine. After compilation of the module, the compiled subroutine will be available to all subprograms that uses that module. Now, consider what will happen if we make a small change in the module. Even after we recompile this particular module, all other files that uses this module needs to be recompiled (this is not always the case though if the changes only reflects the internals of the subroutine). If your project is large, then recompiling all the scripts can be a tedious process. Note that this issue can be avoided if we properly partition the modules.
-
Some programs has circular dependencies, where there are multiple modules that call each other. In this case, compiling only one file will fail.
What is a Makefile?
Make is like a mini programming language whose purpose is to compile a sequence of files to make a single executable file and to help us in the process.
Create a basic Makefile:
Below is an example of a basic Makefile that runs a “hello …” shell script. There are two targets here - hello
, and fun
.
VAR=earthinversion
VAR2=utpal
hello:
@echo "hello ${VAR}"
fun: hello
@echo "hello ${VAR2}"
Here, in the part fun: hello
, fun
is the target and hello
is the dependency.
The first target is always the default. When we run make
, then the first target is executed.
The second target fun
has dependencies. When we run make fun
then it fun executes the target hello
and then it executes the target fun
.
$ make fun
hello earthinversion
hello utpal
We can also define VAR
and VAR2
while executing make
to override variable setting in the script.
$ make VAR2=ron fun
hello earthinversion
hello ron
Special variables
VAR=earthinversion
VAR2=utpal
awesome:
@echo "hello ${VAR}"
fun: hello
@echo ${VAR2} is $@ and $<
$ make fun
hello earthinversion
utpal is fun and hello
In the above example, we used two variables $@
and $<
. You might have already noticed. $@
is the target at the left of the colon and $<
is for the one at the right of the colon.
Example Fortran code (.f90
)
I borrow the example script from an excellent tutorial on Fortran by Daniel Price (see ref).
area.f90
! A module containing functions to compute the area of a circle
! Utpal Kumar
module geometry
implicit none
real, parameter :: pi = 4.*atan(1.)
public :: area, pi
private
contains
!
! A function to calculate the area of a circle
!
real function area(r)
real, intent(in) :: r
area = pi*r**2
end function area
end module geometry
maths.f90
program maths
use geometry, only:area,pi
implicit none
real :: r
r = 2.0
print*,'pi is ',pi
print*,'the area of the circle of radius ',r,' is ', area(r)
end program maths
The script maths.f90
uses the module area.f90
. So, we compile the two independently and then compile the one executable. The workflow would be:
gfortran -o area.o -c area.f90
gfortran -o maths.o -c maths.f90
gfortran -o maths area.o maths.o
Notice that I compiled the module, area.f90
before maths.f90
because of the inherent dependencies.
Use Makefile to compile codes
Now, we will use Makefile to organize our codes
FC=gfortran #fortran compiler
FFLAGS=-O3 -Wall -Wextra -std=f2008 #optimization (for level 3) flags, compiler warnings and the strictest adherence to the latest standards
SRC=area.f90 maths.f90
OBJ=${SRC:.f90=.o} #substitute .f90 with .o
%.o: %.f90 #wildcard rule, creation of *.o depends on *.f90
$(FC) $(FFLAGS) -o $@ -c $<
maths: $(OBJ)
$(FC) $(FFLAGS) -o $@ $(OBJ)
clean: #cleans all the old compilation files
@rm -f *.mod *.o maths
In this example, the first (or default) target is a ‘wildcard’ rule that tells the Make how to compile file ending in .o
from the corresponding .f90
. Just like above, the creation of *.o
file is dependent on *.f90
files.
$ make
gfortran -O3 -Wall -Wextra -std=f2008 -o area.o -c area.f90
gfortran -O3 -Wall -Wextra -std=f2008 -o maths.o -c maths.f90
gfortran -O3 -Wall -Wextra -std=f2008 -o maths area.o maths.o
If you don’t change anything in the script and try compiling the codes again, then Make can “smartly” figure that out.
$ make
make: `maths' is up to date.
You can use the above Makefile as your template for most of the applications.
References
Disclaimer of liability
The information provided by the Earth Inversion is made available for educational purposes only.
Whilst we endeavor to keep the information up-to-date and correct. Earth Inversion makes no representations or warranties of any kind, express or implied about the completeness, accuracy, reliability, suitability or availability with respect to the website or the information, products, services or related graphics content on the website for any purpose.
UNDER NO CIRCUMSTANCE SHALL WE HAVE ANY LIABILITY TO YOU FOR ANY LOSS OR DAMAGE OF ANY KIND INCURRED AS A RESULT OF THE USE OF THE SITE OR RELIANCE ON ANY INFORMATION PROVIDED ON THE SITE. ANY RELIANCE YOU PLACED ON SUCH MATERIAL IS THEREFORE STRICTLY AT YOUR OWN RISK.
Leave a comment