CS 372 Spring 2016 > Notes for February 22, 2016
CS 372 Spring 2016
Notes
for February 22, 2016
Build Tools
What They Are
A build tool, is a software package that organizes and oversees the building of a project. Every IDE includes a build tool of some kind. Build tools are also available as stand-alone programs. Another name for build tools is build automation software.
Build tools originated in the field of software development, and this remains their primary application. However, they are not restricted to this area. For example, I use a build tool in my writing, to create and view PDF files from LaTeX source.
The basic functionality of a build tool revolves around two areas.
- A build tool must be able to determine what portions of a project need to be built.
- A build tool must be able to determine how to build each file that needs to be built.
Make
Introduction
The granddaddy of all build tools is make, created in 1976 as a framework for automating software builds under the Unix operating system.
Make is still heavily used, but its limitations, along with criticisms of its syntax and other annoyances have led to a number of other build tools being written. Some of these are based on Make. The most popular of these is probably GNU make, available under a FLOSS license from the GNU Project. Many other build tools are not based on Make, but all of them were influenced by it.
We will look at how Make is used. Other build tools will differ in interface and syntax, but all generally offer the same basic functionality.
Makefiles & Basic Syntax
Makefiles—The
operation of Make is driven by script files called
makefiles.
By default, the filename of a makefile is
“Makefile
”.
Simply executing Make does a build using the default makefile. Other makefiles can be specified.
A makefile is written using a simple programming language, with a very restricted set of operations. The contents of a makefile consist of three things: rules, comments, and macro definitions.
Rules—A rule tells Make the information it needs to determine whether a file needs to be built, and if so, how to do it. Here is an example of a rule.
[Makefile]
main: main.cpp main.h g++ main.cpp -o main
In the above rule,
abc
is the target:
the file to be built.
The target is followed by a colon and a blank-separated
list of dependencies.
In the above rule,
the dependencies are abc.cpp
and abc.h
.
These are the files that the target is built from.
To determine whether a target needs to be built, Make first checks whether the target exists. If it does not, then it is built. If the target exists, then the modification times of the target and all of its dependencies are examined. If any dependency has a modification time more recent than the target, then the target is built; otherwise it is not.
To build the target, the code in the following lines is executed. Each of these lines must begin with a tab character—indicated by a gray box above. (The number one criticism of Make involves this requirement.)
So, for example, using the rule above,
if abc
does not exist,
or if either abc.cpp
or abc.h
has a more recent modification time,
then the following is executed.
[*ix Command Line]
g++ main.cpp -o main
What if a dependency does not exist? Then Make looks for a rule to build the dependency. If no appropriate rule is found, then Make fails with an error message. If a rule is found, then the dependency is built. The dependency will then generally have a very recent modification time, and so the original target will be built as well.
Here is an example of a rule whose dependencies have their own rules.
[Makefile]
all: prog prog.o: prog.cpp prog.h lib1.h lib2.h g++ prog.cpp -c lib1.o: lib1.cpp lib1.h g++ lib1.cpp -c lib2.o: lib2.cpp lib2.h g++ lib2.cpp -c prog: prog.o lib1.o lib2.o g++ prog.o lib1.o lib2.o -o prog
Above, all
is the default target:
the one that is built if no target is specified.
Target all
is an example of a
phantom target:
a target that does not correspond to a file.
Note that there are no commands associated with
target all
;
the rule simply says that,
if no target is specified,
then we make target prog
.
Another common example of a phantom target
is clean
.
Typically, making target clean
deletes temporary files
and possibly other files that have their own rules,
and thus can easily be rebuilt.
Comments—A
comment in a makefile
begins with a pound sign (“#
”)
and continues to the end of the line.
Make ignores comments in makefiles.
Macro Definitions—Make allows macros (think “variables”) to be defined and then later used in rules. Basic macro definitions are nearly self-explanatory.
[Makefile]
# Macro definitions for C++ compilation CPP = g++ CPPFLAGS = -ansi -pedantic -Wall -std=c++11
To use a macro, enclose its name in parentheses, and precede all of this with a dollar sign. This will be replaced with the value of the macro.
[Makefile]
# Our primary executable main: main.cpp main.h $(CPP) main.cpp -o main $(CPPFLAGS)
Other Makefile Syntax
Special Macros
Make includes a number of special macros that can be used to make rules more concise or more general. These include the following.
$@;
- The current target
$<
- The first dependency
$?
- A list of all dependencies whose modification times are more recent than the target.
So, for example,
we could rewrite our rule for main
as follows.
[Makefile]
# Our primary executable main: main.cpp main.h $(CPP) $< -o $@ $(CPPFLAGS)
Suffix Rules
A suffix rule tells how to build a file with a particular filename suffix from another file with the same basename, but a different filename suffix. Here is an example for C++.
[Makefile]
# From C++ source to object file .cpp.o: $(CPP) $< -o $@ $(CPPFLAGS)
If a makefile has the above rule, then we can use it to build any C++ object file that is based only on a single source file. Object files that are based on more than one file can have their own rules; these override the suffix rule.
Pattern Rules
Make can do simple pattern matching,
using the %
character.
Here is the above suffix rule rewritten
as a pattern rule.
[Makefile]
# From C++ source to object file %.o: %.cpp $(CPP) $< -o $@ $(CPPFLAGS)
Pattern rules are more general than suffix rules, since they allow for more than one dependency.
CMake
Another noteworthy build tool is CMake, which is aimed at system-independent/cross-platform development.
A CMake script is written in a relatively full-featured platform-independent programming language. CMake can generate scripts for a number of common build tools, including Make.
CMake is distributed under a FLOSS license.