Thursday, April 24, 2008

Making make files

So final class in the CSCI 1730 and Dave has covered make files for the undergraduate students. Alas, during my undergraduate studies we did not work much with Linux at school. Frankly, none of the lab instructors in my school were knowledgeable about Windows itself, leave aside make and stuff. They used to treat the school lab systems as their secret treasure and none of us were allowed to even check our mail. That sucks, I know, that really does. (I completed my Bachelor of Engineering in Information Technology, though I consider myself more of a computer science student than an IT personnel). Anyway, I will write down what I learnt more about make files.

Sample Makefile

Note that make files should have the name "Makefile". Invoking make reads this file for rules to be executed.

Calling just make, invokes the first rule and if you want any other rule to be executed you specify it "make ruleX".

batch: a b c

a: a1 a2

touch a

b: b1 b2

touch b



Here batch is the target for which a,b and c are dependencies. So the batch is only executed when the modification time of batch is different from that of a b or c. Again since a is dependent on a1 and a2, it has to be run only when a1 and a2 has different modification time. A rule with no dependencies always executes it with no considerations.

Make file to compile a C++ program

Suppose we have a which depends on List.h and and we wish to compile to get a main.out

build: clean compile


rm -rf main.out

compile: List.h

g++ List.h -o main.out

So do you always need to write a makefile? Well, the answer is no. For example, if you have a C++ program called "testmyprogram.cpp" and then you just type "make testmyprogram" then based on the extension .cpp it invokes the following command.

g++ testmyprogram.cpp -o testmyprogram

Well, this is kind of nice, especially when you do not want to make a file just for testing a program and best of all, when you are lazy like me. But it does not work for java programs, at least not on my terminal machine.

make -f AnotherMakefile

The above command takes in AnotherMakefile instead of Makefile.

Using "variables" in makefiles

Well, look at the following makefile

TARGETS=foo.o bar.o driver.o

driver: $(TARGETS)
       $(CC) $(TARGETS) -o driver

CFLAGS is an implicit flags variable which you do not need to mention when the rules are defined.

Where things can go wrong in Makefile

look the following code.

class Example
int f1;
int f2;
int f3;

The looks like this

#include "foo.h"

void func(Example &x);

Example obj;
= 7;
"f3 :%d\n",obj.f3);
"f3: %d\n",obj.f3);

The looks like this


void func(Example *e)
= 10;

Your makefile to build this is pretty simple, as shown.

prog: foo.o bar.o
++ -o prog foo.o bar.o

foo.o: foo.h
++ -g -c foo.c

bar.o: foo.h
++ -g -c bar.c

So running make and running the program output is pretty easy and you get to see the output as 7 and 10. Now when you remove the dependency on foo.h from the bar.o rule, comment out the field "int f2" from the foo.h. So when you run the make again, since foo.o depends on foo.h, it runs whereas the rule bar.o does not run and there for the bar.o still knows that Example has three fields(int f1,int f2 and int f3) whereas the foo.o believes Example has two fields only. So when you change f3 to 10 in, it does so in the "third" field whereas f3 is the second field in f2.


So it is always good to remember that weird things happen when your Makefile is not correct. (In the above case, you saw something like a pointer bug).


Working with makedepend


Running the command "makedepend", it generates a Makefile with list of all depenedencies. makedepend is useful but not optimal. It goes through each of the project file specified, identifies the #includes and then further checks these includes to find out further dependencies. It looks like great tool to generate the dependencies. GooD!


I guess that is it for now, I hope to write about Jboost in the next post, hopefully.

No comments: