Using Subbuilds

3 minute read

The eMake subbuild feature is designed to help speed up component builds through intelligent build avoidance. Currently, the subbuild feature’s scope includes the following use case:

Makefile:
-------------
.PHONY: a b
all: a b
    @echo all
a b:
    $(MAKE) -C $@
a/Makefile
-------------
all: a.lib
    @echo a
a.lib:
    @touch $@
b/Makefile
-------------
all: ../a/a.lib
    @echo b

Explanation : If something from ‘ a ’ changes, and you are building from ‘ b ’, the only way to pick up the new a.lib is to build from the top level directory. With subbuilds, you know b ’s dependencies so you can build those dependencies directly without having to build everything from the top level directory.

The subbuild database must be built beforehand to make the dependency list available without having to parse any Makefiles that are not in the current directory.

The following sections describe how to use subbuilds. Refer to Subbuild Limitations for additional information.

Subbuild Database Generation

The following command runs your build as normal and also generates a subbuild database with the name emake.subbuild.db.

emake --emake-gen-subbuild-db=1 --emake-root=<path> --emake-subbuild-db=emake.subbuild.db

Where < path > is the eMake root directory setting.

--emake-root is required for cluster.

--emake-subbuild-db is optional. If it is missing, the default emake.subbuild.db name is used.

Run a Build Using Subbuild

The following command runs a build with subbuild information:

emake --emake-subbuild-db=emake.subbuild.db

Specify --emake-subbuild-db=<file> to run a build with subbuild information. When you invoke eMake with the --emake-subbuild-db option, it uses the dependencies extracted from the makefile and the subbuild database to determine which build components are prerequisites of the desired current make, then rebuilds those components before proceeding as normal.

When you specify --emake-subbuild-db=<file>, do not specify --emake-gen-subbuild-db, otherwise eMake regenerates the database.

Subbuild Limitations

  • There is no incremental building of the database. Each time you change something in a makefile in your build, you must rebuild the database by doing a full build.

  • The database is not currently optimized for size. This might result in an extremely large database for very large builds.

  • Subbuilds do not provide additional gains in non-recursive make builds.

  • Because of the manner in which subbuilds are currently scheduled, there is interleaving output for the “Entering directory…​” and “Leaving directory…​” messages.

For example: If a subbuild database was built for the following build:

Makefile:
-------------
.PHONY: a b
all: a b
a b:
    $(MAKE) -C $@
a/Makefile
----------------
all: a.lib
a.lib:
    echo aaa > $@
b/Makefile:
----------------
all: ../a/a.lib
    echo b

When you proceed to build just ‘ b ’ (maybe with “ emake -C b ”) and a/a.lib is missing, you receive “entering directory a” after “entering directory b”, even though ‘ a ’ is supposed to be built before ‘ b ’.

make: Entering directory 'b'
make -C a
make[1]: Entering directory 'a'
echo aaa > a.lib
make[1]: Leaving directory 'a'
echo b
b
make: Leaving directory 'b'

Information Applying to Local Builds Only

  • Rules to build a sub-directory’s output files must not overlap. For example: The rule to build sub1/foo.o must appear in sub1/Makefile only and not sub2/Makefile. Default suffix rules can cause eMake to find a way to build sub1/foo.o while trying to build sub2. In this situation, adding “ .SUFFIXES: ” to sub2/Makefile can resolve the issue.

  • Subbuilds require that the build be componentized to some degree.

  • Subbuilds require that you have practiced “good hygiene” in your build tree—there must be explicit dependencies mentioned in the component makefiles.

For example: If a build has two components, foo and bar, where foo produces a library foo.dll and bar uses that library, the rule might be written to produce bar.exe such as this in bar/Makefile:

bar.exe: $(BAR_OBJS)
    link $(BAR_OBJS) -l $(OUTDIR)/foo/foo.dll

For subbuilds to work (in local mode), it must be modified as in the following:

bar.exe: $(BAR_OBJS) $(OUTDIR)/foo/foo.dll
    link $(BAR_OBJS) -l $(OUTDIR)/foo/foo.dll

Note that it is explicitly stated that bar.exe requires foo.dll. Also note that it is NOT required to have a rule to build foo.dll in bar/Makefile.

There cannot be ANY rule at all to build $(OUTDIR)/foo/foo.dll in bar/Makefile, explicit or implicit, otherwise you will get the wrong information for building foo/foo.dll in the subbuilds database. The subbuilds database currently allows updates to existing entries while building the database.