automake-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Fix installation of scripts and programs with destructive $(transform)


From: Ralf Wildenhues
Subject: Fix installation of scripts and programs with destructive $(transform)
Date: Sat, 13 Sep 2008 12:23:08 +0200
User-agent: Mutt/1.5.18 (2008-05-17)

Jim notified me about a distcheck failure of coreutils with recent git
Automake.  It deals with a destructive $(transform) like this:
  program_transform_name='s/.*/foo/'

which happens to let multiple files end up with identical installed
names.

The failure happens with PROGRAMS and SCRIPTS.  The awk scripts that
collect files to be installed at once use a hash to collect them.
The key for the hash is a destination directory, for files which are
not renamed, or the destination file name, for renamed files.  This
breaks down if either destination file names are not unique, or overlap
with destination directories.  The latter is rather nonsensical, so
let's ignore that for now[1], but non-uniqueness is, while uncommon,
not forbidden by the API.

Fixed thusly.  FWIW, this commit also brings the tree to Autoconf 2.63.

Cheers, and thanks Jim for your testing!
Ralf

[1] until we receive bug reports  ;-)


    install: cope with non-injective $(transform).
    
    * lib/am/progs.am (install-%DIR%PROGRAMS): Rewrite rule to not
    try to use the installed name as key in a hash, so destructive
    $(transform) scripts still work.
    * lib/am/scripts.am (install-%DIR%SCRIPTS): Likewise.
    * tests/transform.test: Fix test to look in right place for
    installed files.
    * tests/transform2.test: New test.
    * tests/Makefile.am: Adjust.
    Report by Jim Meyering.

diff --git a/lib/am/progs.am b/lib/am/progs.am
index ac8bb68..2ff2c2a 100644
--- a/lib/am/progs.am
+++ b/lib/am/progs.am
@@ -47,29 +47,31 @@ install-%DIR%PROGRAMS: $(%DIR%_PROGRAMS)
            -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
        sed 'N;N;N;s,\n, ,g' | \
 ## The following awk script turns that into one line containing directories
-## and then lines of `target_name_or_directory sources...'.
-       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = "" } { \
-         if ($$2 == $$4) tgt = $$3; else tgt = $$3 "/" $$4; \
-         files[tgt] = files[tgt] " " $$1; dirs[$$3] = 1 } \
-         END { d=""; for (dir in dirs) d = d " " dir; print d; \
-               for (dir in files) print dir, files[dir] }' | { \
-       read dirs; \
-?!BASE?        for dir in $$dirs; do test . = $$dir || { \
-?!BASE?          echo " $(MKDIR_P) '$(DESTDIR)$(%NDIR%dir)/$$dir'"; \
-?!BASE?          $(MKDIR_P) "$(DESTDIR)$(%NDIR%dir)/$$dir" || exit $$?; \
-?!BASE?        }; done; \
-       while read dir files; do \
-         if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
-         test -z "$$files" || { \
-?!LIBTOOL?         echo " $(INSTALL_PROGRAM_ENV) $(%DIR%PROGRAMS_INSTALL) 
$$files '$(DESTDIR)$(%NDIR%dir)$$dir'"; \
-?!LIBTOOL?         $(INSTALL_PROGRAM_ENV) $(%DIR%PROGRAMS_INSTALL) $$files 
"$(DESTDIR)$(%NDIR%dir)$$dir" || exit $$?; \
+## and then lines of 'type target_name_or_directory sources...', with type
+## 'd' designating directories, and 'f' files.
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+?!BASE?          case $$type in \
+?!BASE?          d) echo " $(MKDIR_P) '$(DESTDIR)$(%NDIR%dir)/$$dir'"; \
+?!BASE?             $(MKDIR_P) "$(DESTDIR)$(%NDIR%dir)/$$dir" || exit $$?;; \
+?!BASE?          f) \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+?!LIBTOOL?           echo " $(INSTALL_PROGRAM_ENV) $(%DIR%PROGRAMS_INSTALL) 
$$files '$(DESTDIR)$(%NDIR%dir)$$dir'"; \
+?!LIBTOOL?           $(INSTALL_PROGRAM_ENV) $(%DIR%PROGRAMS_INSTALL) $$files 
"$(DESTDIR)$(%NDIR%dir)$$dir" || exit $$?; \
 ## Note that we explicitly set the libtool mode.  This avoids any
 ## lossage if the install program doesn't have a name that libtool
 ## expects.
-?LIBTOOL?        echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) --mode=install $(%DIR%PROGRAMS_INSTALL) $$files 
'$(DESTDIR)$(%NDIR%dir)$$dir'"; \
-?LIBTOOL?        $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) --mode=install $(%DIR%PROGRAMS_INSTALL) $$files 
"$(DESTDIR)$(%NDIR%dir)$$dir" || exit $$?; \
-         }; \
-       done; }
+?LIBTOOL?          echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) --mode=install $(%DIR%PROGRAMS_INSTALL) $$files 
'$(DESTDIR)$(%NDIR%dir)$$dir'"; \
+?LIBTOOL?          $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) --mode=install $(%DIR%PROGRAMS_INSTALL) $$files 
"$(DESTDIR)$(%NDIR%dir)$$dir" || exit $$?; \
+           } \
+?!BASE?          ;; esac \
+       ; done
+
 endif %?INSTALL%
 
 
diff --git a/lib/am/scripts.am b/lib/am/scripts.am
index 6db83da..e4b61d1 100644
--- a/lib/am/scripts.am
+++ b/lib/am/scripts.am
@@ -48,26 +48,25 @@ install-%DIR%SCRIPTS: $(%DIR%_SCRIPTS)
 ?BASE?     -e 'h;s|.*|.|' \
 ?!BASE?            -e "s|$$srcdirstrip/||" -e 'h;s|[^/]*$$||; s|^$$|.|' \
            -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
