1#! /bin/sh
2# Copyright (C) 2012-2021 Free Software Foundation, Inc.
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2, or (at your option)
7# any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17# Check dependency tracking in various flavours.
18# Contains both libtool and non-libtool case.
19# Sourced by the various (autogenerated) 'depcomp*.tap' tests.
20# Examples of reported failures that motivated those test are
21# listed below.
22
23# -------------------------------------------------------------------------
24
25# <https://lists.gnu.org/archive/html/automake-patches/2011-04/msg00028.html>
26#
27# Here's the bug: makedepend will prefix VPATH to the object file name,
28# thus the second make will invoke depcomp with object='../../src/foo.o',
29# causing errors such as:
30#
31#  touch: cannot touch '../../src/.deps/foo.TPo': No such file or directory
32#  makedepend: error:  cannot open "../../src/.deps/foo.TPo"
33#  ../../depcomp: line 560: ../../src/.deps/foo.TPo: No such file or directory
34
35# -------------------------------------------------------------------------
36
37# <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=8473>
38# <https://lists.gnu.org/archive/html/automake-patches/2011-04/msg00079.html>
39#
40# Here's the bug: hp depmode will prefix VPATH to the object file name,
41# thus the second gmake will invoke depcomp with object='../../src/foo.o',
42# causing errors such as (broken on multiple lines for clarity):
43#
44#   cpp: "", line 0: error 4066: Cannot create
45#        "../../gllib/.deps/nonblocking.TPo" file for
46#        "-M../../gllib/.deps/nonblocking.TPo" option.
47#        (No such file or directory[errno=2])
48#
49
50# -------------------------------------------------------------------------
51
52# <https://lists.gnu.org/archive/html/automake-patches/2011-04/msg00140.html>
53# <https://lists.gnu.org/archive/html/automake-patches/2011-05/msg00019.html>
54#
55# A partial failure of an earlier version of this test; some bad
56# post-processing of the '*.Po' files led to the following broken
57# contents of 'src/sub/.deps/subfoo.Po':
58#
59#  > sub/subfoo.o: ../../depmod-data.dir/src/sub/subfoo.c \
60#  >   ../../depmod-data.dir/src/foo.h
61#  > ../../depmod-data.dir/src/sub/subfoo.c \:
62#  >   ../../depmod-data.dir/src/foo.h:
63#
64# which caused make to die with an error like:
65#
66#  "sub/.deps/subfoo.Po:3: *** missing separator.  Stop."
67
68# -------------------------------------------------------------------------
69
70# This code expects test-init.sh has already been included in advance.
71
72ocwd=$(pwd) || fatal_ "getting current working directory"
73longpath=this-is/a-path/which-has/quite-a/definitely/truly/long_long_name
74cachevar=am_cv_CC_dependencies_compiler_type
75
76srctree=depmod-1.0
77mkdir $srctree
78cd $srctree
79
80cd_top ()
81{
82  cd "$ocwd" || fatal_ "cannot chdir back to top directory"
83}
84
85delete ()
86{
87  test -f "$1" || fatal_ "$1: file does not exist"
88  rm -f "$1" || fatal_ "$1: couldn't remove"
89}
90
91edit ()
92{
93  file=$1; shift
94  sed "$@" <"$file" > t && mv -f t "$file" \
95    || fatal_ "$file: editing of file failed"
96}
97
98rewrite ()
99{
100  file=$1; shift
101  "$@" > "$file" || fatal_ "$file: couldn't rewrite"
102}
103
104setup_srcdir ()
105{
106  srcdir=$1 # This is intended to be global.
107  mkdir -p "$srcdir" \
108    || fatal_ "couldn't create source directory '$srcdir'"
109  cp -pR "$ocwd/$srctree"/* "$srcdir"/ \
110    || fatal_ "couldn't populate source directory '$srcdir'"
111}
112
113
114check_no_depfiles ()
115{
116  find . -name '*.Plo' -o -name '*.Po' | grep . && return 1
117  return 0
118}
119
120check_distclean ()
121{
122  # "make distcleancheck" can only run from a VPATH build.
123  if test $vpath = no; then
124    make_ok distclean && check_no_depfiles
125  else
126    $MAKE distcleancheck
127  fi
128}
129
130cat > configure.ac <<END
131AC_INIT([$me], [1.0])
132AC_CONFIG_AUX_DIR([build-aux])
133AM_INIT_AUTOMAKE([subdir-objects])
134AC_PROG_CC
135AM_PROG_AR
136$(if test $depcomp_with_libtool = yes; then
137    echo AC_PROG_LIBTOOL
138  else
139    echo AC_PROG_RANLIB
140  fi)
141AC_CONFIG_FILES([Makefile src/Makefile])
142AC_OUTPUT
143END
144
145mkdir build-aux sub src src/sub2
146
147case $depcomp_with_libtool in
148  yes)
149    po=Plo objext=lo a=la
150    normalized_target=libfoo_la
151    # On platforms requiring that no undefined symbols exist in order
152    # to build shared libraries (e.g. Windows DLLs), you have to
153    # explicitly declare that the libtool library you are building
154    # does not actually have any undefined symbols, for libtool to
155    # even try to build it as a shared library.  Without that
156    # explicit declaration, libtool falls back to a static library
157    # only, regardless of any --enable-shared flags etc.
158    LIBPRIMARY=LTLIBRARIES LINKADD=LIBADD NOUNDEF=-no-undefined
159    libbaz_ldflags="libbaz_${a}_LDFLAGS = $NOUNDEF"
160    echo lib_LTLIBRARIES = libfoo.la >> Makefile.am
161    make_ok ()
162    {
163      run_make -M -- ${1+"$@"}
164      $FGREP 'unknown directive' output && return 1
165      rm -f output
166      # Checks for stray files possibly left around by less common
167      # depmodes.
168      find . -name '*.[ud]' | grep . && return 1
169      return 0
170    }
171    ;;
172  no)
173    po=Po objext='$(OBJEXT)' a=a
174    normalized_target=foo
175    LIBPRIMARY=LIBRARIES LINKADD=LDADD NOUNDEF=
176    libbaz_ldflags=
177    echo bin_PROGRAMS = foo >> Makefile.am
178    make_ok ()
179    {
180      $MAKE ${1+"$@"}
181    }
182    ;;
183  *)
184    fatal_ "invalid value '$depcomp_with_libtool' for variable" \
185           "\$depcomp_with_libtool"
186    ;;
187esac
188
189cat >> Makefile.am <<END
190SUBDIRS = src
191# We include subfoo only to be sure that the munging in depcomp
192# doesn't remove too much from the object file name.
193${normalized_target}_SOURCES = foo.c sub/subfoo.c foo.h sub/subfoo.h
194${normalized_target}_LDFLAGS = $NOUNDEF
195${normalized_target}_${LINKADD} = src/libbaz.$a
196
197.PHONY: grep-test
198grep-test:
199## For debugging.
200	cat \$(DEPDIR)/foo.$po || :
201	cat sub/\$(DEPDIR)/subfoo.$po || :
202	cat src/\$(DEPDIR)/baz.$po || :
203	cat src/sub2/\$(DEPDIR)/sub2foo.$po || :
204## Checks are done here.
205	grep '^foo.$objext.*:' \$(DEPDIR)/foo.$po
206	grep '^sub/subfoo\.$objext.*:' sub/\$(DEPDIR)/subfoo.$po
207	grep '^baz\.$objext.*:' src/\$(DEPDIR)/baz.$po
208	grep '^sub2/sub2foo\.$objext.*:' src/sub2/\$(DEPDIR)/sub2foo.$po
209END
210
211cat > src/Makefile.am <<END
212noinst_${LIBPRIMARY} = libbaz.$a
213# We include sub2foo only to be sure that the munging in depcomp
214# doesn't remove too much from the object file name.
215libbaz_${a}_SOURCES = baz.c sub2/sub2foo.c baz.h sub2/sub2foo.h
216$libbaz_ldflags
217END
218
219cat > foo.c <<'END'
220#include "foo.h"
221#include "src/baz.h"
222#include <stdlib.h>
223int main (void)
224{
225  printf ("foo bar\n");
226  exit (EXIT_SUCCESS + subfoo () + baz ());
227}
228END
229
230cat > foo.h <<'END'
231#include <stdio.h>
232#include "sub/subfoo.h"
233END
234
235cat > sub/subfoo.c <<'END'
236#include "sub/subfoo.h"
237int subfoo (void) { return 0; }
238END
239
240echo '/* empty */' > src/sub2/sub2foo.h
241
242cat > sub/subfoo.h <<'END'
243#include <stdio.h>
244extern int subfoo (void);
245END
246
247cat > src/baz.c <<'END'
248#include "baz.h"
249int baz (void) { return 0; }
250END
251
252cat > src/baz.h <<'END'
253extern int baz (void);
254END
255
256cat > src/sub2/sub2foo.c <<'END'
257#include "sub2foo.h"
258int sub2foo (void) { return 0; }
259END
260
261test $depcomp_with_libtool = no || libtoolize \
262  || fatal_ "libtoolize failed"
263$ACLOCAL && $AUTOCONF && $AUTOMAKE -a \
264  || fatal_ "autotools failed"
265test -f build-aux/depcomp \
266  || fatal_ "depcomp script not installed"
267
268# To offer extra coverage for the depmodes (like "aix" of "hp2") where the
269# name of the compiler-generated depfiles can depend on whether libtool is
270# in use *and* on which kind of libraries libtool is building (static,
271# shared, or both), we would like to run the libtool-oriented tests thrice:
272# once after having run configure with the '--disable-shared' option, once
273# after having run it with the '--enable-shared' options, and once by
274# leaving it to configure to automatically select which kind of library (or
275# libraries) to build.
276#
277# But doing such three-fold checks unconditionally for all the depmodes
278# would slow down the already too slow libtool tests unacceptably (up to a
279# 150-200% factor), with no real gain in coverage for most of the depmodes.
280# So, since the depmodes that would benefit from the extra tests are never
281# forced to configure in out tests below, but can only be automatically
282# selected by '--enable-dependency-tracking', we make this threefold check
283# only in this later case.
284
285if test $depmode,$depcomp_with_libtool = auto,yes; then
286  do_all_tests ()
287  {
288    do_test default
289    do_test noshared --disable-shared
290    do_test nostatic --disable-static
291  }
292else
293  do_all_tests () { do_test; }
294fi
295
296case $depmode in
297  auto)
298    displayed_depmode='..*' # At least one character long.
299    cfg_deptrack=--enable-dependency-tracking ;;
300  disabled)
301    displayed_depmode=none
302    cfg_deptrack=--disable-dependency-tracking ;;
303  *)
304    displayed_depmode="(cached) $depmode"
305    cfg_deptrack="$cachevar=$depmode"
306    # Sanity check: ensure the cache variable we force is truly
307    # used by configure.
308    $FGREP $cachevar configure \
309      || fatal_ "configure lacks required cache variable '$cachevar'";;
310esac
311
312cd_top
313
314do_test ()
315{
316  cd_top
317  if test $vpath = no; then
318    pfx="in-tree build"
319  else
320    pfx="$vpath VPATH"
321  fi
322  if test $# -gt 0; then
323    subdir=$1; shift
324    pfx="$pfx, $subdir"
325    test -d $subdir || mkdir $subdir || fatal_ "creating directory $subdir"
326    cd $subdir
327  fi
328  pfx="[$pfx]"
329  case $vpath in
330    simple)
331      mkdir -p vpath-simple/build
332      cd vpath-simple/build
333      setup_srcdir ..
334      ;;
335    long)
336      mkdir -p vpath-long/src vpath-long/wrk
337      cd vpath-long/wrk
338      setup_srcdir ../src/$longpath
339      ;;
340    absolute)
341      mkdir -p vpath-abs/build
342      cd vpath-abs/build
343      absdir=$(cd .. && pwd) || fatal_ "getting absolute directory"
344      setup_srcdir "$absdir/vpath-abs"
345      unset absdir
346      ;;
347    no)
348      mkdir intree
349      cd intree
350      setup_srcdir .
351      ;;
352    *)
353      fatal_ "invalid value '$vpath' for variable \$vpath"
354      ;;
355  esac
356
357  command_ok_ \
358    "$pfx configure" \
359    "$srcdir/configure" $cfg_deptrack ${1+"$@"} >stdout
360  cat stdout
361
362  command_ok_ \
363    "$pfx right depmode selected" \
364    grep "^checking dependency style .*\.\.\. $displayed_depmode$" stdout
365  rm -f stdout
366
367  command_ok_ "$pfx simple make" make_ok
368  # Some bugs in VPATH builds only kick in during a rebuild.
369  command_ok_ "$pfx clean & rebuild" eval '$MAKE clean && make_ok'
370
371  if test $depmode = disabled; then
372      command_ok_ "$pfx no dependency files generated" check_no_depfiles
373      r=ok \
374        && grep "[ $tab]depmode=none" Makefile \
375        && rewrite "$srcdir"/src/sub2/sub2foo.h echo 'choke me' \
376        && delete "$srcdir"/sub/subfoo.h \
377        && make_ok \
378        || r='not ok'
379      result_ "$r" "$pfx dependency tracking is truly disabled"
380  elif grep "[ $tab]depmode=none" Makefile; then
381    skip_row_ 2 -r "automatic dependency tracking couldn't be activated"
382  else
383    command_ok_ "$pfx generated $po files look correct" $MAKE grep-test
384    r=ok \
385      && : "Some checks in the subdir." \
386      && $sleep \
387      && : "Ensure rebuild rules really kick in." \
388      && rewrite "$srcdir"/src/sub2/sub2foo.h echo 'choke me' \
389      && cd src \
390      && not $MAKE  \
391      && cd .. \
392      && : "Ensure the deleted header bug is fixed." \
393      && delete "$srcdir"/src/sub2/sub2foo.h \
394      && edit "$srcdir"/src/sub2/sub2foo.c -e 1d \
395      && cd src \
396      && make_ok \
397      && : "Now do similar checks for the parent directory." \
398      && cd .. \
399      && rewrite "$srcdir"/sub/subfoo.h echo 'choke me' \
400      && not $MAKE \
401      && delete "$srcdir"/sub/subfoo.h \
402      && edit "$srcdir"/sub/subfoo.c -e 1d \
403      && edit "$srcdir"/foo.h -e 2d \
404      && make_ok \
405      || r='not ok'
406    result_ "$r" "$pfx dependency tracking works"
407  fi
408
409  command_ok_ "$pfx make distclean" check_distclean
410  cd_top
411}
412
413for vpath in no simple long absolute; do
414  do_all_tests
415done
416
417:
418