Free Hosting Online for WorkStations

< Previous | Contents | Next >

Building The Program

Most programs build with a simple, two-command sequence:



./configure make

./configure make


The configure program is a shell script which is supplied with the source tree. Its job is to analyze the build environment. Most source code is designed to be portable. That is, it is designed to build on more than one kind of Unix-like system. But in order to do that, the source code may need to undergo slight adjustments during the build to accommodate differences between systems. configure also checks to see that necessary external tools and components are installed. Let’s run configure. Since configure is not lo- cated where the shell normally expects programs to be located, we must explicitly tell the shell its location by prefixing the command with ./ to indicate that the program is lo- cated in the current working directory:



[me@linuxbox diction-1.11]$ ./configure

[me@linuxbox diction-1.11]$ ./configure


configure will output a lot of messages as it tests and configures the build. When it finishes, it will look something like this:



checking libintl.h presence... yes checking for libintl.h... yes

checking for library containing gettext... none required configure: creating ./config.status

config.status: creating Makefile config.status: creating diction.1 config.status: creating diction.texi config.status: creating diction.spec config.status: creating style.1 config.status: creating test/rundiction config.status: creating config.h [me@linuxbox diction-1.11]$

checking libintl.h presence... yes checking for libintl.h... yes

checking for library containing gettext... none required configure: creating ./config.status

config.status: creating Makefile config.status: creating diction.1 config.status: creating diction.texi config.status: creating diction.spec config.status: creating style.1 config.status: creating test/rundiction config.status: creating config.h [me@linuxbox diction-1.11]$


What’s important here is that there are no error messages. If there were, the configuration failed, and the program will not build until the errors are corrected.

We see configure created several new files in our source directory. The most impor- tant one is Makefile. Makefile is a configuration file that instructs the make pro- gram exactly how to build the program. Without it, make will refuse to run. Makefile is an ordinary text file, so we can view it:



[me@linuxbox diction-1.11]$ less Makefile

[me@linuxbox diction-1.11]$ less Makefile


The make program takes as input a makefile (which is normally named Makefile), that describes the relationships and dependencies among the components that comprise the finished program.

The first part of the makefile defines variables that are substituted in later sections of the makefile. For example we see the line:



CC= gcc

CC= gcc


which defines the C compiler to be gcc. Later in the makefile, we see one instance where it gets used:


diction:

diction.o sentence.o misc.o getopt.o getopt1.o

$(CC) -o $@ $(LDFLAGS) diction.o sentence.o misc.o \ getopt.o getopt1.o $(LIBS)

diction:


A substitution is performed here, and the value $(CC) is replaced by gcc at run time.

Most of the makefile consists of lines, which define a target, in this case the executable file diction, and the files on which it is dependent. The remaining lines describe the command(s) needed to create the target from its components. We see in this example that the executable file diction (one of the final end products) depends on the existence of diction.o, sentence.o, misc.o, getopt.o, and getopt1.o. Later on, in the makefile, we see definitions of each of these as targets:


diction.o:

getopt.o: getopt1.o: misc.o:

diction.c config.h getopt.h misc.h sentence.h

getopt.c getopt.h getopt_int.h getopt1.c getopt.h getopt_int.h misc.c config.h misc.h

diction.o:

getopt.o: getopt1.o: misc.o:


sentence.o:

style.o:

sentence.c config.h misc.h sentence.h

style.c config.h getopt.h misc.h sentence.h

sentence.o:

style.o:


However, we don’t see any command specified for them. This is handled by a general tar- get, earlier in the file, that describes the command used to compile any .c file into a .o file:



.c.o:

$(CC) -c $(CPPFLAGS) $(CFLAGS) $<

.c.o:

$(CC) -c $(CPPFLAGS) $(CFLAGS) $<


This all seems very complicated. Why not simply list all the steps to compile the parts and be done with it? The answer to this will become clear in a moment. In the meantime, let’s run make and build our programs:


[me@linuxbox diction-1.11]$ make

[me@linuxbox diction-1.11]$ make


The make program will run, using the contents of Makefile to guide its actions. It will produce a lot of messages.

