Sun WorkShop TeamWare User's Guide |
Using the
dmake
UtilityThis chapter describes the way the distributed make (
dmake
) utility distributes builds over several hosts to build programs concurrently over a number of workstations or multiple CPUs.
- Basic Concepts
- Understanding the dmake Utility
- Impact of the dmake Utility on Makefiles
- Using the dmake Utility
Basic Concepts
Distributed make (
dmake
) allows you to concurrently distribute the process of building large projects, consisting of many programs, over a number of workstations and, in the case of multiprocessor systems, over multiple CPUs. Thedmake
utility parses your makefiles and:
- Determines which targets can be built concurrently
- Distributes the build of those targets over a number of hosts
The
dmake
utility is a superset of themake
utility.To understand
dmake
, you should know about:
- Configuration files (runtime and build server)
- The dmake host
- The build server
Configuration Files
The
dmake
utility consults two files to determine to which build servers jobs are distributed and how many jobs can be distributed to each.Runtime Configuration File
The
dmake
utility searches for a runtime configuration file on thedmake
host to know where to distribute jobs. Generally, this file is in your home directory on thedmake
host and is named.dmakerc
. It consists of a list of build servers and the number of jobs to be distributed to each build server. See "The dmake Host" section for more information.Build Server Configuration File
Each build server that you want to participate in a distributed build must have a
/etc/opt/SPROdmake/dmake.conf
file. This file specifies the maximum total number of dmake jobs that can be distributed to this build server by all dmake users. In addition, it may specify the "nice" priority under which all dmake jobs should run.See The Build Server for more information.
The
dmake
HostThe dmake host is defined as the machine on which the dmake command is initially invoked. The
dmake
utility searches for a runtime configuration file to determine where to distribute jobs. Generally, this file must be in your home directory on the dmake host and is named.dmakerc
. Thedmake
utility searches for the runtime configuration file in these locations and in the following order:
- The path name you specify on the command line using the
-c
option- The path name you specify using the
DMAKE_RCFILE
makefile macro- The path name you specify using the
DMAKE_RCFILE
environment variable$(HOME)/.dmakerc
If a runtime configuration file is not found, the
dmake
utility distributes two jobs to the dmake host.The runtime configuration file allows you to specify a list of build servers and the number of jobs you want distributed to each build server. The following is an example of a
CODE EXAMPLE 10-1 dmakerc file.dmakerc
file:
# My machine. This entry causes dmake to distribute to it.falcon { jobs = 1 }hawkeagle { jobs = 3 }# Manager's machine. She's usually at meetingsheron { jobs = 4 }avocet
- The entries:
falcon
,hawk
,eagle
,heron
, andavocet
are listed build servers.- You can specify the number of jobs you want distributed to each build server. The default number of jobs is two.
- Any line that begins with the # character is interpreted as a comment.
Note In the code example above, list of build servers includesfalcon
which is also the dmake host. The dmake host can also be specified as a build server. If you do not include it in the runtime configuration file, no dmake jobs are distributed to it.
You can also construct groups of build servers in the runtime configuration file. dmake provides you with the flexibility of easily switching between different groups of build servers as circumstances warrant. For instance, you may define groups of build servers for builds under different operating systems, or you may define groups of build servers that have special software installed on them.
The following is an example of a runtime configuration file that contains groups of build servers:
- Formal groups are specified by the
group
keyword and lists of their members are delimited by braces ({}).- Build servers that are members of groups are specified by the optional
host
directive.- Groups can be members of other groups.
- Individual build servers can be listed in runtime configuration files that also contain groups of build servers; in this case,
dmake
treats these build servers as members of the unnamed group.In order of precedence, the
dmake
utility distributes jobs to the following:
- The formal group specified on the command-line as an argument to the
-g
option- The formal group specified by the
DMAKE_GROUP
makefile macro- The formal group specified by the
DMAKE_GROUP
environment variable- The first group specified in the runtime configuration file
The
dmake
utility allows you to specify a different execution path for each build server. By defaultdmake
looks for the dmake support binaries on the build server in the same logical path as on the dmake host. You can specify alternate paths for build servers as a host attribute in the.dmakerc
file. For example:
group lab1 {host falcon { jobs = 10 , path = "/set/dist/sparc-S2/bin" }host hawk { path = "/opt/SUNWspro/bin" }}You can use double quotation marks to enclose the names of groups and hosts in the
.dmakerc
file. This allows you more flexibility in the characters that you can use in group names. Digits are allowed, as well as alphabetic characters. Names that start with digits should be enclosed in double quotes. For example:
group "123_lab" {host "456_hawk" { path = "/opt/SUNWspro/bin" }}The Build Server
The
/etc/opt/SPROdmake/dmake.conf
file is in the file system of build servers. Use this file to limit the maximum number of dmake jobs (from all users) that can run concurrently on a build server and to specify the "nice" priority under which all dmake jobs should run. The following is an example of an/etc/opt/SPROdmake/dmake.conf
file. This file sets the maximum number of dmake jobs permitted to run on a build server (from alldmake
users) to be eight.
max_jobs: 8nice_prio: 5
Note If the/etc/opt/SPROdmake/dmake.conf
file does not exist on a build server, no dmake jobs will be allowed to run on that server.
Understanding the
dmake
UtilityTo run a distributed make, use the executable file
dmake
in place of the standardmake
utility. You should understand the Solarismake
utility before you usedmake
. If you need to read more about themake
utility, see the Solaris Programming Utilities Guide. If you use themake
utility, the transition todmake
requires little if any alteration.Impact of the
dmake
Utility on MakefilesThe methods and examples in this section show the kinds of problems that dmake can help solve. As procedures become more complicated, so do the makefiles that implement them. You must know which approach will yield a reasonable makefile that works. The examples in this section illustrate common code-development predicaments and some straightforward methods to simplify them using
dmake
.Using Makefile Templates
If you use a makefile template from the outset of your project, custom makefiles that evolve from the makefile templates will be:
- More familiar
- Easier to understand
- Easier to integrate
- Easier to maintain
- Easier to reuse
The less time you spend editing makefiles, the more time you have to develop your program or project.
Building Targets Concurrently
Large software projects typically consist of multiple independent modules that can be built concurrently. The
dmake
utility supports concurrent processing of targets on multiple machines over a network. This concurrency can markedly reduce the time required to build a large project.When given a target to build,
dmake
checks the dependencies associated with that target and builds those that are out of date. Building those dependencies may, in turn, entail building some of their dependencies. When distributing jobs,dmake
starts every target that it can. As these targets complete,dmake
starts other targets. Nested invocations ofdmake
are not run concurrently by default, but this can be changed (see Restricting Parallelism for more information).Since
dmake
builds multiple targets concurrently, the output of each build is produced simultaneously. To avoid intermixing the output of various commands,dmake
collects output from each build separately. Thedmake
utility displays the commands before they are executed. If an executed command generates any output, warnings, or errors,dmake
displays the entire output for that command. Since commands started later may finish earlier, this output may be displayed in an unexpected order.Limitations on Makefiles
Concurrent building of multiple targets places some restrictions on makefiles. Makefiles that depend on the implicit ordering of dependencies may fail when built concurrently. Targets in makefiles that modify the same files may fail if those files are modified concurrently by two different targets. Some examples of possible problems are discussed in this section.
Dependency Lists
When building targets concurrently, it is important that dependency lists be accurate. For example, if two executables use the same object file but only one specifies the dependency, then the build may cause errors when done concurrently. For example, consider the following makefile fragment:
all: prog1 prog2prog1: prog1.o aux.o$(LINK.c) prog1.o aux.o -o prog1prog2: prog2.o$(LINK.c) prog2.o aux.o -o prog2When built serially, the target
aux.o
is built as a dependent ofprog1
and is up-to-date for the build ofprog2
. If built in parallel, the link ofprog2
may begin before aux.o is built, and is therefore incorrect. The.KEEP_STATE
feature ofmake
detects some dependencies, but not the one shown above.Explicit Ordering of Dependency Lists
Other examples of implicit ordering dependencies are more difficult to fix. For example, if all of the headers for a system must be constructed before anything else is built, then everything must be dependent on this construction. This causes the makefile to be more complex and increases the potential for error when new targets are added to the makefile. The user can specify the special target
.WAIT
in a makefile to indicate this implicit ordering of dependents. Whendmake
encounters the.WAIT
target in a dependency list, it finishes processing all prior dependents before proceeding with the following dependents. More than one.WAIT
target can be used in a dependency list. The following example shows how to use.WAIT
to indicate that the headers must be constructed before anything else.
all: hdrs .WAIT libs functionsYou can add an empty rule for the
.WAIT
target to the makefile so that the makefile is compatible with the make utility.Concurrent File Modification
You must make sure that targets built concurrently do not attempt to modify the same files at the same time. This can happen in a variety of ways. If a new suffix rule is defined that must use a temporary file, the temporary file name must be different for each target. You can accomplish this by using the dynamic macros
$@
or$*
. For example, a.c.o
rule that performs some modification of the .c file before compiling it might be defined as:
.c.o:awk -f modify.awk $*.c > $*.mod.c$(COMPILE.c) $*.mod.c -o $*.o$(RM) $*.mod.cConcurrent Library Update
Another potential concurrency problem is the default rule for creating libraries that also modifies a fixed file, that is, the library. The inappropriate
.c.a
rule causesdmake
to build each object file and then archive that object file. Whendmake
archives two object files in parallel, the concurrent updates will corrupt the archive file.
.c.a:$(COMPILE.c) -o $% $<$(AR) $(ARFLAGS) $@ $%$(RM) $%A better method is to build each object file and then archive all the object files after completion of the builds. An appropriate suffix rule and the corresponding library rule are:
.c.a:$(COMPILE.c) -o $% $<$(COMPILE.c) -o $% $<lib.a: lib.a($(OBJECTS))$(AR) $(ARFLAGS) $(OBJECTS)$(RM) $(OBJECTS)Multiple Targets
Another form of concurrent file update occurs when the same rule is defined for multiple targets. An example is a
yacc
(1) program that builds both a program and a header for use withlex
(1). When a rule builds several target files, it is important to specify them as a group using the + notation. This is especially so in the case of a parallel build.
y.tab.c y.tab.h: parser.y$(YACC.y) parser.yThis rule is actually equivalent to the two rules:
y.tab.c: parser.y$(YACC.y) parser.yy.tab.h: parser.y$(YACC.y) parser.yThe serial version of
make
builds the first rule to producey.tab.c
and then determines thaty.tab.h
is up-to-date and need not be built. When building in parallel,dmake
checksy.tab.h
beforeyacc
has finished buildingy.tab.c
and notices thaty.tab.h
does need to be built, it then starts anotheryacc
in parallel with the first one. Since bothyacc
invocations are writing to the same files (y.tab.c
andy.tab.h
), these files are apt to be corrupted and incorrect. The correct rule uses the+
construct to indicate that both targets are built simultaneously by the same rule. For example:
y.tab.c + y.tab.h: parser.y$(YACC.y) parser.yRestricting Parallelism
Sometimes file collisions cannot be avoided in a makefile. An example is
xstr
(1), which extracts strings from a C program to implement shared strings. Thexstr
command writes the modified C program to the fixed filex.c
and appends the strings to the fixed filestrings
. Sincexstr
must be run over each C file, the following new.c.o
rule is commonly defined:
.c.o:$(CC) $(CPPFLAGS) -E $*.c | xstr -c -$(CC) $(CFLAGS) $(TARGET_ARCH) -c x.cmv x.o $*.oThe
dmake
utility cannot concurrently build targets using this rule since the build of each target writes to the samex.c
andstrings
files. Nor is it possible to change the files used. You can use the special target.NO_PARALLEL
: to telldmake
not to build these targets concurrently. For example, if the objects being built using the.c.o
rule were defined by theOBJECTS
macro, the following entry would forcedmake
to build those targets serially:
.NO_PARALLEL: $(OBJECTS)If most of the objects must be built serially, it is easier and safer to force all objects to default to serial processing by including the
.NO_PARALLEL
: target without any dependents. Any targets that can be built in parallel can be listed as dependencies of the.PARALLEL
: target:
.NO_PARALLEL:.PARALLEL: $(LIB_OBJECT)Nested Invocations of Distributed Make
When
dmake
encounters a target that invokes anotherdmake
command, it builds that target serially, rather than concurrently. This prevents problems where two differentdmake
invocations attempt to build the same targets in the same directory. Such a problem might occur when two different programs are built concurrently, and each must access the same library. The only way for eachdmake
invocation to be sure that the library is up-to-date is for each to invokedmake
recursively to build that library. Thedmake
utility recognizes a nested invocation only when the$(MAKE)
macro is used in the command line.If you nest commands that you know will not collide, you can force them to be done in parallel by using the
.PARALLEL:
construct.When a makefile contains many nested commands that run concurrently, the load-balancing algorithm may force too many builds to be assigned to the local machine. This may cause high loads and possibly other problems, such as running out of swap space. If such problems occur, allow the nested commands to run serially.
Using the
dmake
UtilityYou execute
dmake
on a dmake host and distribute jobs to build servers. You can also distribute jobs to the dmake host, in which case it is also considered to be a build server. Thedmake
utility distributes jobs based on makefile targets thatdmake
determines (based on your makefiles) can be built concurrently. You can use a machine as a build server if it meets the following requirements:
- From the dmake host (the machine you are using) you must be able to use
rsh
, without being prompted for a password, to remotely execute commands on the build server. See thersh
(1) man page for more information about thersh
command. For example:
demo%rsh
build_serverwhich dmake
/opt/SUNWspro/bin/dmake- The
bin
directory in which thedmake
software is installed must be accessible from the build server. It is common practice to have all build servers share a common dmake installation directory. See theshare
(1M) andmount
(1M) man pages or the system AnswerBook documentation for more information about creating shared filesystems.- By default,
dmake
assumes that the logical path to the dmake executables on the build server is the same as on the dmake host. You can override this assumption by specifying a path name as an attribute of the host entry in the runtime configuration file. For example:
group sparc-cluster {
host wren { jobs = 10 , path = "/export/SUNWspro/bin"}host stimpy { path = "/opt/SUNWspro/bin" }- The source hierarchy you are building must be:
From the dmake host you can control which build servers are used and how many dmake jobs are allotted to each build server. The number of dmake jobs that can run on a given build server can also be limited on that server.
If you specify the
-m
option with theparallel
argument, or set theDMAKE_MODE
variable or macro to the valueparallel
,dmake
does not scan your runtime configuration file. Therefore, you must specify the number of jobs using the-j
option or theDMAKE_MAX_JOBS
variable or macro. If you do not specify a value this way, a default of two jobs is used.If you modify the maximum number of jobs using the
-j
option, or theDMAKE_MAX_JOBS
variable or macro when usingdmake
in distributed mode, the value you specify overrides the values listed in the runtime configuration file. The value you specify is used as the total number of jobs that can be distributed to all build servers.If you access
dmake
from the Building window, use the online help to see how to specify your build servers and jobs. If you accessdmake
from the command line, see thedmake
man page (dmake.1
).
Sun Microsystems, Inc. Copyright information. All rights reserved. Feedback |
Library | Contents | Previous | Next | Index |