Day 16 of 60: I strongly dislike M4

Posted by nik on July 25, 2006

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/lib
$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.

Comments

Leave a response

  1. Andre Lucas Wed, 26 Jul 2006 11:31:13 PDT

    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.

  2. nik Wed, 26 Jul 2006 11:54:35 PDT

    I tried that yesterday.

    With

    changequote(`, \')dnl

    it gets further through the build process, but eventually fails when trying to make

    .../executable.m4:42 EOF in quote

    Since the manpage for m4 says:

    changequote without arguments restores the original values (that is,`\’).

    I\’ve tried changequote() and changequote too, to no effect. I\’ve even tried changequote(\"`\", \"\'\").

    Here\’s the current links.m4 (which doesn\’t work). If you can drop that in to devtools/M4/UNIX/, and get sh Build to work then I\’m interested in what you had to change.

  3. nik Wed, 26 Jul 2006 11:57:14 PDT

    You can, of course, ignore the backslashes in the previous comment. Seems to be a bug in WordPress.

  4. Andre Wed, 26 Jul 2006 12:35:07 PDT

    This compiled for me on Solaris 10 (gcc). I haven’t tried it on Sun Studio yet.

    — 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

  5. Andre Wed, 26 Jul 2006 12:37:41 PDT

    Not sure why I used blockquote instead of code. Sigh.

  6. Andre Wed, 26 Jul 2006 12:38:48 PDT

    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
     

  7. Andre Thu, 27 Jul 2006 14:38:54 PDT

    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
     

  8. Andre Thu, 27 Jul 2006 14:43:37 PDT

    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.

  9. Andre Thu, 27 Jul 2006 14:45:38 PDT

    Grrr! Wordpress ’smart quotes’ buggered it up this time. Sod it, read the patch!

  10. nik Fri, 28 Jul 2006 11:09:38 PDT

    Bingo. Committed, with related changes, in 1097.

  11. […] 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. […]

  12. Tref Fri, 29 Dec 2006 15:14:07 PST

    If Sendmail is driving you insane, I’d strongly recommend Exim. It’s an excellent MTA.

Comments


Close
E-mail It