When it finishes, we will see that all the targets are now present in our directory:



[me@linuxbox

diction-1.11]$ ls

config.guess

de.po

en

install-sh

sentence.c

config.h

diction

en_GB

Makefile

sentence.h

config.h.in

diction.1

en_GB.mo

Makefile.in

sentence.o

config.log

diction.1.in

en_GB.po

misc.c

style

config.status

diction.c

getopt1.c

misc.h

style.1

config.sub

diction.o

getopt1.o

misc.o

style.1.in

configure

diction.pot

getopt.c

NEWS

style.c

configure.in

diction.spec

getopt.h

nl

style.o

COPYING

diction.spec.in

getopt_int.h

nl.mo

test

de

diction.texi

getopt.o

nl.po

de.mo

diction.texi.in

INSTALL

README


Among the files, we see diction and style, the programs that we set out to build. Congratulations are in order! We just compiled our first programs from source code!

But just out of curiosity, let’s run make again:


[me@linuxbox diction-1.11]$ make

make: Nothing to be done for `all'.

[me@linuxbox diction-1.11]$ make

make: Nothing to be done for `all'.


It only produces this strange message. What’s going on? Why didn’t it build the program again? Ah, this is the magic of make. Rather than simply building everything again, make only builds what needs building. With all of the targets present, make determined that there was nothing to do. We can demonstrate this by deleting one of the targets and running make again to see what it does. Let’s get rid of one of the intermediate targets:



[me@linuxbox diction-1.11]$ rm getopt.o

[me@linuxbox diction-1.11]$ make

[me@linuxbox diction-1.11]$ rm getopt.o

[me@linuxbox diction-1.11]$ make


We see that make rebuilds it and re-links the diction and style programs, since they depend on the missing module. This behavior also points out another important feature of make: it keeps targets up to date. make insists that targets be newer than their dependen- cies. This makes perfect sense, as a programmer will often update a bit of source code and then use make to build a new version of the finished product. make ensures that ev- erything that needs building based on the updated code is built. If we use the touch pro- gram to “update” one of the source code files, we can see this happen:



[me@linuxbox diction-1.11]$ ls -l diction getopt.c

-rwxr-xr-x 1 me me 37164 2009-03-05 06:14 diction

-rw-r--r-- 1 me me 33125 2007-03-30 17:45 getopt.c [me@linuxbox diction-1.11]$ touch getopt.c

[me@linuxbox diction-1.11]$ ls -l diction getopt.c

-rwxr-xr-x 1 me me 37164 2009-03-05 06:14 diction

-rw-r--r-- 1 me me 33125 2009-03-05 06:23 getopt.c [me@linuxbox diction-1.11]$ make

[me@linuxbox diction-1.11]$ ls -l diction getopt.c

-rwxr-xr-x 1 me me 37164 2009-03-05 06:14 diction

-rw-r--r-- 1 me me 33125 2007-03-30 17:45 getopt.c [me@linuxbox diction-1.11]$ touch getopt.c

[me@linuxbox diction-1.11]$ ls -l diction getopt.c

-rwxr-xr-x 1 me me 37164 2009-03-05 06:14 diction

-rw-r--r-- 1 me me 33125 2009-03-05 06:23 getopt.c [me@linuxbox diction-1.11]$ make


After make runs, we see that it has restored the target to being newer than the depen- dency:



[me@linuxbox diction-1.11]$ ls -l diction getopt.c

-rwxr-xr-x 1 me me 37164 2009-03-05 06:24 diction

-rw-r--r-- 1 me me 33125 2009-03-05 06:23 getopt.c

[me@linuxbox diction-1.11]$ ls -l diction getopt.c

-rwxr-xr-x 1 me me 37164 2009-03-05 06:24 diction

-rw-r--r-- 1 me me 33125 2009-03-05 06:23 getopt.c


The ability of make to intelligently build only what needs building is a great benefit to programmers. While the time savings may not be very apparent with our small project, it


is very significant with larger projects. Remember, the Linux kernel (a program that un- dergoes continuous modification and improvement) contains several million lines of code.


Top OS Cloud Computing at OnWorks: