| Introduction to Sun WorkShop |
The
dmakeUtilityThis appendix 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. See also thedmake(1) man page.Basic Concepts
Distributed make (
dmake) is a superset of themakeutility and 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.You execute
dmakeon admakehost and distribute jobs to build servers. You can also distribute jobs to thedmakehost, in which case it is also considered to be a build server. Thedmakeutility distributes jobs based on makefile targets thatdmakedetermines (based on your makefiles) can be built concurrently. From thedmakehost you can control which build servers are used and how manydmakejobs are allotted to each build server. The number ofdmakejobs that can run on a given build server can also be limited on that server.The distribution of
dmakejobs is controlled in two ways:
- A
dmakeuser on admakehost can specify the machines to use as build servers and the number of jobs to distribute to each build server.- The owner of a build server (a user who can alter the
/etc/opt/SPROdmake/dmake.confbuild server configuration file) can control the maximum total number ofdmakejobs that can be distributed to that build server.
Note If you accessdmakefrom the Building window, see the online help for information about specifying your build servers and jobs. If you accessdmakefrom the command line, see thedmake(1) man page.
To understand
dmake, you should know about:
- The
dmakehost- The build server
The
dmakeHostThe
dmakehost is defined as the machine on which thedmakecommand is initially issued. Thedmakeutility searches for a runtime configuration file to determine where to distribute jobs. Generally, this file must be in your home directory on thedmakehost and is named.dmakerc. Thedmakeutility 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
-coption- The path name you specify using the
DMAKE_RCFILEmakefile macro- The path name you specify using the
DMAKE_RCFILEenvironment variable$(HOME)/.dmakercIf a runtime configuration file is not found, the
dmakeutility distributes two jobs to thedmakehost.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. CODE EXAMPLE C-1 is an example of a
CODE EXAMPLE C-1.dmakercfile..dmakercFile
# 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, andavocetare 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. In the example above, the list of build servers includesfalconwhich is also thedmakehost. Thedmakehost can also be specified as a build server. If you do not include it in the runtime configuration file, nodmakejobs are distributed to it.You can also construct groups of build servers in the runtime configuration file. The
dmakeutility 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.CODE EXAMPLE C-2 shows a
CODE EXAMPLE C-2.dmakercfile that contains groups of build servers..dmakercFile With Groups of Build Servers
Formal groups are specified by the
groupkeyword and lists of their members are delimited by braces ({}). Build servers that are members of groups are specified by the optionalhostkeyword. 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,dmaketreats these build servers as members of the unnamed group.In order of precedence, the
dmakeutility distributes jobs to the following:
- The formal group specified on the command-line as an argument to the -
-goption- The formal group specified by the
DMAKE_GROUPmakefile macro- The formal group specified by the
DMAKE_GROUPenvironment variable- The first group specified in the runtime configuration file
The
CODE EXAMPLE C-3dmakeutility allows you to specify a different execution path for each build server. By defaultdmakelooks for thedmakesupport binaries on the build server in the same logical path as on thedmakehost. You can specify alternate paths for build servers as a host attribute in the.dmakercfile. For example:.dmakercFile With Alternate Paths for Build Servers
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
CODE EXAMPLE C-4.dmakercfile. 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:.dmakercFile With Special Characters
group "123_lab" {host "456_hawk" { path = "/opt/SUNWspro/bin" }}
The Build Server
Each build server that is to participate in a distributed build must have a file called
/etc/opt/SPROdmake/dmake.conf. This file is the build server configuration file and specifies the maximum total number ofdmakejobs that can be distributed to that particular build server by alldmakeusers. In addition, it might specify thenicepriority under which alldmakejobs should run.
Note If the/etc/opt/SPROdmake/dmake.conffile does not exist on a build server, nodmakejobs will be allowed to run on that server.
CODE EXAMPLE C-5 is an example of an
CODE EXAMPLE C-5/etc/opt/SPROdmake/dmake.conffile. This file sets the maximum number ofdmakejobs permitted to run on a build server (from alldmakeusers) to be eight (8).dmake.confFile
max_jobs: 8nice_prio: 5
You can use a machine as a build server if it meets the following requirements:
- From the
dmakehost (the machine you are using), you must be able to usershwithout being prompted for a password to remotely execute commands on the build server. See thersh(1) man page. For example:
%rshbuild-serverwhich dmake/opt/SUNWspro/bin/dmake- The
bindirectory in which thedmakesoftware is installed must be accessible from the build server. It is common practice to have all build servers share a commondmakeinstallation directory. See theshare(1M) andmount(1M) man pages.- By default,
dmakeassumes that the logical path to thedmakeexecutables on the build server is the same as on thedmakehost. 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 accessible from the build server and mounted under the same name.
Impact of the
dmakeUtility on MakefilesTo run a distributed make, use the executable file
dmakein place of the standardmakeutility. You should understand the Solarismakeutility before you usedmake. If you need to read more about themakeutility, see the Solaris Programming Utilities Guide and themake(1) man page. If you use themakeutility, the transition todmakerequires little or no alteration.The methods and examples shown in this section present the kinds of problems that lend themselves to being solved with
dmake. This section does not suggest that any one approach or example is the best.As procedures become more complicated, so do the makefiles that implement them. The examples in this section illustrate common code-development predicaments and some straightforward methods to simplify them using
dmake.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, and easier to reuse.
Concurrent Building of Targets
Large software projects typically consist of multiple independent modules that can be built concurrently. The
dmakeutility 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,
dmakechecks 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,dmakestarts every target that it can. As these targets complete,dmakestarts other targets. Nested invocations ofdmakeare not run concurrently by default, but this can be changed (see Parallelism for more information).Since
dmakebuilds multiple targets concurrently, the output of each build is produced simultaneously. To avoid intermixing the output of various commands,dmakecollects output from each build separately. Thedmakeutility displays the commands before they are executed. If an executed command generates any output, warnings, or errors,dmakedisplays the entire output for that command. Since commands started later might finish earlier, this output might 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 might 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.ois built as a dependent ofprog1and is up-to-date for the build ofprog2. If built in parallel, the link ofprog2can begin beforeaux.ois built and is therefore incorrect. The.KEEP_STATEfeature ofmakedetects 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
.WAITin a makefile to indicate this implicit ordering of dependents. Whendmakeencounters the.WAITtarget in a dependency list, it finishes processing all prior dependents before proceeding with the following dependents. More than one.WAITtarget can be used in a dependency list. The following example shows how to use.WAITto indicate that the headers must be constructed before anything else.
all: hdrs .WAIT libs functionsYou can add an empty rule for the
.WAITtarget to the makefile so that the makefile is compatible with themakeutility.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.orule that performs some modification of the.cfile 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.arule causesdmaketo build each object file and then archive that object file. Whendmakearchives 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 $% $<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
makebuilds the first rule to producey.tab.cand then determines thaty.tab.his up-to-date and need not be built. When building in parallel,dmakechecksy.tab.hbeforeyacchas finished buildingy.tab.cand notices thaty.tab.hdoes need to be built, it then starts anotheryaccin parallel with the first one. Since bothyaccinvocations are writing to the same files (y.tab.candy.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.yParallelism
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. Thexstrcommand writes the modified C program to the fixed filex.cand appends the strings to the fixed filestrings. Sincexstrmust be run over each C file, the following new.c.orule is commonly defined:
.c.o:$(CC) $(CPPFLAGS) -E $*.c | xstr -c -$(CC) $(CFLAGS) $(TARGET_ARCH) -c x.cmv x.o $*.oThe
dmakeutility cannot concurrently build targets using this rule since the build of each target writes to the samex.candstringsfiles. Nor is it possible to change the files used. You can use the special target.NO_PARALLEL: to telldmakenot to build these targets concurrently. For example, if the objects being built using the.c.orule were defined by theOBJECTSmacro, the following entry would forcedmaketo 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)When
dmakeencounters a target that invokes anotherdmakecommand, it builds that target serially, rather than concurrently. This prevents problems where two differentdmakeinvocations 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 eachdmakeinvocation to be sure that the library is up-to-date is for each to invokedmakerecursively to build that library. Thedmakeutility 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.
|
Sun Microsystems, Inc. Copyright information. All rights reserved. Feedback |
Library | Contents | Previous | Next | Index |