]> git.draconx.ca Git - dxcommon.git/commitdiff
Fix DX_BASEDIR hoisting problems in base.m4.
authorNick Bowler <nbowler@draconx.ca>
Sat, 22 Nov 2014 18:38:20 +0000 (13:38 -0500)
committerNick Bowler <nbowler@draconx.ca>
Sun, 19 Apr 2015 18:52:16 +0000 (14:52 -0400)
Currently, DX_INIT expands to a bunch of text, mostly whitespace.
This is not normally a serious problem, except when DX_BASEDIR
is called at the top level without previously expanding DX_INIT.
Since DX_BASEDIR is intended to be expanded during argument
collection, the result is that DX_INIT's output ends up as part
of the argument where DX_BASEDIR appears.

Fixing this turns out to be somewhat non-trivial.  Both DX_INIT and
DX_BASEDIR need to be changed.

  - First, avoid using AC_REQUIRE in DX_BASEDIR.  This relies on
    diversions which do not work correctly during argument collection.

  - Rewrite DX_INIT so that it expands to no text whatsoever.

  - Finally, the AC_DEFUN_ONCE mechanism appears to insert newlines
    where the macros are called for the first time.  Use m4_ignore
    to eat that inside DX_BASEDIR.

m4/base.m4
m4/dx-stamp.m4
tests/macros.at

index aebf6cde1438800bb825edaa970088f56bf3ae43..86d6b842c0d6098fd29323945c7545ad2bacd4e5 100644 (file)
@@ -1,57 +1,68 @@
-dnl Copyright © 2012 Nick Bowler
+dnl Copyright © 2012, 2014 Nick Bowler
 dnl
-dnl Base definitions for dxcommon.
+dnl Base directory handling for dxcommon.
 dnl
 dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
 dnl This is free software: you are free to do what the fuck you want to.
 dnl There is NO WARRANTY, to the extent permitted by law.
 
-m4_pattern_forbid([^_?DX_])
+AC_PREREQ([2.64])
 
-dnl DX_INIT([directory])
-dnl
-dnl Sets the directory of the dxcommon checkout, which is used by other macros
-dnl to find any source files that they may need.  If this file was included
-dnl from its original location using m4_include, which normally happens when
-dnl using aclocal, then the directory will be determined automatically (and
-dnl this macro does not need to be called in configure.ac at all).  Otherwise,
-dnl this should be called prior to any other dxcommon macro.
+m4_pattern_forbid([^_?DX_])
 
+dnl _DX_BASE_FILE
+dnl
+dnl This macro identifies the filename of this file, used to automatically
+dnl determine the dxcommon base directory.  It is a literal string, thus it
+dnl should not be expanded directly; use m4_defn([_DX_BASE_FILE]) instead.
 m4_define([_DX_BASE_FILE], __file__)
