Day 16 of 60: I strongly dislike M4
Which is a problem because the Sendmail build system is written in it.
Here’s the problem I’m trying to solve.
As mentioned previously, Sendmail supports a DESTDIR variable, which you can set on the make command line, to specify a prefix to be added to the all the installation paths.
The problem is that the build infrastructure doesn’t create some necessary directories. Specifically, it won’t create:
$DESTDIR/usr/bin
$DESTDIR/usr/share/man/cat8
$DESTDIR/usr/share/man/cat5
$DESTDIR/usr/share/man/cat1
Some of the code to support creating this is easy, but I’ve run in to problem with links.m4.
Specifically, this bit of code:
define(`bldMAKE_TARGET_LINKS',
` for i in $2; do \
rm -f $$i; \
ln -s ${DESTDIR}$1 $$i; \
done'
)dnl
The loop body needs to be modified with a mkdir call, like so:
define(`bldMAKE_TARGET_LINKS',
` for i in $2; do \
-mkdir `dirname $$i`; \
rm -f $$i; \
ln -s ${DESTDIR}$1 $$i; \
done'
)dnl
to ensure that the directory in which the link is going to be created will work.
The problem is the backticks. They don’t play nicely with M4. I thought I could fix this with changequote, but this code doesn’t work:
dnl Change the quote definition temporarily so that
dnl we can use backticks in the next bit of Makefile
changequote(",")dnl
define("bldMAKE_TARGET_LINKS",
" for i in $2; do \
-mkdir -p `dirname $$i`; \
rm -f $$i; \
ln -s ${DESTDIR}$1 $$i; \
done"
)dnl
dnl Change the quotes back
changequote(, )dnl
More specifically, I get errors like this:
.../library.m4:17 bad macro name
Where library.m4 includes links.m4.
What’s especially hateful is that if I cut and paste the code in to a separate m4 file it works fine (read: it produces the correct output).
Anyone know how I might fix this?
PS: Using other characters as quotes (e.g., changequote([, ]) doesn’t work, and nor does using $(...) instead of backticks. Solaris’ /bin/sh (which make(1) uses) doesn’t understand that construct.
Trackbacks
Use this link to trackback from your own site.
changequote(,) doesn’t reset the quotes, it turns off quoting. I think you want changequote(`,’).
I put your macro in my site.config.m4, with cq.([,]) before and cq.(`,’) at the end and it works fine. If I use cq.(,) at the end, it explodes spectacularly.
The reason it works standalone is because there’s nothing else to quote, so turning quoting off doesn’t cause a problem.
I tried that yesterday.
With
changequote(`, \')dnlit gets further through the build process, but eventually fails when trying to make
.../executable.m4:42 EOF in quoteSince the manpage for m4 says:
I\’ve tried
changequote()andchangequotetoo, to no effect. I\’ve even triedchangequote(\"`\", \"\'\").Here\’s the current links.m4 (which doesn\’t work). If you can drop that in to
devtools/M4/UNIX/, and getsh Buildto work then I\’m interested in what you had to change.You can, of course, ignore the backslashes in the previous comment. Seems to be a bug in WordPress.
This compiled for me on Solaris 10 (gcc). I haven’t tried it on Sun Studio yet.
Not sure why I used blockquote instead of code. Sigh.
Same patch, will need to xlate spaces to tabs.
--- devtools/M4/UNIX/links.nik 2006-07-26 12:33:13.423230000 +0100
+++ devtools/M4/UNIX/links.m4 2006-07-26 12:29:29.005179000 +0100
@@ -22,14 +22,14 @@
)dnl
dnl Change the quote definition temporarily so that we can use backticks
dnl in the next bit of Makefile
-changequote(",")dnl
-define("bldMAKE_TARGET_LINKS",
-" for i in $2; do \
+changequote([,])dnl
+define([bldMAKE_TARGET_LINKS],
+[ for i in $2; do \
-mkdir -p `dirname $$i`; \
rm -f $$i; \
ln -s ${DESTDIR}$1 $$i; \
- done"
-)dnl
+ done
+])dnl
dnl Change the quotes back
changequote(`, ')dnl
Ok, got this working reliably now. It’s a high-9 on the ugly hackometer, but it seems to work fairly portably.
The problem with using changequote is that it only applies to the first run through m4. It appears that the block in question goes through m4 twice, and that’s where the quoting headache comes from.
Instead of using changequote([,]), I put in enough quotes to survive the multiple m4 runs, and use the fact that the string (two single-quotes) is a null string in sh, in order to balance the m4-esque backtick-quote pairs.
E.g. in order to get in the output, I have `stuff “command`”’ more stuff’ in the macro. Actually, the output is , but since it’s interpreted by /bin/sh, ‘’ is effectively ignored. Ugly, but it works.
Patch against the original links.m4. There’s another little fix in there, as discussed the ‘-’ in front of mkdir shouldn’t be there, it’s a make construct and doesn’t work in the middle of a compound sh command.
--- devtools/M4/UNIX/links.m4.nik 2006-07-27 14:36:07.744667000 +0100
+++ devtools/M4/UNIX/links.m4 2006-07-27 14:36:36.849567000 +0100
@@ -20,16 +20,11 @@
define(`bldMAKE_SOURCE_LINKS',
`bldFOREACH(`bldMAKE_SOURCE_LINK(', $1)'dnl
)dnl
-dnl Change the quote definition temporarily so that we can use backticks
-dnl in the next bit of Makefile
-changequote([,])dnl
-define([bldMAKE_TARGET_LINKS],
-[ for i in $2; do \
- -mkdir -p `dirname $$i`; \
+define(`bldMAKE_TARGET_LINKS',
+` for i in $2; do \
+ mkdir -p ``dirname $$i`'''; \
rm -f $$i; \
ln -s ${DESTDIR}$1 $$i; \
done
-])dnl
-dnl Change the quotes back
-changequote(`, ')dnl
+')dnl
Ironically, my last post had a quoting error… (In the exposition, not the patch.) I used ‘<’ as a quote character, which generally doesn’t work well in HTML. Doh.
In order to get [stuff `command` more stuff] in the output, I put [`stuff “command`”’ more stuff’] in the macro definition. Actually the output is [stuff `command`'’ more stuff] but the ['’] is effectively removed by the shell.
Grrr! Wordpress ’smart quotes’ buggered it up this time. Sod it, read the patch!
Bingo. Committed, with related changes, in 1097.
[…] The issues with M4 have been resolved. A colleague, Andre Lucas, took up the challenge and worked out a fix which he describes in detail. And ministat’s now looking much better. It’s grown some useful new options, a lot of documentation, and can now (optionally) generate plots in colour. Look below the fold for two example plots. […]
If Sendmail is driving you insane, I’d strongly recommend Exim. It’s an excellent MTA.