Makefile - VAST Lab
Download
Report
Transcript Makefile - VAST Lab
The Makefile utility
Motivation
Small programs
single file
“Not so small” programs :
– Many lines of code
– Multiple components
– More than one programmer
Mozilla
Mozilla Directory Structure
One very large directory tree
26,000 files
2,500 subdirectories
240 file types
Mozilla Directory References
1,521 directory references
Avg. fan-in/fan-out 12
Max fan-in=100
Max fan-out=42
Median fan-in=5
Median fan-out=12
Build-level
File (atomic entity)
–Source
–Documentation
Directory tree (container) = source tree
Build process
–To build/install software
–Driven by make/ANT/…
Configuration process
–To control build process
–Driven by configure/configuration files/…
Mozilla Build Level
1,350 Makefiles
40,000 LOC build instructions
16,000 LOC configuration
Cyclic dependencies
Two-phase build process
Centralized build/configuration knowledge
Code duplication
Component implementations scattered
Motivation – continued
Problems:
– Long files are harder to manage
(for both programmers and machines)
– Every change requires long compilation
– Many programmers can not modify the
same file simultaneously
– Division to components is desired
Motivation – continued
Solution : divide project to multiple files
Targets:
– Good division to components
– Minimum compilation when something is
changed
– Easy maintenance of project structure,
dependencies and creation
Project maintenance
Done in Unix by the Makefile mechanism
A makefile is a file (script) containing :
– Project structure (files, dependencies)
– Instructions for files creation
The make command reads a makefile,
understands the project structure and
makes up the executable
Note that the Makefile mechanism is not
limited to C programs
Project structure
Project structure and dependencies can be
represented as a DAG (= Directed Acyclic
Graph)
Example :
– Program contains 3 files
– main.c., sum.c, sum.h
– sum.h included in both .c files
– Executable should be the file sum
sum (exe)
sum.o
main.o
main.c
sum.h
sum.c
sum.h
Make: Header Dependencies
What if …
– Sensor.cc changes?
– Sensor.h changes?
– Robot.h changes?
Pattern rule ignores header
dependencies!
Requires unnecessary “make
clean; make”
Let gcc figure out the header
dependencies for us!
The –MM option produces make
rules in a .d file which we can
then include in the Makefile
Sensor.h
Sensor.cc
Robot.h
Robot.cc
robotest.cc
makefile
sum: main.o sum.o
gcc –o sum main.o sum.o
main.o: main.c sum.h
gcc –c main.c
sum.o: sum.c sum.h
gcc –c sum.c
Rule syntax
main.o: main.c sum.h
gcc –c main.c
Rule
tab
dependency
action
Equivalent makefiles
.o depends (by default) on corresponding
.c file. Therefore, equivalent makefile is:
sum: main.o sum.o
gcc –o sum main.o sum.o
main.o: sum.h
gcc –c main.c
sum.o: sum.h
gcc –c sum.c
Equivalent makefiles - continued
We can compress identical dependencies
and use built-in macros to get another
(shorter) equivalent makefile :
sum: main.o sum.o
gcc –o $@ main.o sum.o
main.o sum.o: sum.h
gcc –c $*.c
make operation
Project dependencies tree is constructed
Target of first rule should be created
We go down the tree to see if there is a target
that should be recreated. This is the case when
the target file is older than one of its
dependencies
In this case we recreate the target file according
to the action specified, on our way up the tree.
Consequently, more files may need to be
recreated
If something is changed, linking is usually
necessary
make operation - continued
make operation ensures minimum
compilation, when the project structure is
written properly
Do not write something like:
prog: main.c sum1.c sum2.c
gcc –o prog main.c sum1.c sum2.c
which requires compilation of all project when
something is changed
Make operation - example
File
sum
main.o
sum.o
main.c
sum.c
sum.h
Last Modified
10:03
09:56
09:35
10:45
09:14
08:39
Make operation - example
Operations performed:
gcc –c main.c
gcc –o sum main.o sum.o
main.o should be recompiled (main.c is
newer).
Consequently, main.o is newer than sum and
therefore sum should be recreated (by relinking).
Another makefile example
# Makefile to compare sorting routines
BASE = /home/blufox/base
CC
= gcc
CFLAGS = -O –Wall
EFILE
= $(BASE)/bin/compare_sorts
INCLS = -I$(LOC)/include
LIBS
= $(LOC)/lib/g_lib.a \
$(LOC)/lib/h_lib.a
LOC
= /usr/local
OBJS = main.o another_qsort.o
compare.o quicksort.o
chk_order.o \
$(EFILE): $(OBJS)
@echo “linking …”
@$(CC) $(CFLAGS) –o $@ $(OBJS) $(LIBS)
$(OBJS): compare_sorts.h
$(CC) $(CFLAGS) $(INCLS) –c $*.c
# Clean intermediate files
clean:
rm *~ $(OBJS)
Example - continued
We can define multiple targets in a makefile
Target clean – has an empty set of
dependencies. Used to clean intermediate
files.
make
– Will create the compare_sorts executable
make clean
– Will remove intermediate files
Passing parameters to makefile
We can pass parameters to a makefile by
specifying them along with their values in
the command line.
For example:
make PAR1=1 PAR2=soft1
will call the makefile with 2 parameters:
PAR1 is assigned the value “1” and PAR2
is assigned the value “soft1”. The same
names should be used within the makefile
to access these variables (using the usual
“$(VAR_NAME)” syntax)
Passing parameters - continued
Note that assigning a value to a variable
within the makefile overrides any value
passed from the command line.
For example:
command line : make PAR=1
in the makefile:
PAR = 2
PAR value within the makefile will be 2,
overriding the value sent from the command
line
Conditional statements
Simple conditional statements can be
included in a makefile.
Usual syntax is:
ifeq (value1, value2)
body of if
else
body of else
endif
Conditional statements - example
sum: main.o sum.o
gcc –o sum main.o sum.o
main.o: main.c sum.h
gcc –c main.c
#deciding which file to compile to create sum.o
ifeq ($(USE_SUM), 1)
sum.o: sum1.c sum.h
gcc –c sum1.c –o $@
else
sum.o: sum2.c sum.h
gcc –c sum2.c –o $@
endif
Make: Advanced Options
Text manipulation functions
– $(patsubst pattern,replacement,text)
– $(patsubst %.o,%.cc,<list of objfiles>)
Pattern rules
– Uses a pattern in the target with % as wildcard
– Matched % can be used in dependencies as well
– Simple Example:
%.o : %.cc
<tab>command …
Pattern rules with automatic variables
–
–
–
–
$@ full target name
$< first dependency
$* string which matched % wildcard
Advance Example:
%.o : %.cc
<tab>$(CC) $(CCFLAGS) –c $< $(INCPATHS)
Make: A Simple Example
CC=g++
FLAGS=-g
MASLAB_ROOT=maslab-software
LIB_DIR=$(MASLAB_ROOT)/liborc
INC_DIR=$(MASLAB_ROOT)/liborc
LIBS=-lm –lpthread -lorc
#
#
#
#
#
#
Compiler to use
Compile flags
Maslab software root directory
orc-related library directory
orc-related include directory
Library files
all : helloworld
helloworld.o : helloworld.cc
$(CC) $(FLAGS) –c $*.cc –o $@
helloworld: helloworld.o
$(CC) -o helloworld helloworld.o $(LIBS)
clean:
rm -f *.o helloworld
Make: Example Makefile
MASLABROOT = /mnt/maslab/software/maslab-software-current
#This is the list of places to look for include files
INCPATHS = -I$(MASLABROOT)/libs/liborc \
-I$(MASLABROOT)/libs/libim \
-I$(MASLABROOT)/libs/libbotserver \
-I/opt/intel/ipp/include
#This is the list of places to look for libraries
LIBPATHS = -L$(MASLABROOT)/libs/liborc \
-L$(MASLABROOT)/libs/libim \
-L$(MASLABROOT)/libs/libbotserver \
-L/opt/intel/ipp/sharedlib
#This is the names of the libraries
LIBS = -lippipx -lippcvpx -lim -lorc -lbotserver -lm -lpthread -ljpeg -lpng
#This is the compiler to use
CC = g++
# This is your c++ file extension (usually cc or cpp)
CCEXT = cc
Make: Example Makefile (cont)
CCFLAGS = -g -Wall
# This rule builds everything.
# programs in this list.
all : robotest
You should put the names of all your
# This rule says how to turn any .cpp file into a .o file.
%.o : %.$(CCEXT)
$(CC) $(CCFLAGS) -c $< $(INCPATHS)
#---------------------------------------------------------------------# robotest
PROGRAM_NAME = robotest
PROGRAM_OBJS = robotest.o BumpSensor.o Robot.o
GLOBAL_OBJS += $(PROGRAM_OBJS)
JUNK += $(PROGRAM_NAME)
$(PROGRAM_NAME): $(PROGRAM_OBJS)
$(CC) $(PROGRAM_OBJS) -o $(PROGRAM_NAME) $(LIBS) $(LIBPATHS)
chmod a+x $(PROGRAM_NAME)
Extending Example Makefile
So to add a new executable program, simply cut and
paste the robotest section and enter your own
PROGRAM_NAME and PROGRAM_OBJS
#---------------------------------------------------------------------# Sensor Incremental Test
PROGRAM_NAME = sensor-test
PROGRAM_OBJS = sensor.t.o BumpSensor.o
GLOBAL_OBJS += $(PROGRAM_OBJS)
JUNK += $(PROGRAM_NAME)
$(PROGRAM_NAME): $(PROGRAM_OBJS)
$(CC) $(PROGRAM_OBJS) -o $(PROGRAM_NAME) $(LIBS) $(LIBPATHS)
chmod a+x $(PROGRAM_NAME)
Extending example Makefile
DEPENDS += $(patsubst %.o, %.d, $(GLOBAL_OBJS))
JUNK += $(DEPENDS)
include $(DEPENDS)
depend : $(DEPENDS)
depend.$(CCEXT) = set -e; $(CC) $(CCFLAGS) -MM $(DEFS) $(INCPATHS)
depend.filt = sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; [ -s $@ ] || rm -f $@
%.d: %.$(CCEXT)
$(depend.cc) $< | $(depend.filt)
#======================================================================
# Miscellaneous Rules
#---------------------------------------------------------------------# This rule cleans your directory. You could also add commands here
# to remove program files and any other files that should be cleaned
clean:
rm -f $(JUNK) *~ *.o core.[0-9]* core
ANT:
Another Nice Tool
What is Ant?
Java-based Build tool from Apache
De facto standard for building, packaging, and
installing Java applications
Accomplishes same objectives that make does on
Unix based systems
Files are written in XML
Why Ant?
Many claim.. That
– Unlike makefiles, Ant files work cross platform
- No need for multiple, complex makefiles
depending on the operating system.
- Tasks declared in platform independent way; Ant
engine translates to OS specific commands.
But still need to know (potentially) complex
path/install data. So not as general as they claim
Easy to create own Ant “tasks”, in addition to core
tasks
Installing Ant
Download Ant binary distribution from:
http://ant.apache.org/bindownload.cgi
Set ANT_HOME to where you installed Ant
Include $ANT_HOME/bin in PATH
Make sure JAVA_HOME is set to point to JDK
Running Ant
Type “ant” at the command line
Automatically looks for build.xml file in current
directory to run
Type “ant –buildfile buildfile.xml” to specify
another build file to run.
Ant Output
Sample build.xml
<project name="MyProject" default="dist" basedir=".">
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init" >
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile" >
<mkdir dir="${dist}/lib"/>
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>
<target name="clean" >
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
Ant Overview: Project
Each build file contains exactly one project and at
least one target
Project tags specify the basic project attributes
and have 3 properties:
- name
- default target
- basedir
Example: <project name=“MyProject” default=“build” basedir=“.”>
Ant Overview: Targets
Target is a build module in Ant
Each target contains task(s) for Ant to do
One must be a project default
Overall structure of targets:
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
Ant Overview: Tasks
Each target comprises one or more tasks
Task is a piece of executable Java code (e.g.
javac, jar, etc)
Tasks do the actual “build” work in Ant
Ant has core (built in) tasks and the ability to
create own tasks
Ant Overview: Tasks
Example:
<target name="prepare" depends="init“ >
<mkdir dir="${build}" />
</target>
<target name="build" depends="copy" >
<javac srcdir="src" destdir="${build}">
<include name="**/*.java" />
</javac>
</target>
Ant Overview: Core Tasks
javac – Runs the Java Compiler
java – Runs the Java Virtual Machine
jar (and war) – Create JAR files
mkdir – Makes a directory
copy – Copies files to specified location
delete – Deletes specified files
cvs – Invokes CVS commands from Ant
Ant Overview: Writing Own
Task
Create a Java class that extends org.apache.tools.ant.Task
For each attribute, write a setter method that is
public void and takes a single argument
Write a public void execute() method, with no
arguments, that throws a BuildException -- this
method implements the task itself
Ant Overview: Properties
Special task for setting up build file properties:
Example:
<property name=“src” value=“/home/src”/>
Can use ${src} anywhere in build file to denote
/home/src
Ant provides access to all system properties as if
defined by the <property> task
Ant Overview: Path Structures
Ant provides means to set various environment
variables like PATH and CLASSPATH.
Example of setting CLASSPATH:
<classpath>
<pathelement path="${classpath}"/>
<pathelement location="lib/helper.jar"/>
</classpath>
Command Line Arguments
-buildfile buildfile – specify build file to use
targetname – specify target to run (instead of
running default)
-verbose, -quiet, -debug – Allows control over
the logging information Ant outputs
-logger classname – Allows user to specify their
own classes for logging Ant events
IDE Integration
Eclipse, NetBeans, JBuilder, VisualAge, and
almost any other Java IDE has Ant integration
built-in to the system
Refer to each IDE’s documentation for how to use
Ant with that IDE
Web Development with Ant
Tomcat comes with special Ant tasks to ease Web
application development and deployment
Copy $TOMCAT_HOME/server/lib/catalina-ant.jar to
$ANT_HOME/lib
Ant tasks for Tomcat:
- install
- reload
- deploy
- remove
Documentation/References
Good tutorial for makefiles
http://www.gnu.org/manual/make-3.80/make.html
Good tutorial for cmakef
http://www.cmake.org/HTML/Documentation.html
ANT User Manual:
http://ant.apache.org/manual/index.html
Sun’s Web development tutorial (Ant and JSPs):
http://java.sun.com/webservices/docs/1.2/tutorial/doc/GettingStarted3.html
Standardized Build Interface
Different build systems exist, e.g.,
–make, ANT, shell scripts, IDE
Different software systems require different build
actions, e.g.,
–make
–make bootstrap, make, make install
make
make
make
make
make
clean
all
check
(un)install
dist
The real Problem
How do we handle platform specific issues?
– Providing a different Makefile for each architecture
– Using Autoconf, Automake and Libtool
The installer needs only
– Bourne shell
– C compilers
– Make program
Standardized Configuration
Interface
Different mechanisms exist to control software
construction, e.g.,
–configuration files, configuration tools, Makefile
editing
Standardized configuration interface to enable
uniform compile-time configuration:
configure
configure
configure
configure
configure
--help
--prefix=/usr
--with-aterm=/usr/lib
--with-optimization=true
--with-debug=false
Explicit Context Dependencies
Dependencies on build-level components are
declared in configuration interfaces
> configure --help
…
--with-aterm=DIR
--with-sglr=DIR
…
use ATerm Library at DIR
use SGLR Parser at DIR
Independent Deployment
Build-level components are deployed as packages
A package is a versioned release of a build-level
component, e.g.,
firefox-1.0.tar.gz
Packages are published on web/ftp sites
Third-party Composition
A configuration interface enables late-binding of
dependencies
> configure --with-aterm=/usr/local/aterm
--with-sglr=/usr/local/sglr
--with-…=
Compositions are thus not predefined
and can be defined by a third party
Some advantages when using GNU
autotools
The installation of a program is straightforward:
./configure; make; make install
This procedure checks for system parameters, libraries,
location of programs, availability of functions and writes
a Makefile
./configure supports many options to overwrite
defaults settings
GNU autoconf
Source Code
configure.ac
(configure.in)
aclocal
autoscan
autoconf
configure.scan
configure
GNU automake
Makefile.am
automake
Makefile.in
configure
Makefile
configure.ac
dnl Comment … …
AC_INIT(main.c)
AM_INIT_AUTOMAKE(project_name, 1.2.8)
AM_PROG_LIBTOOL
it supports libtool and shared libraries
AC_PROG_CC
it locates the C (C++) compiler
AC_HEADER_STDC
it checks for standard headers
AC_CHECK_HEADERS(sys/time.h /header.h)
it checks for headers availability
AC_CHECK_LIB(crypto SSLeay_version)
it checks for libraries availability
AC_CHECK_FUNCS(ctime)
it checks for functions availability
AC_PROG_INSTALL
it checks for BSD compatible install utility
AC_OUTPUT([Makefile])
(or AC_PROG_CXX)
Makefile.am
bin_PROGRAMS = foo
/configure --prefix=… (default /usr/local)
foo_PROGRAMS=foo.c foo.h
noist_PROGRAMS=test
(make compiles, make install does nothing)
EXTRA_DIST=disclaimer.txt
Example
foo.c :
#include <stdio.h>
main()
{
printf(“Cum grano salis\n");
}
Makefile.am :
bin_PROGRAMS = foo
foo_SOURCES = foo.c
configure.ac :
AC_INIT(foo.c)
AM_INIT_AUTOMAKE(latin_words, 0.9)
AC_PROG_CC
AC_HEADER_STDC
AC_PROG_INSTALL
AC_OUTPUT([Makefile])
Summary
Source Code, configure.ac, Makefile.am
autoscan; aclocal; autoconf
Create NEWS README AUTHORS ChangeLog
automake –add-missing
./configure; make; make dist
Result: project_name-2.10.tar.gz
aclocal.m4
autom4te-2.53.cache
ChangeLog
config.status
configure.in
COPYING
install-sh Makefile.am
missing
NEWS
README
AUTHORS
autoscan.log
config.log configure
configure.scan
INSTALL Makefile.in mkinstalldirs code.c
References
GNU Autoconf, Automake, and Libtool
http://sources.redhat.com/autobook/autobook/autobook_toc.html
GNU Autoconf Manual
http://www.gnu.org/manual/autoconf
GNU Automake Manual
http://www.gnu.org/manual/automake
GNU Libtool Manual
http://www.gnu.org/manual/libtool
Learning the GNU development tools
http://autotoolset.sourceforge.net/tutorial.html
The GNU configure and build system
http://www.airs.com/ian/configure/configure_toc.html
GNU macro processor (GNU m4)
http://www.gnu.org/manual/m4-1.4/m4.html