Difference between revisions of "Writing Makefiles"
(works) |
(modes) |
||
Line 1: | Line 1: | ||
Some tips for writing clean Makefile.am's in Apertium: |
Some tips for writing clean Makefile.am's in Apertium: |
||
==Modes== |
|||
==Only one modes goal== |
|||
If you have <code>apertium</code> revision 51184 or higher, you can do this to simplify dealing with [[Modes]] files / modes.xml: |
|||
Add <code>AP_MKINCLUDE</code> to <code>configure.ac</code> in the language pair. |
|||
So, make one goal for a mode you know it creates, and then put that goal into noinst_DATA: |
|||
Your <code>Makefile.am</code> should include this: |
|||
<pre> |
<pre> |
||
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=modes/$(PREFIX1).mode |
||
</pre> |
|||
(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.) |
|||
@ap_include@ |
|||
==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 <code>apertium -d . fie-bar</code>.) |
|||
⚫ | |||
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: |
|||
<pre> |
|||
EXTRA_DIST: |
|||
⚫ | |||
modes.xml \ |
|||
# other files, typically .dix and .t1x |
|||
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 |
|||
</pre> |
</pre> |
||
This method leaves no root-owned files hanging around. |
|||
Nowhere else should modes be mentioned in the <code>Makefile.am</code>. |
|||
(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== |
==Use .deps/.d to say that the .deps directory must be created== |
||
Line 60: | Line 47: | ||
==Removing directories on make clean== |
==Removing directories on make clean== |
||
Say you want to remove .deps and modes on "make clean". Don't do </code>CLEANFILES=-rf .deps modes file1 |
Say you want to remove .deps and modes on "make clean". Don't do </code>CLEANFILES=-rf .deps modes file1 file2 …</code>, it doesn't work everywhere. |
||
A more portable solution is this: |
A more portable solution is this: |
||
Line 68: | Line 55: | ||
-rm -rf .deps modes |
-rm -rf .deps modes |
||
</pre> |
</pre> |
||
==Avoid duplicating install="yes" (modes.xml) in Makefile.am== |
|||
Most language pairs have lines like |
|||
<pre> |
|||
$(INSTALL_DATA) $(PREFIX1).mode $(DESTDIR)$(apertium_modesdir) |
|||
rm $(PREFIX1).mode |
|||
</pre> |
|||
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: |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
(xmllint and sed are prerequisites of apertium/lttoolbox, and the sed line is portable, so it doesn't add any dependencies.) |
Revision as of 15:53, 24 March 2014
Some tips for writing clean Makefile.am's in Apertium:
Modes
If you have apertium
revision 51184 or higher, you can do this to simplify dealing with Modes files / modes.xml:
Add AP_MKINCLUDE
to configure.ac
in the language pair.
Your Makefile.am
should include this:
noinst_DATA=modes/$(PREFIX1).mode @ap_include@ install-data-local: install-modes EXTRA_DIST: modes.xml \ # other files, typically .dix and .t1x
Nowhere else should modes be mentioned in the Makefile.am
.
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