Makefies : Conditional execution using ifeq

Conditions can be added in makefiles using “if” conditions, to ensure the commands get executed only under certain conditions.

The syntax of if in a makefile is

ifeq(,) statements else statement endif

Let us say we have two files hello1.c and hello2.c which we want to compile using makefile. But the condition for compiling these files is that if the user who is compiling is root then hello_1.c should be compiled,else for any other user hello_2.c should be compiled. We can use the if condition in makefile to achieve this.

This can be done using the following makefile

CC = cc -o pf=hello user = $(shell whoami) ifeq ($(user),root) targets := $(pf)_2 else targets = $(pf)_1 endif $(targets):$(targets).c $(CC) $(targets) $(targets).c

user = $(shell whoami)

Above statement assigns the current user name to the variable “user” using the command “whoami”.

Then we use the “if” condition and check the user name and assign the target based on the result of the condition check.

If we execute the make command as root we will get the following output

$ make cc -o hello_2 hello_2.c

If we do the same as any other user other than root, we will get the following output

$ make cc -o hello_2 hello_2.c

Category: Linux | Comments Off on Makefies : Conditional execution using ifeq

Makefiles: Using variables

Prev: make is smart We can use variables in makefile to prevent typing the same strings over and over and also make the file more easy to understand.

Defining variables: Let us say we have a makefile to compile three independent executables hello_1, hello_2 and hello_3

all: hello_1 hello_2 hello_3 hello_1:hello_1.c cc -o hello_1 hello_1.c hello_2:hello_2.c cc -o hello_2 hello_2.c hello_3:hello_3.c cc -o hello_3 hello_3.c

In the above makefile we use the string “cc -o” repeatedly. Instead of typing the whole string every time we can create a variable for it.
We can create a variable of any name by using the “=” sign. The left hand would be the name of the variable and the right hand side would be the value of the variable.
Any where in the file if we want to use the value of the variable we just have to use the name of the variable in the format $() and make will automatically replace the variable with its value while executing.

CC = cc -o all: hello_1 hello_2 hello_3 hello_1:hello_1.c $(CC) hello_1 hello_1.c hello_2:hello_2.c $(CC) hello_2 hello_2.c hello_3:hello_3.c $(CC) hello_3 hello_3.c

In the above file have created a variable CC and used it whenever we needed cc -o.
Note that variables are case sensitive thus “cc” “CC” and “Cc” are all different.
We can also use variables for prefixes of various strings. Like in the example above “hello” is like a prefix to a number of strings, thus we can use a variable for it.

CC = cc -o pf=hello all: $(pf)_1 $(pf)_2 $(pf)_3 $(pf)_1:$(pf)_1.c $(CC) $(pf)_1 $(pf)_1.c $(pf)_2:hello_2.c $(CC) $(pf)_2 $(pf)_2.c $(pf)_3:hello_3.c $(CC) $(pf)_3 $(pf)_3.c

Recursive expanded variables : We can create recursive variables by using one variable while declaring another.

CC = cc -o pf=hello targets = $(pf)_1 $(pf)_2 $(pf)_3 all: $(targets) $(pf)_1:$(pf)_1.c $(CC) $(pf)_1 $(pf)_1.c $(pf)_2:hello_2.c $(CC) $(pf)_2 $(pf)_2.c $(pf)_3:hello_3.c $(CC) $(pf)_3 $(pf)_3.c

In the above example “targets” is a variable, which is a list of all the targets. The targets variable uses the variable “pf” , thus to find out what $(targets) refers to make will have to expand pf creating a recursion among variables any depth of such recursion is allowed.
The limitation of defining variables using “=” is that a variable can not refer to itself in recursion.

CC = cc -o pf=hello targets = $(pf)_1 $(pf)_2 targets = $(targets) $(pf)_3 all: $(targets) $(pf)_1:$(pf)_1.c $(CC) $(pf)_1 $(pf)_1.c $(pf)_2:hello_2.c $(CC) $(pf)_2 $(pf)_2.c $(pf)_3:hello_3.c $(CC) $(pf)_3 $(pf)_3.c

In the above example, the second definition of variable “targets” uses the “targets” itself in recursion. Such usage will result in an infinite loop, which make successfully detects and throws the error.

