12.3.1 How stepmake works

Typing make website runs the file ‘GNUmakefile’ from the build directory. This only contains 3 lines:

depth = .
include config$(if $(conf),-$(conf),).make
include $(configure-srcdir)/GNUmakefile.in

The variable depth is used throughout the make system to track how far down the directory structure the make is. The first include sets lots of variables but doesn’t "do" anything. Default values for these variables are automatically detected at the ./configure step, which creates the file ‘config.make’. The second include runs the file ‘GNUmakefile.in’ from the top level source directory.

This sets another load of variables, and then includes (i.e. immediately runs) ‘stepmake.make’ from the ‘make’ subdirectory. This sets a load of other variables, does some testing to see if SCONS (another build tool?) is being used, and then runs ‘make/config.make’ - which doesn’t seem to exist...

GP: scons is indeed a different build tool; I think that Jan experimented with it 5 years ago or something. It seems like we still have bits and pieces of it floating around.

Next, it runs ‘make/toplevel-version.make’, which sets the version variables for major, minor, patch, stable, development and mypatchlevel (which seems to be used for patch numbers for non-stable versions only?).

Next - ‘make/local.make’, which doesn’t exist.

Then a few more variable and the interesting comment:

# Don't try to outsmart us, you puny computer!
# Well, UGH.  This only removes builtin rules from

and then tests to see whether BUILTINS_REMOVED is defined. It appears to be when I run make, and so ‘stepmake/stepmake/no-builtin-rules.make’ is run. The comment at the head of this file says:

# UGH.  GNU make comes with implicit rules.
# We don't want any of them, and can't force users to run
# --no-builtin-rules

I’ve not studied that file at length, but assume it removes all make’s build-in rules (e.g. ‘*.c’ files are run through the GNU C compiler) - there’s a lot of them in here, and a lot of comments, and I’d guess most of it isn’t needed.

We return to ‘stepmake.make’, where we hit the make rule all: The first line of this is:

-include $(addprefix $(depth)/make/,$(addsuffix -inclusions.make, $(LOCALSTEPMAKE_TEMPLATES)))

which, when the variables are substituted, gives:


(Note - according to the make documentation, -include is only different from include in that it doesn’t produce any kind of error message when the included file doesn’t exist).

And the first file doesn’t exist. Nor the second. Next:

-include $(addprefix $(stepdir)/,$(addsuffix -inclusions.make, $(STEPMAKE_TEMPLATES)))

which expands to the following files:


One little feature to notice here - these are all absolute file locations - the line prior to this used relative locations. And none of these files exist, either.

(Further note - I’m assuming all these lines of make I’m following are autogenerated, but that’ll be something else to discover.)

JM: “No, these lines are not useful in LilyPond (this is why you think they are autogenerated), but they are part of StepMake, which was meant to be a package to be installed as a build system over autoconf/make in software project source trees.”

Next in ‘stepmake.make’:

include $(addprefix $(stepdir)/,$(addsuffix -vars.make, $(STEPMAKE_TEMPLATES)))

which expands to:


Woo. They all exist (they should as there’s no - in front of the include). ‘generic-vars.make’ sets loads of variables (funnily enough). ‘toplevel-vars.make’ is very short - one line commented as # override Generic_vars.make: and 2 as follows:

# urg?
include $(stepdir)/documentation-vars.make

I assume the urg comment refers to the fact that this should really just create more variables, but it actually sends us off to ‘/home/phil/lilypond-git/stepmake/stepmake/documentation-vars.make’.

That file is a 3 line variable setting one.

po-vars.make’ has the one-line comment # empty, as does ‘install-vars.make’.

So now we’re back to ‘stepmake.make’.

The next lines are :

# ugh. need to do this because of PATH :=$(top-src-dir)/..:$(PATH)
include $(addprefix $(depth)/make/,$(addsuffix -vars.make, $(LOCALSTEPMAKE_TEMPLATES)))

and the include expands to:

include ./make/generic-vars.make ./make/lilypond-vars.make.

These again set variables, and in some cases export them to allow child make processes to use them.

The final 4 lines of ‘stepmake.make’ are:

include $(addprefix $(depth)/make/,$(addsuffix -rules.make, $(LOCALSTEPMAKE_TEMPLATES)))
include $(addprefix $(stepdir)/,$(addsuffix -rules.make, $(STEPMAKE_TEMPLATES)))
include $(addprefix $(depth)/make/,$(addsuffix -targets.make, $(LOCALSTEPMAKE_TEMPLATES)))
include $(addprefix $(stepdir)/,$(addsuffix -targets.make, $(STEPMAKE_TEMPLATES)))

which expand as follows:

include ./make/generic-rules.make ./make/lilypond-rules.make
include ./make/generic-targets.make ./make/lilypond-targets.make

lilypond-rules.make’ is #empty

generic-rules.make’ does seem to have 2 rules in it. They are:

$(outdir)/%.ly: %.lym4
        $(M4) $< | sed "s/\`/,/g" > $@

$(outdir)/%: %.in
        rm -f $@
        cat $< | sed $(sed-atfiles) | sed $(sed-atvariables) > $@

I believe the first rule is for *.ly files, and has a prerequisite that *.lym4 files must be built first. The recipe is m4 | sed "s/\`/,/g" >. Perhaps someone with more Unix/make knowledge can comment on exactly what the rules mean/do.

toplevel-rules.make’ is #empty

po-rules.make’ is #empty

install-rules.make’ is #empty

generic-targets.make’ contains 2 lines of comments.

lilypond-targets.make’ contains only:

## TODO: fail dist or web if no \version present.
        grep -L version $(LY_FILES)

stepmake/generic-targets.make’ contains lots of rules - too many to list here - it seems to be the main file for rules. (FWIW I haven’t actually found a rule for website: anywhere, although it clearly exists. I have also found that you can display a rule in the terminal by typing, say make -n website. This is probably common knowledge.

stepmake/toplevel-targets.make’ adds a load of other (and occasionally the same) rules to the gernric-targets.

stepmake/po-targets.make’ is rules for po* makes.

stepmake/install-targets.make’ has rules for local-install*.

And that’s the end of stepmake.make. Back to ‘GNUmakefile.in’.

A bit more info from 27 March. I’ve put some error traces into GNUmakefile in the build directory, and it looks like the following lines actually cause the make to run (putting an error call above them - no make; below them - make):

ifeq ($(out),www)
# All web targets, except info image symlinks and info docs are
# installed in non-recursing target from TOP-SRC-DIR
        -$(INSTALL) -m 755 -d $(DESTDIR)$(webdir)
        rsync -rl --exclude='*.signature' $(outdir)/offline-root $(DESTDIR)$(webdir)
        $(MAKE) -C Documentation omf-local-install

I don’t currently understand the ifeq, since $(out) is empty at this point, but the line starting -$(INSTALL) translates to:

-/usr/bin/python /home/phil/lilypond-git/stepmake/bin/install.py \
  -c -m 755 -d /usr/local/share/doc/lilypond/html

End of work for Sunday 27th.

Another alterative approach to understanding the website build would be to redirect make -n website and make website to a text file and work through a) what it does and b) where the errors are occurring.

GP: wow, all the above is much more complicated than I’ve ever looked at stuff – I tend to do a "back first" approach (where I begin from the command-line that I want to modify, figure out where it’s generated, and then figure out how to change the generated command-line), rather than a "front first" (where you begin from the "make" command).

LilyPond — Contributor’s Guide v2.19.80 (development-branch).