diff options
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | bin/automake.in | 102 | ||||
-rw-r--r-- | t/list-of-tests.mk | 1 | ||||
-rw-r--r-- | t/subobj-objname-clash.sh | 104 |
4 files changed, 197 insertions, 17 deletions
@@ -64,6 +64,13 @@ New in 1.16: +* Miscellaneous changes + + - When subdir-objects is in effect, Automake will now construct + shorter object file names when no programs and libraries name + clashes are encountered. This should make the discouraged use of + 'foo_SHORTNAME' unnecessary in many cases. + * Bugs fixed: - Automatic dependency tracking has been fixed to work also when the diff --git a/bin/automake.in b/bin/automake.in index 8db874cc7..d126836a0 100644 --- a/bin/automake.in +++ b/bin/automake.in @@ -74,6 +74,7 @@ use Automake::Wrap 'makefile_wrap'; use Automake::Language; use File::Basename; use File::Spec; +use List::Util 'none'; use Carp; ## ----------------------- ## @@ -472,6 +473,15 @@ my %dep_files; # This is a list of all targets to run during "make dist". my @dist_targets; +# List of all programs, libraries and ltlibraries as returned +# by am_install_var +my @proglist; +my @liblist; +my @ltliblist; +# Blacklist of targets (as canonical base name) for which object file names +# may not be automatically shortened +my @dup_shortnames; + # Keep track of all programs declared in this Makefile, without # $(EXEEXT). @substitutions@ are not listed. my %known_programs; @@ -592,6 +602,11 @@ sub initialize_per_input () @dist_common = (); $handle_dist_run = 0; + @proglist = (); + @liblist = (); + @ltliblist = (); + @dup_shortnames = (); + %known_programs = (); %known_libraries = (); @@ -1704,14 +1719,48 @@ sub handle_single_transform # object. In this case we rewrite the object's # name to ensure it is unique. - # We choose the name 'DERIVED_OBJECT' to ensure - # (1) uniqueness, and (2) continuity between - # invocations. However, this will result in a - # name that is too long for losing systems, in - # some situations. So we provide _SHORTNAME to - # override. - - my $dname = $derived; + # We choose the name 'DERIVED_OBJECT' to ensure (1) uniqueness, + # and (2) continuity between invocations. However, this will + # result in a name that is too long for losing systems, in some + # situations. So we attempt to shorten automatically under + # subdir-objects, and provide _SHORTNAME to override as a last + # resort. If subdir-object is in effect, it's usually + # unnecessary to use the complete 'DERIVED_OBJECT' (that is + # often the result from %canon_reldir%/%C% usage) since objects + # are placed next to their source file. Generally, this means + # it is already unique within that directory (see below for an + # exception). Thus, we try to avoid unnecessarily long file + # names by stripping the directory components of + # 'DERIVED_OBJECT'. This allows avoiding explicit _SHORTNAME + # usage in many cases. EXCEPTION: If two (or more) targets in + # different directories but with the same base name (after + # canonicalization), using target-specific FLAGS, link the same + # object, then this logic clashes. Thus, we don't strip if + # this is detected. + my $dname = $derived; + if ($directory ne '' + && option 'subdir-objects' + && none { $dname =~ /$_$/ } @dup_shortnames) + { + # At this point, we don't clear information about what + # parts of $derived are truly file name components. We can + # determine that by comparing against the canonicalization + # of $directory. + my $dir = $directory . "/"; + my $cdir = canonicalize ($dir); + my $dir_len = length ($dir); + # Make sure we only strip full file name components. This + # is done by repeatedly trying to find cdir at the + # beginning. Each iteration removes one file name + # component from the end of cdir. + while ($dir_len > 0 && index ($derived, $cdir) != 0) + { + # Eventually $dir_len becomes 0. + $dir_len = rindex ($dir, "/", $dir_len - 2) + 1; + $cdir = substr ($cdir, 0, $dir_len); + } + $dname = substr ($derived, $dir_len); + } my $var = var ($derived . '_SHORTNAME'); if ($var) { @@ -2432,12 +2481,33 @@ sub handle_libtool () LTRMS => join ("\n", @libtool_rms)); } +# Check for duplicate targets +sub handle_targets () +{ + my %seen = (); + my @dups = (); + @proglist = am_install_var ('progs', 'PROGRAMS', + 'bin', 'sbin', 'libexec', 'pkglibexec', + 'noinst', 'check'); + @liblist = am_install_var ('libs', 'LIBRARIES', + 'lib', 'pkglib', 'noinst', 'check'); + @ltliblist = am_install_var ('ltlib', 'LTLIBRARIES', + 'noinst', 'lib', 'pkglib', 'check'); + + # Record duplications that may arise after canonicalization of the + # base names, in order to prevent object file clashes in the presence + # of target-specific *FLAGS + my @targetlist = (@proglist, @liblist, @ltliblist); + foreach my $pair (@targetlist) + { + my $base = canonicalize (basename (@$pair[1])); + push (@dup_shortnames, $base) if ($seen{$base}); + $seen{$base} = $base; + } +} sub handle_programs () { - my @proglist = am_install_var ('progs', 'PROGRAMS', - 'bin', 'sbin', 'libexec', 'pkglibexec', - 'noinst', 'check'); return if ! @proglist; $must_handle_compiled_objects = 1; @@ -2524,8 +2594,6 @@ sub handle_programs () sub handle_libraries () { - my @liblist = am_install_var ('libs', 'LIBRARIES', - 'lib', 'pkglib', 'noinst', 'check'); return if ! @liblist; $must_handle_compiled_objects = 1; @@ -2634,9 +2702,7 @@ sub handle_libraries () sub handle_ltlibraries () { - my @liblist = am_install_var ('ltlib', 'LTLIBRARIES', - 'noinst', 'lib', 'pkglib', 'check'); - return if ! @liblist; + return if ! @ltliblist; $must_handle_compiled_objects = 1; my @prefix = am_primary_prefixes ('LTLIBRARIES', 0, 'lib', 'pkglib', @@ -2729,7 +2795,7 @@ sub handle_ltlibraries () skip_ac_subst => 1); } - foreach my $pair (@liblist) + foreach my $pair (@ltliblist) { my ($where, $onelib) = @$pair; @@ -7793,6 +7859,8 @@ sub generate_makefile handle_configure ($makefile_am, $makefile_in, $makefile, @inputs); handle_gettext; + + handle_targets; handle_libraries; handle_ltlibraries; handle_programs; diff --git a/t/list-of-tests.mk b/t/list-of-tests.mk index 15755c52b..dacdc8dd8 100644 --- a/t/list-of-tests.mk +++ b/t/list-of-tests.mk @@ -1062,6 +1062,7 @@ t/subobjname.sh \ t/subobj-clean-pr10697.sh \ t/subobj-clean-lt-pr10697.sh \ t/subobj-indir-pr13928.sh \ +t/subobj-objname-clash.sh \ t/subobj-vpath-pr13928.sh \ t/subobj-pr13928-more-langs.sh \ t/subpkg.sh \ diff --git a/t/subobj-objname-clash.sh b/t/subobj-objname-clash.sh new file mode 100644 index 000000000..a33d36bc5 --- /dev/null +++ b/t/subobj-objname-clash.sh @@ -0,0 +1,104 @@ +#! /bin/sh +# Copyright (C) 1996-2017 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 2, 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 object names don't clash when using subdir-objects. +# The check is done for clashing programs, clashing libraries and +# a program that clashes with a library + +. test-init.sh + +mkdir src + +cat >> configure.ac << 'END' +AC_PROG_CC +AC_PROG_RANLIB +AC_OUTPUT +END + +cat > Makefile.am << 'END' +AUTOMAKE_OPTIONS = subdir-objects foreign +noinst_PROGRAMS = +noinst_LIBRARIES = + +# CLASHING PROGRAMS +noinst_PROGRAMS += foo src/foo +foo_SOURCES = src/foo.c src/main.c +foo_CPPFLAGS = -DVAL=0 +src_foo_CPPFLAGS = -DVAL=1 +src_foo_SOURCES = src/foo.c src/main.c + +# CLASHING LIBS +noinst_PROGRAMS += bar src/bar +noinst_LIBRARIES += libbar.a src/libbar.a +bar_SOURCES = src/main.c +bar_LDADD = libbar.a +src_bar_SOURCES = src/main.c +src_bar_LDADD = src/libbar.a +libbar_a_SOURCES = src/foo.c +libbar_a_CPPFLAGS = -DVAL=0 +src_libbar_a_SOURCES = src/foo.c +src_libbar_a_CPPFLAGS = -DVAL=1 + +# CLASHING PROGRAM + LIB +noinst_PROGRAMS += libzap_a src/zap +noinst_LIBRARIES += src/libzap.a +libzap_a_SOURCES = src/main.c src/foo.c +libzap_a_CPPFLAGS = -DVAL=2 +src_zap_SOURCES = src/main.c +src_zap_LDADD = src/libzap.a +src_libzap_a_SOURCES = src/foo.c +src_libzap_a_CPPFLAGS = -DVAL=3 + +# NON-CLASHING +noinst_PROGRAMS += src/foo-uniq +src_foo_uniq_SOURCES = src/main.c src/foo.c +src_foo_uniq_CPPFLAGS = -DVAL=4 +END + +cat > src/foo.c << 'END' +int +foo () +{ + return VAL; +} +END + +cat > src/main.c << 'END' +int foo (void); + +int +main () +{ + return foo (); +} +END + +$ACLOCAL +$AUTOCONF +$AUTOMAKE --add-missing + +./configure +$MAKE +set +e +./foo || fail_ "./foo should return 0" +./src/foo; test $? = 1 || fail_ "./src/foo should return 1" +./bar || fail_ "./bar should return 0" +./src/bar; test $? = 1 || fail_ "./src/bar should return 1" +./libzap_a; test $? = 2 || fail_ "./libfoo_a should return 2" +./src/zap; test $? = 3 || fail_ "./src/prog_libfoo should return 3" +./src/foo-uniq; test $? = 4 || fail_ "./foo_uniq should return 4" +set -e +$MAKE clean |