Discussion:
m4/autoconf quoting difference in include()
Roman Neuhauser
2014-07-16 15:17:46 UTC
Permalink
(this is a resend with a proper subject, sorry)

i had some trouble figuring out how to get the include macro inside
another (parameterized) macro.

this works in m4:

changequote(`[', `]')

define([nodot], [[\([_0-9a-zA-Z]+\)]])
define([reversion], [^nodot\.nodot\.nodot$])
define([getver], [regexp($1, reversion, $2)])
define([readver], [getver(include($1), [\&])])

readver([VERSION])

this fails in configure.ac (autoconf 2.69):

m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))

messages:

aclocal: error: configure.ac:7: file '$1' does not exist
autoreconf: aclocal failed with exit status: 1

i can get it to work by quoting the m4_include macro name:

m4_define([readver], [getver([m4_include]($1), [\&])])

why is this? can you point me to the relevant passages in the manual?
i admit i haven't read it all (yet).
--
roman
Eric Blake
2014-07-16 16:25:16 UTC
Permalink
Post by Roman Neuhauser
(this is a resend with a proper subject, sorry)
i had some trouble figuring out how to get the include macro inside
another (parameterized) macro.
I think your problem is not with include, per se, but rather with the
more generic question of "How do I write a macro which in turn defines
another macro that contains parameterization".
Post by Roman Neuhauser
changequote(`[', `]')
define([nodot], [[\([_0-9a-zA-Z]+\)]])
define([reversion], [^nodot\.nodot\.nodot$])
define([getver], [regexp($1, reversion, $2)])
define([readver], [getver(include($1), [\&])])
Insufficiently quoted. You probably meant include([$1]), to include the
file literally named "VERSION" and not the file that happens to be
whatever the macro $1 expands to.
Post by Roman Neuhauser
readver([VERSION])
but you got away with it, because your m4 example did not define a macro
named VERSION. But that's unrelated to your actual problem.
Post by Roman Neuhauser
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
Why not use m4_bregexp here?
Post by Roman Neuhauser
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))
You aren't showing enough context here. My guess is that you are trying
to do something even bigger; maybe along the lines of:

AC_DEFUN([my_macro], [
... existing m4_define calls...
])
Post by Roman Neuhauser
aclocal: error: configure.ac:7: file '$1' does not exist
autoreconf: aclocal failed with exit status: 1
Your message is not reproduced if I do things at the top level:

$ cat > configure.ac <<\EOF
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))
AC_INIT
witness string
ver
EOF
$ echo 1.2.3 > VERSION
$ autoconf
$ grep -A1 'witness string' configure
witness string
1.2.3
$

But if I try to write a macro whose expansion defines macros, then I see
a similar issue:

$ cat configure.ac
AC_DEFUN([my_macro], [
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))
])
AC_INIT
witness string
my_macro
ver
$ autoconf
/usr/bin/m4:configure.ac:10: cannot open `': No such file or directory
autom4te: /usr/bin/m4 failed with exit status: 1
$

So - what's going on? The answer is that $1 is getting substituted too
early. In my example, it was getting substituted at the time I called
my_macro, with whatever $1 was in the argument to my_macro. That is, as
written, my_macro called without arguments includes this expansion text:

m4_define([readver], [getver(m4_include(), [\&])])

after $1 was prematurely expanded.

But my error message mentions `', not `$1', as the failed file name, so
I can't fathom the full context of your example that seems to be causing
$1 to be treated as a literal file name.
Post by Roman Neuhauser
m4_define([readver], [getver([m4_include]($1), [\&])])
Without seeing the full context of where you are trying to add this
text, I'm not sure why it (seems to) work for you. In my example, that
is not the right workaround:

$ cat configure.ac
AC_DEFUN([my_macro], [
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver([m4_include]($1), [\&])])
m4_define([ver], readver([VERSION]))
])
AC_INIT
witness string1
my_macro
ver
witness string2
$ autoconf
$ sed -n '/witness string1/,/witness string2/p' configure | cat -s
witness string1

witness string2
$

which means that I ended up defining 'ver' to the empty string. But
THIS works:

