190 likes | 218 Views
Makefiles. Multiple Source Files (1). Obviously, large programs are not going to be contained within single files. C provides several techniques to ensure that these multiple files are managed properly. These are not enforced rules but every good C programmer know how to do this.
E N D
Multiple Source Files (1) • Obviously, large programs are not going to be contained within single files. • C provides several techniques to ensure that these multiple files are managed properly. • These are not enforced rules but every good C programmer know how to do this. • A large program is divided into several modules, perhaps using abstract data types. • The header (.h) file contains function prototypes of a module. • The (.c) file contains the function definitions of a module. • Each module is compiled separately and they are linked to generate the executable file.
Multiple Source Files (2) • C programs are generally broken up into two types of files. .c files: • contain source code (function definitions) and global variable declarations • these are compiled once and never included .h files: • these are the “interface” files which “describe” the .c files • type and struct declarations • const and #define constant declarations • #includes of other header files that must be included • prototypes for functions
Example - Main Program sample.c #include <stdio.h> #include "my_stat.h" int main() { int a, b, c; puts("Input three numbers:"); scanf("%d %d %d", &a, &b, &c); printf("The average of %d %d %d is %f.\n", x,y,z,average(a,b,c)); return 0; }
/* my_stat.h */ #define PI 3.1415926 float average(int x, int y, int z); float sum( int x, int y, int z); /* my_stat.c */ #include "my_stat.h" float average(int x, int y, int z) { return sum(x,y,z)/3; } float sum(int x, int y, int z) { return x+y+z; } Example - Module my_stat
Example - Compile the Sample Program • You need my_stat.c and my_stat.h to compile the my_stat module to object code cc –c my_stat.c • You need my_stat.h and sample.c to compile sample.c to object code cc –c sample.c • You need my_stat.o and sample.o to generate an executable file cc –o sample sample.o my_stat.o • Therefore, the module my_stat can be reused just with the my_stat.o and my_stat.h. In fact, this is how the standard libraries work. (Libraries are just collections of object code, with headers describing functions and types used in the libraries.)
The make Utility (1) • Programs consisting of many modules are very tedious to compile manually. • This can be addressed by using the make utility. all: sample sample: sample.o my_stat.o cc –o sample sample.o my_stat.o sample.o: sample.c my_stat.h cc –c sample.c my_stat.o: my_stat.c my_stat.h cc –c my_stat.c clean: rm sample *.o core Target Dependencies These indentation are from a tab (not spaces!!!) Commands
The make Utility • A make rule is of the form… targets : dependencies commands • Atarget is a filename, where the rules tell us how to create that file sample: sample.omy_stat.o cc –o sample sample.omy_stat.o • The target is the executable file sample, which requires that sample.o and my_stat.o already exist • The command is executed to carry out the action • which in this case is to create the executable program sample
The make Utility • A target can also be a so-called phony target • A phony target is a rule for creating a file that is never actually created • A phony target is a set of commands that are executed when we ask for that file to be created, e.g. clean: rm *.o sample • In this case the target clean has no dependencies • So it doesn’t require that any other files exist before the command is executed • The command will always be executed, provided that there is no file in the current directory called clean • If there is a file in the current directory called clean, the make system will be satisfied that the file already exists, so no action is needed • But the command does not create a file called clean, instead it deletes some files in the current directory
The make Utility • A make rule is of the form… target : dependencies commands • The dependencies tell us what files we need to create the target • If these dependencies files already exist and are up to date, then the make system will run the command(s) associated with the rule • But if the dependencies… • Do not exist, or • Are not up to date • … the make system will follow the rules for creating the dependencies files
The make Utility • A target file is considered to be out of date if… • It doesn’t exist at all or • The target file is older than any of its prerequisite files • The age of files is determined by the time they were created or last modified (their timestamp) • You can see the timestamp of files in the current directory using ls -l • The make utility is great for large programs with many files • If you modify a source file, only the files that depend on the source file are recompiled • The make utility looks after this by checking the timestamps on all the files listed in each dependency
The make Utility • A make rule is of the form… targets : dependencies commands • A command is a normal Unix command like you would type at the command line • The command is normally expected to be instructions for building the target file • Typically invoking the compiler • But you can invoke other tools, such as parser generators • But as we have seen in the case of dummy targets • The command does not have to create the target file • The command can do anything the programmer writes
The make Utility • Save the file with name "Makefile" (or "makefile") at the same directory. • For every time you want to make your program, type make • The make utility will • Find the Makefile • Check rules and dependencies to see if an update is necessary. • Re-generate the necessary files that need updating. • For example: • If only sample.c is newer than sample, then only the following commands will be executed: • cc –c sample.c • cc –o sample sample.o my_stat.o
The make Utility (1) • Programs consisting of many modules are very tedious to compile manually. • This can be addressed by using the make utility. all: sample sample: sample.o my_stat.o cc –o sample sample.o my_stat.o sample.o: sample.c my_stat.h cc –c sample.c my_stat.o: my_stat.c my_stat.h cc –c my_stat.c clean: rm sample *.o core Target Dependencies These indentation are from a tab (not spaces!!!) Commands
The make Utility (3) • To clean all generated files: make clean • To re-compile, you can • Remove all generated files and make again. • make clean; make • Or you can: • touch my_stat.h and thenmakeagain • This changes the time stamp of my_stat.h, so make thinks it necessary to make all the files.
Example Three C source files and one header file: compute.c includes no header files, calls no functions in other files init.c includes “myprogram.h” calls functions in io.c io.c includes “myprogram.h” calls functions in compute.c How do we build a makefile that compiles and links these files in the correct order?
Example # the first target is the default target all: myprogram # define the components of the program, the dependencies between them # and the actions necessary to build each component myprogram: io.o init.o compute.o gcc – o myprogram io.o init.o compute.o # define the dependencies and how to build each of the three source files compute.o: compute.c gcc –Wall –c –o compute.o compute.c init.o: init.c myprogram.h gcc –Wall –c –o init.o init.c io.o: io.c myprogram.h gcc –Wall –c –o io.o io.c
# remove some repetition by defining things once at the start CC=gcc CFLAGS=-Wall COMPILE=$(CC) $(CFLAGS) -c # all is the default target all: myprogram # define the components of the program, the dependencies between them # and the actions necessary to build each component myprogram: io.o init.o compute.o gcc – o myprogram io.o init.o compute.o # define the dependencies and how to build each of the three source files compute.o: compute.c $(COMPILE) –o compute.o compute.c init.o: init.c myprogram.h $(COMPILE) –o init.o init.c io.o: io.c myprogram.h $(COMPILE) –o io.o io.c
# remove some repetition by defining things once at the start CC=gcc CFLAGS=-Wall COMPILE=$(CC) $(CFLAGS) -c # all is the default target all: myprogram # define the components of the program, the dependencies between them # and the actions necessary to build each component myprogram: io.o init.o compute.o gcc –o myprogram io.o init.o compute.o # remove even more repetition from the file: # define dependencies on header files init.o io.o: myprogram.h # compile all .c source files to .o object files %.o: %.c $(COMPILE) –o $@ $< # note $@ denotes the target; $< denotes the source