makefile:5: *** Recursive variable `targets’ references itself (eventually). Stop.

Simply expanded variables This can be prevented by making use of simply expanded variables which are defined using “:=”. The use of “:=” makes the expansion of all the variables in the assignment only once and stop, thus preventing the infinite loop.

Thus in the above example the second definition should be

CC = cc -o pf=hello targets = $(pf)_1 $(pf)_2 targets := $(targets) $(pf)_3 all: $(targets) $(pf)_1:$(pf)_1.c $(CC) $(pf)_1 $(pf)_1.c $(pf)_2:hello_2.c $(CC) $(pf)_2 $(pf)_2.c $(pf)_3:hello_3.c $(CC) $(pf)_3 $(pf)_3.c

Now make will not throw any error and will successfully compile the targets.

Using shell in declaration : We can also execute shell commands while defining variables.

CC = cc -o pf=hello targets = $(pf)_1 $(pf)_2 targets := $(targets) $(pf)_3 opd = $(shell pwd) all: $(targets) $(pf)_1:$(pf)_1.c $(CC) $(opd)/$(pf)_1 $(pf)_1.c $(pf)_2:hello_2.c $(CC) $(pf)_2 $(pf)_2.c $(pf)_3:hello_3.c $(CC) $(pf)_3 $(pf)_3.c

In the above example we executed the command “pwd” and assigned the result to the variable “opd” which we used while compiling to indicate the path where the compiled executable needs to be stored.

Category: Linux | Comments Off on Makefiles: Using variables

Makefiles:make is smart

Prev: Multiple independent targets

Till now to compile a c program we have passed the command to the makefile to compile a given c code. But make has built in intelligence and can work even without the command.

Let us say we have ta file

hello.c

#includemain() { printf(“Hello world”); }

To compile this file using make we just need to create the makefile with the contents

makefile

hello:

make looks at the targets and if no dependencies and commands are mentioned in the makefile,it automatically looks for a file with the name .c i.e. in the above example hello.c and compiles it to create the executable.

$ make cc hello.c -o hello

If we want to make sure that the correct files are being compiled before actually generating the executable we can just print the commands that make is going to run by passing the option “–just-print”.

$ make –just-print cc hello.c -o hello

In the above case the executable will not get generated, but it only prints the commands that will be executed.

We can also print the folders in which make is running the commands from using the option -w

$ make -w make: Entering directory `/home/user/temp’ cc hello.c -o hello make: Leaving directory `/home/user/temp’

Next: Makefiles: Using variables

Category: Linux | Comments Off on Makefiles:make is smart

Makefiles: Multiple independent targets

Prev: Multiple dependent targets

The make command when executed with out any arguments always tries to create the first target. But in one makefile we can specify as many independent targets as we want and then choose to create the specific targets .

Let us say we have two programs

hello_1.c

#includemain() { printf(“Hello world”); }

hello_2.c

#includemain() { printf(“Hello universe”); }

The above two are independent programs which can be compiled on the command line using

$ cc -o hello_1 hello_1.c $ cc -o hello_2 hello_2.c

The same can be done by creating a makefile with two targets “hello_1” and “hello_2”.

makefile:

hello_1: hello_1.c cc -o hello_1 hello_1.c hello_2: hello_2.c cc -o hello_2 hello_2.c

Now if we run the command make

$ make cc -o hello_1 hello_1.c

We can see that if use the command make with no arguments the first target i.e. hello_1 gets crated. Now if we want to create the second target we will have to pass the second target to the make command as an argument.

$ make hello_2 cc hello_2.c -o hello_2

Thus we can specify any specific target we want to create as the argument to the command make.

If we want to option of creating all the independent targets with out specifying every target separately we add a target to the makefile and mention all the targets as the dependencies.

makefile:

all: hello_1 hello_2 hello_1: hello_1.c cc -o hello_1 hello_1.c hello_2: hello_2.c cc -o hello_2 hello_2.c

Now we can create hello_1 and hello_2 by running make with all as the target.

$ make all cc -o hello_1 hello_1.c cc -o hello_2 hello_2.c

Thus we can use makefile with multiple targets and selectively create the required targets or create all of them together.

Next: Makefiles: make is smart

Category: Linux | Comments Off on Makefiles: Multiple independent targets

Makefiles: Introduction

Makefiles are the files used by the utility make. make helps in compiling a source code into an executable or automate execution of commands listed in the makefile.

Let us say we have a file “hello.c”

hello.c

#includemain() { printf(“Hello world”); }

The usual compilation of this in linux using gcc is

$ cc hello.c -o hello

We can use a makefile to do the same compilation
The syntax of writing a makefile is

Target:prerequisite command

A makefile is comprised of

Target : The executable which has to be generated. In the above case the target is the executable hello.

Prerequisite: The source files required to generated the target. In the above example the source is hello.c

Command: If the prerequisite is available which command will convert it into the target ? The command in the above example is “cc -o hello.c -o hello”. The command always has to be preceded by a single tab space

Create a file by the name “Makefile” and enter the contents

Makefile

hello:hello.c cc -o hello hello.c

Now open a terminal and cd to the folder where the makefile is stored.
Run the command

$ make cc -o hello hello.c

We can see that make has run the command and generated the executable just as we did from the command line.
You might get the following error if you have omitted the tab space before the command.

Makefile:2: *** missing separator. Stop.

If you name the makefile wrongly You might get the error

make: *** No targets specified and no makefile found. Stop.

The makefile can also be named with any other name we want but in that case we need to use the option “-f” with the command make. If we want to name the above makefile as my_makefile then we need to use the command make as make -f my_makefile

After the makefile has generated the executable if we run the command make again we will get the message

make: `hello’ is up to date.

This is a special property of the make utility. It will generated a new executable of the mentioned target only if the target does not exist or the source file has been modified after the target has been generated. Next : Makefiles: Dependent targets

Category: Linux | Comments Off on Makefiles: Introduction