Writing Makefiles
Some tips for writing clean Makefile.am's in Apertium:
Contents
Only one modes goal
The command apertium-gen-modes
creates _all_ modes files at once. So one goal is sufficient (and several can lead to problems with e.g. make -j2) when creating your debug modes.
So, make one goal for a mode you know it creates, and then put that goal into noinst_DATA:
modes/$(PREFIX1).mode: modes.xml apertium-validate-modes modes.xml apertium-gen-modes modes.xml cp *.mode modes/ noinst_DATA=modes/$(PREFIX1).mode
(noinst_DATA is for listing stuff that you want built, but not installed or distributed. Don't list the mode in TARGETS_COMMON or EXTRA_DIST, debug modes should not be installed or distributed.)
Avoid ending up with root-owned modes files
When you do "sudo make install", some Makefiles.am still have a bug where they'll leave around root-owned modes files. Then on the next "make", you see a "Permission denied" error, since it tries to create the same filenames again as non-root. (The installable mode files have paths pointing to e.g. /usr/local, while the non-install mode files have paths that point to your source development directory. You want the latter to hang around so you can do apertium -d . fie-bar
.)
A workaround is this: when doing make install, first stash away any already existing development modes directory, the generate the install modes, then clean up the root-owned stuff and unstash the old modes directory:
install-data-local: mv modes modes.bak apertium-gen-modes modes.xml $(BASENAME) rm -rf modes mv modes.bak modes test -d $(DESTDIR)$(apertium_modesdir) || mkdir $(DESTDIR)$(apertium_modesdir) $(INSTALL_DATA) $(PREFIX1).mode $(DESTDIR)$(apertium_modesdir) $(INSTALL_DATA) $(PREFIX2).mode $(DESTDIR)$(apertium_modesdir) rm $(PREFIX1).mode $(PREFIX2).mode
This method leaves no root-owned files hanging around.
(It might look odd that we "rm -rf modes" there after gen-modes, but "apertium-gen-modes somedir" creates both apertium-foo-bar/foo-bar.mode and non-installable debug modes in apertium-foo-bar/modes/ – perhaps tihs could be fixed in apertium-gen-modes so we can avoid this makefile workaround.)
Use .deps/.d to say that the .deps directory must be created
Say you have several goals that put temporary files in .deps/, e.g.
.deps/apertium-wat-lol.lol.dix: apertium-wat-lol.lol.dix test -d .deps || mkdir .deps xsltproc lexchoicebil.xsl $< >$@
and so on. The .deps directory has to be created for the file in .deps to be created. If you put mkdir .deps in each such goal, you can get a race condition where two goals try to make .deps at the same time.
The solution is this: if a goal needs the .deps directory to be created, let it depend on the file .deps/.d
. First put this in Makefile.am:
.deps/.d: test -d .deps || mkdir .deps touch $@ .PRECIOUS: .deps/.d
And then, instead of creating the dir in each goal, just depend on .deps/.d for those goals:
.deps/apertium-wat-lol.lol.dix: apertium-wat-lol.lol.dix .deps/.d xsltproc lexchoicebil.xsl $< >$@
(The PRECIOUS
line prevents the .d file from being cleaned up and removed automatically.)
Removing directories on make clean
Say you want to remove .deps and modes on "make clean". Don't do CLEANFILES=-rf .deps modes file1 file2 …, it doesn't work everywhere.
A more portable solution is this:
CLEANFILES = $(TARGETS_COMMON) clean-local: -rm -rf .deps modes
Avoid duplicating install="yes" (modes.xml) in Makefile.am
Most language pairs have lines like
$(INSTALL_DATA) $(PREFIX1).mode $(DESTDIR)$(apertium_modesdir) rm $(PREFIX1).mode
for every mode that has install="yes" in modes.xml. So setting install="yes" doesn't actually install the mode, it just creates an installable mode. This is redundant and confusing.
To actually install all and only those with install="yes", you can do this:
install-data-local: mv modes modes.bak apertium-gen-modes modes.xml $(BASENAME) rm -rf modes mv modes.bak modes test -d $(DESTDIR)$(apertium_modesdir) || mkdir $(DESTDIR)$(apertium_modesdir) modes=`xmllint --xpath '//mode[@install="yes"]/@name' modes.xml | sed 's/ *name="\([^"]*\)"/\1.mode /g'`; \ $(INSTALL_DATA) $$modes $(DESTDIR)$(apertium_nn_modesdir); \ rm $$modes
(xmllint and sed are prerequisites of apertium/lttoolbox, and the sed line is portable, so it doesn't add any dependencies.)