$ cat configure.ac
AC_DEFUN([my_macro], [
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($][1, reversion, $][2)])
m4_define([readver], [getver(m4_include($[]1), [\&])])
m4_define([ver], readver([VERSION]))
])
AC_INIT
witness string1
my_macro
ver
witness string2
$ autoconf
$ sed -n '/witness string1/,/witness string2/p' configure | cat -s
witness string1

1.2.3
witness string2
$

Notice that I used the construct define([name], [...($][1)...]) to get
the $1 to not be concatenated at the expansion of the outer macro, but
to wait until the inner m4_define is actually used.
Post by Roman Neuhauser
why is this? can you point me to the relevant passages in the manual?
https://www.gnu.org/software/autoconf/manual/autoconf.html#Quoting-and-Parameters
Post by Roman Neuhauser
i admit i haven't read it all (yet).
Other ideas. Do you really need to wait to define your helper macros
until the time that my_macro is expanded? Or can you hoist them to the
top level, outside of the AC_DEFUN, where you don't have to worry about
deferred concatenation of $ and 1?

Also, what are the contents of your VERSION file? Is the whole point of
your regexp to try and strip the trailing newline away? If so, why not
go with the simpler:

m4_define([ver], m4_esyscmd_s([cat VERSION]))
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Nick Bowler
2014-07-16 18:33:34 UTC
Permalink
Adding Automake list to Cc.
Post by Roman Neuhauser
(this is a resend with a proper subject, sorry)
i had some trouble figuring out how to get the include macro inside
another (parameterized) macro.
[...]
Post by Roman Neuhauser
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))
aclocal: error: configure.ac:7: file '$1' does not exist
autoreconf: aclocal failed with exit status: 1
Autoconf/m4 have no problem with using m4_include in this manner
(although you have some quoting issues). The problem here is aclocal
(part of Automake) which basically works by grepping a bunch of input
files for magic strings (such as m4_include).

Unfortunately, as you have just discovered, this method comes with some
severe limitations. I don't think the operation of aclocal is really
discussed in the Automake manual. This is regrettable because it's
easy to run into these problems by accident.
Post by Roman Neuhauser
m4_define([readver], [getver([m4_include]($1), [\&])])
You can trick aclocal really easily because it doesn't try to
understand m4 syntax at all. If this approach works for your
package, go for it.

Cheers,
--
Nick Bowler, Elliptic Technologies (http://www.elliptictech.com/)
Roman Neuhauser
2014-07-17 11:51:07 UTC
Permalink
Post by Roman Neuhauser
(this is a resend with a proper subject, sorry)
i had some trouble figuring out how to get the include macro inside
another (parameterized) macro.
[...]
Post by Roman Neuhauser
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))
aclocal: error: configure.ac:7: file '$1' does not exist
autoreconf: aclocal failed with exit status: 1
[...] The problem here is aclocal (part of Automake) which basically
works by grepping a bunch of input files for magic strings (such as
m4_include).
Unfortunately, as you have just discovered, this method comes with some
severe limitations. I don't think the operation of aclocal is really
discussed in the Automake manual. This is regrettable because it's
easy to run into these problems by accident.
wow, that's a really broken behavior...

oh and thank you for the reply, much appreciated!
--
roman
Roman Neuhauser
2014-07-17 12:08:17 UTC
Permalink
Post by Nick Bowler
Post by Roman Neuhauser
(this is a resend with a proper subject, sorry)
i had some trouble figuring out how to get the include macro inside
another (parameterized) macro.
[...]
Post by Roman Neuhauser
m4_define([nodot], [[\([_0-9a-zA-Z]+\)]])
m4_define([reversion], [^nodot\.nodot\.nodot$])
m4_define([getver], [regexp($1, reversion, $2)])
m4_define([readver], [getver(m4_include($1), [\&])])
m4_define([ver], readver([VERSION]))
aclocal: error: configure.ac:7: file '$1' does not exist
autoreconf: aclocal failed with exit status: 1
Autoconf/m4 have no problem with using m4_include in this manner
(although you have some quoting issues).
Nick, can you help me with those quoting issues a bit? i'm getting
really confused here. one thing i'm really curious about: why do i have
to double-quote the nodot value? if i don't, ver is empty no matter if
i quote the $1, $2 in getver or not.
--
roman
Loading...