-       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = ""; list[""] = "" } { \
-         if ($$2 == $$4) tgt = $$3; else tgt = $$3 "/" $$4; \
-         files[tgt] = files[tgt] " " $$1; dirs[$$3] = 1; \
-         if (++n[tgt] == $(am__install_max)) \
-           { list[++lno] = tgt " " files[tgt]; n[tgt] = 0; files[tgt] = "" } } 
\
-         END { d = ""; for (dir in dirs) d = d " " dir; print d; \
-               for (l in list) print list[l]; \
-               for (dir in files) print dir, files[dir] }' | { \
-       read dirs; \
-?!BASE?        for dir in $$dirs; do test . = $$dir || { \
-?!BASE?          echo " $(MKDIR_P) '$(DESTDIR)$(%NDIR%dir)/$$dir'"; \
-?!BASE?          $(MKDIR_P) "$(DESTDIR)$(%NDIR%dir)/$$dir" || exit $$?; \
-?!BASE?        }; done; \
-       while read dir files; do \
-         if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
-         test -z "$$files" || { \
-           echo " $(%DIR%SCRIPT_INSTALL) $$files 
'$(DESTDIR)$(%NDIR%dir)$$dir'"; \
-           $(%DIR%SCRIPT_INSTALL) $$files "$(DESTDIR)$(%NDIR%dir)$$dir" || 
exit $$?; \
-         }; \
-       done; }
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+             if (++n[d] == $(am__install_max)) { \
+               print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+           else { print "f", d "/" $$4, $$1 } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+?!BASE?          case $$type in \
+?!BASE?          d) echo " $(MKDIR_P) '$(DESTDIR)$(%NDIR%dir)/$$dir'"; \
+?!BASE?             $(MKDIR_P) "$(DESTDIR)$(%NDIR%dir)/$$dir" || exit $$?;; \
+?!BASE?          f) \
+            if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+            test -z "$$files" || { \
+              echo " $(%DIR%SCRIPT_INSTALL) $$files 
'$(DESTDIR)$(%NDIR%dir)$$dir'"; \
+              $(%DIR%SCRIPT_INSTALL) $$files "$(DESTDIR)$(%NDIR%dir)$$dir" || 
exit $$?; \
+            } \
+?!BASE?          ;; esac \
+       ; done
 endif %?INSTALL%
 
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a9e995e..7146770 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -618,6 +618,7 @@ txinfo29.test \
 txinfo30.test \
 txinfo31.test \
 transform.test \
+transform2.test \
 unused.test \
 upc.test \
 upc2.test \
diff --git a/tests/transform.test b/tests/transform.test
index 7a9e549..a5f4730 100755
--- a/tests/transform.test
+++ b/tests/transform.test
@@ -1,5 +1,6 @@
 #! /bin/sh
-# Copyright (C) 2002, 2003, 2004, 2007  Free Software Foundation, Inc.
+# Copyright (C) 2002, 2003, 2004, 2007, 2008  Free Software Foundation,
+# Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -56,7 +57,7 @@ $AUTOMAKE
 $MAKE
 $MAKE test-install
 $MAKE uninstall
-test `find inst/foo -type f -print | wc -l` = 0
+test `find inst -type f -print | wc -l` = 0
 
 # Opportunistically test for installdirs.
 rm -rf inst
diff --git a/tests/transform2.test b/tests/transform2.test
new file mode 100755
index 0000000..f1faa94
--- /dev/null
+++ b/tests/transform2.test
@@ -0,0 +1,82 @@
+#! /bin/sh
+# Copyright (C) 2002, 2003, 2004, 2007, 2008  Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Make sure that --program-transform works even when multiple files are
+# collapsed.
+
+. ./defs || Exit 1
+
+set -e
+
+cat >>configure.in <<'END'
+AC_PROG_CC
+AC_OUTPUT
+END
+
+cat >Makefile.am <<'EOF'
+bin_PROGRAMS = p1 p2
+bin_SCRIPTS = s1.sh s2.sh
+man_MANS = m1.1 m2.1
+
+test-install: install
+       test -f inst/bin/p$(EXEEXT)
+       test -f inst/bin/s.sh
+       test -f inst/man/man1/m.1
+
+test-install-foo: install
+       test -f inst/bin/foo$(EXEEXT)
+       test -f inst/bin/foo
+       test -f inst/man/man1/foo.1
+       test ! -f inst/bin/p1$(EXEEXT)
+       test ! -f inst/bin/p2$(EXEEXT)
+       test ! -f inst/bin/s1.sh
+       test ! -f inst/bin/s2.sh
+       test ! -f inst/man/man/m1.1
+       test ! -f inst/man/man/m2.1
+EOF
+
+cat >p1.c <<'EOF'
+int
+main ()
+{
+  return 0;
+}
+EOF
+
+cp p1.c p2.c
+
+: > s1.sh
+: > s2.sh
+: > m1.1
+: > m2.1
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE
+
+./configure --program-transform-name='s/[12]//' --prefix "`pwd`/inst" --mandir 
"`pwd`/inst/man"
+$MAKE
+$MAKE test-install
+$MAKE uninstall
+test `find inst -type f -print | wc -l` = 0
+
+# Also squash all file types in question.
+./configure --program-transform-name='s/.*/foo/' --prefix "`pwd`/inst" 
--mandir "`pwd`/inst/man"
+$MAKE
+$MAKE test-install-foo
+$MAKE uninstall
+test `find inst -type f -print | wc -l` = 0
+:




reply via email to

[Prev in Thread] Current Thread [Next in Thread]