-AC_DEFUN_ONCE([DX_INIT], [dnl
 
-dnl Care must be taken to avoid spurious expansions of things that look like
-dnl macros in the filename; this is made especially difficult since
-dnl m4_bpatsubst does not expand to a quoted string.
-m4_define([_DX_BASEDIR], m4_if([$1], [],
-       [m4_bpatsubst(m4_dquote(m4_defn([_DX_BASE_FILE])),
-                     [/m4/[^/]*\.m4\(.\)$], [\1])],
-       [[$1]]))
+dnl _DX_SET_BASEDIR([directory])
+dnl
+dnl Defines the macro _DX_BASEDIR to the dxcommon base directory.  If the
+dnl argument is empty, the base directory will be determined automatically.
+dnl Otherwise, the base directory is set to the argument (which is not
+dnl subject to macro expansion).
+dnl
+dnl Quoting here is tricky as we must avoid macro expansion of _DX_BASE_FILE,
+dnl but m4_bpatsubst does not quote its result.  The resulting _DX_BASEDIR
+dnl macro is a literal string, thus it should not be expanded directly; use
+dnl m4_defn([_DX_BASEDIR]) instead.
+m4_define([_DX_SET_BASEDIR], [m4_do(
+  [m4_define([_DX_BASEDIR], m4_ifval([$1], [[$1]],
+    [m4_bpatsubst(m4_dquote(m4_defn([_DX_BASE_FILE])),
+      [/m4/[^/]*\.m4\(.\)$], [\1])]))],
+  [_DX_STAMP])])
 
-dnl Include the stamp file, which will cause a failure at autoconf time
-dnl if it does not exist in the checkout.  We circumvent m4_include to
-dnl avoid warnings about multiple inclusions.
-m4_pushdef([m4_include], [m4_builtin([include], $][@)])
-m4_include(m4_defn([_DX_BASEDIR])[/m4/dx-stamp.m4])
-m4_popdef([m4_include])
-_DX_STAMP_DUMMY
+dnl Include the stamp file to force failure at autoconf time if it does
+dnl not exist in the checkout.  We circumvent m4_include to avoid warnings
+dnl about multiple inclusions.
+m4_define([_DX_STAMP], [m4_do(
+  [m4_pushdef([m4_include], [m4_builtin([include], $][@)])],
+  [m4_include(m4_defn([_DX_BASEDIR])[/m4/dx-stamp.m4])],
+  [m4_popdef([m4_include])])])
 
-dnl Autoconf scripts should use the DX_BASEDIR m4 macro instead of the
-dnl AC_SUBSTed shell variable, but we use the same name for the macro since
-dnl it means the same thing as the substituted variable.
+dnl DX_INIT(directory)
+dnl
+dnl Sets the dxcommon base directory, which is used by other macros to
+dnl find any source files that they may need.  It is not normally necessary
+dnl to use this macro.  If it used, it must be expanded prior to any other
+dnl dxcommon macro.  Otherwise, the base directory will be determined
+dnl automatically.
+dnl
+dnl The directory argument is a literal string, not subject to macro expansion.
 dnl
 dnl Autoconf versions <= 2.69 have a bug which causes the first argument of
-dnl AC_SUBST to be expanded as a macro when using the two-argument form.  So
-dnl until we require a newer version of autoconf, we must use the one-argument
-dnl form of AC_SUBST.
+dnl AC_SUBST to be expanded as a macro when using the two-argument form.  This
+dnl bug has been fixed upstream but as of September, 2014 there is no release
+dnl which includes the fix.
+AC_DEFUN_ONCE([DX_INIT], [m4_do(
+  [_DX_SET_BASEDIR([$1])],
+  [AC_SUBST([DX_BASEDIR])],
+  [AC_CONFIG_COMMANDS_PRE(
+    [[DX_BASEDIR]="AS_ESCAPE(m4_dquote(m4_defn([_DX_BASEDIR])))"])])])
 
-[DX_BASEDIR]="AS_ESCAPE(m4_dquote(m4_defn([_DX_BASEDIR])))"
-m4_pushdef([m4_pattern_allow])
-AC_SUBST([DX_BASEDIR])
-m4_popdef([m4_pattern_allow])
-])
-
-AC_DEFUN([DX_BASEDIR], [dnl
-AC_REQUIRE([DX_INIT])dnl
-m4_defn([_DX_BASEDIR])dnl
-])
+dnl DX_BASEDIR
+dnl
+dnl This macro expands to the dxcommon base directory, as a quoted string.
+AC_DEFUN([DX_BASEDIR], [m4_ignore(DX_INIT())m4_defn([_DX_BASEDIR])])
index 5b64a7cf9f15e1bac498fba614cfeacebac63c0d..f0784805c38058dcaeaed619d7757170fea5cfd6 100644 (file)
@@ -1,4 +1,4 @@
 dnl This m4 snippet does nothing; its existence is used to identify the
 dnl dxcommon checkout location.  We define a dummy macro so that aclocal
 dnl can pick it up.
-AC_DEFUN([_DX_STAMP_DUMMY])
+AC_DEFUN([_DX_STAMP_DUMMY])dnl
index 9986d75ffd0274b3ffc73d03d59b380d1c575599..f57ecae23976626ab7e9e8f49effb446dfff2746 100644 (file)
@@ -26,14 +26,12 @@ dnl Verify that the DX_BASEDIR macro expands correctly during argument
 dnl collection.  Crucially, the output must not contain any other text.
 AT_SETUP([DX_BASEDIR during argument collection])
 
-AT_XFAIL_IF([:])
-
 AT_DATA([test.in],
 [[@TEST@
 ]])
 
 TEST_CONFIGURE_AC(
-[[AC@&t@_SUBST([TEST], 'm4@&t@_dquote(DX_BASEDIR)')
+[[AC_SUBST([TEST], 'm4@&t@_dquote(DX_BASEDIR)')
 AC_CONFIG_FILES([test])
 ]])
 TEST_AUTORECONF
@@ -44,3 +42,39 @@ printf '%s\n' "$srcdir" | sed -e 's:/\./:/:g' -e 's:/\.$::g' \
 AT_CHECK([cat test], [0], [expout])
 
 AT_CLEANUP
+
+dnl Verify that DX_BASEDIR is correctly AC_SUBSTed
+AT_SETUP([DX_BASEDIR output substitution])
+
+AT_DATA([test.in],
+[[@DX_BASEDIR@
+]])
+
+TEST_CONFIGURE_AC(
+[[DX_INIT
+AC_CONFIG_FILES([test])
+]])
+TEST_AUTORECONF
+TEST_CONFIGURE
+
+printf '%s\n' "$srcdir" | sed -e 's:/\./:/:g' -e 's:/\.$::g' \
+                              -e 's:\(.\)//*:\1/:g' >expout
+AT_CHECK([cat test], [0], [expout])
+
+AT_CLEANUP
+
+dnl Verify that DX_BASEDIR is set correctly implicitly
+AT_SETUP([DX_BASEDIR implicit definition])
+
+AT_DATA([test.in],
+[[@DX_BASEDIR@
+]])
+
+TEST_CONFIGURE_AC(
+[[DX_EXPORTED_SH
+AC_CONFIG_FILES([test])
+]])
+TEST_AUTORECONF
+TEST_CONFIGURE
+
+AT_CLEANUP