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 main.cc which depends on List.h and List.cc and we wish to compile main.cc to get a main.out
build: clean compile
clean:
rm -rf main.out
compile: main.cc List.h List.cc
g++ main.cc List.h List.cc -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
CFLAGS=-g
CC=g++
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.
#include<stdio.h>
class Example
{
public:
int f1;
int f2;
int f3;
};
The foo.cc looks like this
#include "foo.h"
void func(Example &x);
main()
{
Example obj;
obj.f3 = 7;
printf("f3 :%d\n",obj.f3);
func(obj);
printf("f3: %d\n",obj.f3);
}
The bar.cc looks like this
#include"foo.h"
void func(Example *e)
{
e.f3 = 10;
}
Your makefile to build this is pretty simple, as shown.
prog: foo.o bar.o
g++ -o prog foo.o bar.o
foo.o: foo.cc foo.h
g++ -g -c foo.c
bar.o: bar.cc foo.h
g++ -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 bar.cc, it does so in the "third" field whereas f3 is the second field in f2.