[tz] [PROPOSED] Make Makefile safer for parallelism

Paul Eggert eggert at cs.ucla.edu
Wed Jun 27 00:57:38 UTC 2018


Although this still does not fully work with GNU Make,
it’s better than what we had.
* Makefile (TIME_T_ALTERNATIVES_HEAD)
(TIME_T_ALTERNATIVES_TAIL): New macros.
(TIME_T_ALTERNATIVES): Use them.
(TZS_CUTOFF_FLAG): New macro.
($(ZDS)): Use it, so that submakes can use -t instead of -c cutoffs.
(EIGHT_YARDS): New macro.
(ENCHILADA): Use it.
(INSTALL_DATA_DEPS, TZS_NEW_DEPS): New macros.
(install_data, posix_only, right_only, posix_packrat, $(TZS_NEW)):
Use them to avoid duplicate work with GNU make -j.
($(TZS_NEW), check_zishrink_posix, check_zishrink_right, check_public)
(check_time_t_alternatives):
Use rule-specific temporary directories so that other rules can
run in parallel.
($(TZS_NEW)): Check for sort failure.
($(TZS)): Simply touch it if it doesn’t exist, so that it’s empty.
(check_tzs): Treat empty $(TZS) as nonexistent.
(check_character_set, check_white_space, check_name_lengths)
(check_sorted, check_links, check_tables, check_tzs, check_web)
(check_zishrink, check_public):
No longer phony.
(check_zishrink_posix, check_zishrink_right)
(typecheck_long_long, typecheck_unsigned):
New rules, so that they can be done in parallel.
(clean_misc): Clean the timestamp files that are now made due
to rules no longer being phony.
(set-timestamps.out): Do not set timestamp of $(TZS).
(set-tzs-timestamp.out): New rule.
(check_time_t_alternatives): Break into subrules, one for each
alternative, so that they can be done in parallel.
(tarballs, rearguard_tarballs, traditional_tarballs)
(signatures, rearguard_signatures, traditional_signatures):
Depend on set-timestamps.out and rearguard.zi.
(tzdb-$(VERSION).tar.lz): Depend on set-tzs-timestamp.out.
(TYPECHECK_CFLAGS): New macro.
---
 Makefile | 240 +++++++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 142 insertions(+), 98 deletions(-)

diff --git a/Makefile b/Makefile
index 2289dff..29058e5 100644
--- a/Makefile
+++ b/Makefile
@@ -106,8 +106,10 @@ MANDIR = $(TOPDIR)/$(USRSHAREDIR)/man
 LIBDIR = $(TOPDIR)/$(USRDIR)/lib
 
 
-# Types to try, as an alternative to time_t.  int64_t should be first.
-TIME_T_ALTERNATIVES = int64_t int32_t uint32_t uint64_t
+# Types to try, as an alternative to time_t.
+TIME_T_ALTERNATIVES = $(TIME_T_ALTERNATIVES_HEAD) $(TIME_T_ALTERNATIVES_TAIL)
+TIME_T_ALTERNATIVES_HEAD = int64_t
+TIME_T_ALTERNATIVES_TAIL = int32_t uint32_t uint64_t
 
 # What kind of TZif data files to generate.
 # (TZif is the binary time zone data format that zic generates.)
@@ -493,11 +495,14 @@ AWK_SCRIPTS=	checklinks.awk checktab.awk leapseconds.awk \
 			ziguard.awk zishrink.awk
 MISC=		$(AWK_SCRIPTS) zoneinfo2tdf.pl
 TZS_YEAR=	2050
+TZS_CUTOFF_FLAG=	-c $(TZS_YEAR)
 TZS=		to$(TZS_YEAR).tzs
 TZS_NEW=	to$(TZS_YEAR)new.tzs
 TZS_DEPS=	$(PRIMARY_YDATA) asctime.c localtime.c \
 			private.h tzfile.h zdump.c zic.c
-ENCHILADA=	$(COMMON) $(DOCS) $(SOURCES) $(DATA) $(MISC) $(TZS) tzdata.zi
+# EIGHT_YARDS is just a yard short of the whole ENCHILADA.
+EIGHT_YARDS = $(COMMON) $(DOCS) $(SOURCES) $(DATA) $(MISC) tzdata.zi
+ENCHILADA = $(EIGHT_YARDS) $(TZS)
 
 # Consult these files when deciding whether to rebuild the 'version' file.
 # This list is not the same as the output of 'git ls-files', since
@@ -606,14 +611,16 @@ INSTALLARGS = \
  YEARISTYPE='$(YEARISTYPE)' \
  ZIC='$(ZIC)'
 
+INSTALL_DATA_DEPS = zic leapseconds yearistype tzdata.zi
+
 # 'make install_data' installs one set of TZif files.
-install_data:	zic leapseconds yearistype tzdata.zi
+install_data: $(INSTALL_DATA_DEPS)
 		$(ZIC_INSTALL) tzdata.zi
 
-posix_only:
+posix_only: $(INSTALL_DATA_DEPS)
 		$(MAKE) $(INSTALLARGS) LEAPSECONDS= install_data
 
-right_only:
+right_only: $(INSTALL_DATA_DEPS)
 		$(MAKE) $(INSTALLARGS) LEAPSECONDS='-L leapseconds' \
 			install_data
 
@@ -640,7 +647,7 @@ posix_right:	posix_only
 
 # This obsolescent rule is present for backwards compatibility with
 # tz releases 2014g through 2015g.  It should go away eventually.
-posix_packrat:
+posix_packrat: $(INSTALL_DATA_DEPS)
 		$(MAKE) $(INSTALLARGS) PACKRATDATA=backzone posix_only
 
 zones:		$(REDO)
@@ -651,29 +658,33 @@ ZDS = dummy.zd
 # Rule used only by submakes invoked by the $(TZS_NEW) rule.
 # It is separate so that GNU 'make -j' can run instances in parallel.
 $(ZDS): zdump
-		./zdump -i -c $(TZS_YEAR) '$(wd)/'$$(expr $@ : '\(.*\).zd') >$@
-
-$(TZS_NEW):	tzdata.zi zdump zic
-		rm -fr tzs.dir
-		mkdir tzs.dir
-		$(zic) -d tzs.dir tzdata.zi
+		./zdump -i $(TZS_CUTOFF_FLAG) '$(wd)/'$$(expr $@ : '\(.*\).zd') \
+		  >$@
+
+TZS_NEW_DEPS = tzdata.zi zdump zic
+$(TZS_NEW): $(TZS_NEW_DEPS)
+		rm -fr tzs$(TZS_YEAR).dir
+		mkdir tzs$(TZS_YEAR).dir
+		$(zic) -d tzs$(TZS_YEAR).dir tzdata.zi
 		$(AWK) '/^L/{print "Link\t" $$2 "\t" $$3}' \
 		   tzdata.zi | LC_ALL=C sort >$@.out
 		wd=`pwd` && \
-		set x `$(AWK) '/^Z/{print "tzs.dir/" $$2 ".zd"}' tzdata.zi \
+		x=`$(AWK) '/^Z/{print "tzs$(TZS_YEAR).dir/" $$2 ".zd"}' \
+				tzdata.zi \
 			| LC_ALL=C sort -t . -k 2,2` && \
+		set x $$x && \
 		shift && \
 		ZDS=$$* && \
-		$(MAKE) wd="$$wd" TZS_YEAR=$(TZS_YEAR) ZDS="$$ZDS" $$ZDS && \
-		sed 's,^TZ=".*tzs\.dir/,TZ=",' $$ZDS >>$@.out
-		rm -fr tzs.dir
+		$(MAKE) wd="$$wd" TZS_CUTOFF_FLAG="$(TZS_CUTOFF_FLAG)" \
+		  ZDS="$$ZDS" $$ZDS && \
+		sed 's,^TZ=".*\.dir/,TZ=",' $$ZDS >>$@.out
+		rm -fr tzs$(TZS_YEAR).dir
 		mv $@.out $@
 
-# If $(TZS) does not already exist (e.g., old-format tarballs), create it.
-# If it exists but 'make check_tzs' fails, a maintainer should inspect the
+# If $(TZS) exists but 'make check_tzs' fails, a maintainer should inspect the
 # failed output and fix the inconsistency, perhaps by running 'make force_tzs'.
 $(TZS):
-		$(MAKE) force_tzs
+		touch $@
 
 force_tzs:	$(TZS_NEW)
 		cp $(TZS_NEW) $(TZS)
@@ -718,12 +729,14 @@ check_character_set: $(ENCHILADA)
 			leapseconds yearistype.sh zone.tab && \
 		! grep -Env $(OK_LINE) $(ENCHILADA); \
 	}
+	touch $@
 
 check_white_space: $(ENCHILADA)
 		patfmt=' \t|[\f\r\v]' && pat=`printf "$$patfmt\\n"` && \
 		! grep -En "$$pat" $(ENCHILADA)
 		! grep -n '[[:space:]]$$' \
 			$$(ls $(ENCHILADA) | grep -Fvx leap-seconds.list)
+		touch $@
 
 PRECEDES_FILE_NAME = ^(Zone|Link[[:space:]]+[^[:space:]]+)[[:space:]]+
 FILE_NAME_COMPONENT_TOO_LONG = \
@@ -732,6 +745,7 @@ FILE_NAME_COMPONENT_TOO_LONG = \
 check_name_lengths: $(TDATA_TO_CHECK) backzone
 		! grep -En '$(FILE_NAME_COMPONENT_TOO_LONG)' \
 			$(TDATA_TO_CHECK) backzone
+		touch $@
 
 CHECK_CC_LIST = { n = split($$1,a,/,/); for (i=2; i<=n; i++) print a[1], a[i]; }
 
@@ -744,52 +758,61 @@ check_sorted: backward backzone iso3166.tab zone.tab zone1970.tab
 		  LC_ALL=C sort -c
 		$(AWK) '/^[^#]/ $(CHECK_CC_LIST)' zone1970.tab | \
 		  LC_ALL=C sort -cu
+		touch $@
 
 check_links:	checklinks.awk $(TDATA_TO_CHECK) tzdata.zi
 		$(AWK) -f checklinks.awk $(TDATA_TO_CHECK)
 		$(AWK) -f checklinks.awk tzdata.zi
+		touch $@
 
 check_tables:	checktab.awk $(PRIMARY_YDATA) $(ZONETABLES)
 		for tab in $(ZONETABLES); do \
 		  $(AWK) -f checktab.awk -v zone_table=$$tab $(PRIMARY_YDATA) \
 		    || exit; \
 		done
+		touch $@
 
 check_tzs:	$(TZS) $(TZS_NEW)
-		diff -u $(TZS) $(TZS_NEW)
+		if test -s $(TZS); then \
+		  diff -u $(TZS) $(TZS_NEW); \
+		else \
+		  cp $(TZS_NEW) $(TZS); \
+		fi
+		touch $@
 
 # This checks only the HTML 4.01 strict page.
 # To check the the other pages, use <https://validator.w3.org/>.
 check_web:	tz-how-to.html
 		$(VALIDATE_ENV) $(VALIDATE) $(VALIDATE_FLAGS) tz-how-to.html
+		touch $@
 
 # Check that zishrink.awk does not alter the data, and that ziguard.awk
 # preserves main-format data.
-check_zishrink: zic leapseconds $(PACKRATDATA) $(TDATA) \
-		  $(DATAFORM).zi tzdata.zi
-		for type in posix right; do \
-		  mkdir -p time_t.dir/$$type time_t.dir/$$type-t \
-		    time_t.dir/$$type-shrunk && \
-		  case $$type in \
-		    right) leap='-L leapseconds';; \
-	            *) leap=;; \
-		  esac && \
-		  $(ZIC) $$leap -d time_t.dir/$$type $(DATAFORM).zi && \
+check_zishrink: check_zishrink_posix check_zishrink_right
+check_zishrink_posix check_zishrink_right: \
+  zic leapseconds $(PACKRATDATA) $(TDATA) $(DATAFORM).zi tzdata.zi
+		rm -fr $@.dir $@-t.dir $@-shrunk.dir
+		mkdir $@.dir $@-t.dir $@-shrunk.dir
+		case $@ in \
+		  *_right) leap='-L leapseconds';; \
+		  *) leap=;; \
+		esac && \
+		  $(ZIC) $$leap -d $@.dir $(DATAFORM).zi && \
+		  $(ZIC) $$leap -d $@-shrunk.dir tzdata.zi && \
 		  case $(DATAFORM) in \
 		    main) \
-		      $(ZIC) $$leap -d time_t.dir/$$type-t $(TDATA) && \
+		      $(ZIC) $$leap -d $@-t.dir $(TDATA) && \
 		      $(AWK) '/^Rule/' $(TDATA) | \
-			$(ZIC) $$leap -d time_t.dir/$$type-t - \
-			  $(PACKRATDATA) && \
-		      diff -r time_t.dir/$$type time_t.dir/$$type-t;; \
-		  esac && \
-		  $(ZIC) $$leap -d time_t.dir/$$type-shrunk tzdata.zi && \
-		  diff -r time_t.dir/$$type time_t.dir/$$type-shrunk || exit; \
-		done
-		rm -fr time_t.dir
+			$(ZIC) $$leap -d $@-t.dir - $(PACKRATDATA) && \
+		      diff -r $@.dir $@-t.dir;; \
+		  esac
+		diff -r $@.dir $@-shrunk.dir
+		rm -fr $@.dir $@-t.dir $@-shrunk.dir
+		touch $@
 
 clean_misc:
-		rm -f core *.o *.out \
+		rm -f *.o *.out $(TIME_T_ALTERNATIVES) \
+		  check_* core typecheck_* \
 		  date tzselect version.h zdump zic yearistype libtz.a
 clean:		clean_misc
 		rm -fr *.dir *.zi tzdb-*/ $(TZS_NEW)
@@ -826,10 +849,10 @@ $(MANTXTS):	workman.sh
 # If git or GNU 'touch' is absent, don't bother to sync with git timestamps.
 # Also, set the timestamp of each prebuilt file like 'leapseconds'
 # to be the maximum of the files it depends on.
-set-timestamps.out: $(ENCHILADA)
+set-timestamps.out: $(EIGHT_YARDS)
 		rm -f $@
 		if (type git) >/dev/null 2>&1 && \
-		   files=`git ls-files $(ENCHILADA)` && \
+		   files=`git ls-files $(EIGHT_YARDS)` && \
 		   touch -md @1 test.out; then \
 		  rm -f test.out && \
 		  for file in $$files; do \
@@ -847,62 +870,74 @@ set-timestamps.out: $(ENCHILADA)
 		    exit; \
 		done
 		touch -cmr `ls -t $(TZDATA_ZI_DEPS) | sed 1q` tzdata.zi
-		touch -cmr `ls -t $(TZS_DEPS) | sed 1q` $(TZS)
 		touch -cmr `ls -t $(VERSION_DEPS) | sed 1q` version
 		touch $@
+set-tzs-timestamp.out: $(TZS)
+		touch -cmr `ls -t $(TZS_DEPS) | sed 1q` $(TZS)
+		touch $@
 
 # The zics below ensure that each data file can stand on its own.
 # We also do an all-files run to catch links to links.
 
-check_public:
-		$(MAKE) maintainer-clean
-		$(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' ALL
-		mkdir -p public.dir
-		for i in $(TDATA_TO_CHECK) tzdata.zi; do \
-		  $(zic) -v -d public.dir $$i 2>&1 || exit; \
+check_public: $(VERSION_DEPS)
+		rm -fr public.dir
+		mkdir public.dir
+		ln $(VERSION_DEPS) public.dir
+		cd public.dir && $(MAKE) CFLAGS='$(GCC_DEBUG_FLAGS)' ALL
+		for i in $(TDATA_TO_CHECK) public.dir/tzdata.zi; do \
+		  public.dir/zic -v -d public.dir/zoneinfo $$i 2>&1 || exit; \
 		done
-		$(zic) -v -d public.dir $(TDATA_TO_CHECK)
+		public.dir/zic -v -d public.dir/zoneinfo-all $(TDATA_TO_CHECK)
 		rm -fr public.dir
+		touch $@
 
 # Check that the code works under various alternative
 # implementations of time_t.
-check_time_t_alternatives:
-		if diff -q Makefile Makefile 2>/dev/null; then \
-		  quiet_option='-q'; \
-		else \
-		  quiet_option=''; \
-		fi && \
+check_time_t_alternatives: $(TIME_T_ALTERNATIVES)
+$(TIME_T_ALTERNATIVES_TAIL): $(TIME_T_ALTERNATIVES_HEAD)
+$(TIME_T_ALTERNATIVES): $(VERSION_DEPS)
+		rm -fr $@.dir
+		mkdir $@.dir
+		ln $(VERSION_DEPS) $@.dir
+		case $@ in \
+		  int32_t) range=-2147483648,2147483648;; \
+		  u*) range=0,4294967296;; \
+		  *) range=-4294967296,4294967296;; \
+		esac && \
 		wd=`pwd` && \
 		zones=`$(AWK) '/^[^#]/ { print $$3 }' <zone1970.tab` && \
-		for type in $(TIME_T_ALTERNATIVES); do \
-		  mkdir -p time_t.dir/$$type && \
-		  $(MAKE) clean_misc && \
-		  $(MAKE) TOPDIR="$$wd/time_t.dir/$$type" \
-		    CFLAGS='$(CFLAGS) -Dtime_tz='"'$$type'" \
+		if test $@ = $(TIME_T_ALTERNATIVES_HEAD); then \
+		  range_target=; \
+		else \
+		  range_target=to$$range.tzs; \
+		fi && \
+		(cd $@.dir && \
+		  $(MAKE) TOPDIR="$$wd/$@.dir" \
+		    CFLAGS='$(CFLAGS) -Dtime_tz='"'$@'" \
 		    REDO='$(REDO)' \
-		    install && \
-		  diff $$quiet_option -r \
-		    time_t.dir/int64_t/etc \
-		    time_t.dir/$$type/etc && \
-		  diff $$quiet_option -r \
-		    time_t.dir/int64_t/usr/share \
-		    time_t.dir/$$type/usr/share && \
-		  case $$type in \
-		  int32_t) range=-2147483648,2147483647;; \
-		  uint32_t) range=0,4294967296;; \
-		  int64_t) continue;; \
-		  *u*) range=0,10000000000;; \
-		  *) range=-10000000000,10000000000;; \
-		  esac && \
-		  echo checking $$type zones ... && \
-		  time_t.dir/int64_t/usr/bin/zdump -V -t $$range $$zones \
-		      >time_t.dir/int64_t.out && \
-		  time_t.dir/$$type/usr/bin/zdump -V -t $$range $$zones \
-		      >time_t.dir/$$type.out && \
-		  diff -u time_t.dir/int64_t.out time_t.dir/$$type.out \
-		    || exit; \
-		done
-		rm -fr time_t.dir
+			D=$$wd/$@.dir \
+		    TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
+		    install $$range_target) && \
+		test $@ = $(TIME_T_ALTERNATIVES_HEAD) || { \
+		  (cd $(TIME_T_ALTERNATIVES_HEAD).dir && \
+		    $(MAKE) TOPDIR="$$wd/$@.dir" \
+		      TZS_YEAR="$$range" TZS_CUTOFF_FLAG="-t $$range" \
+			D=$$wd/$@.dir \
+		      to$$range.tzs) && \
+		  diff -u $(TIME_T_ALTERNATIVES_HEAD).dir/to$$range.tzs \
+			  $@.dir/to$$range.tzs && \
+		  if diff -q Makefile Makefile 2>/dev/null; then \
+		    quiet_option='-q'; \
+		  else \
+		    quiet_option=''; \
+		  fi && \
+		    diff $$quiet_option -r $(TIME_T_ALTERNATIVES_HEAD).dir/etc \
+					   $@.dir/etc && \
+		    diff $$quiet_option -r \
+		      $(TIME_T_ALTERNATIVES_HEAD).dir/usr/share \
+		      $@.dir/usr/share; \
+		}
+		touch $@
 
 TRADITIONAL_ASC = \
   tzcode$(VERSION).tar.gz.asc \
@@ -913,7 +948,8 @@ ALL_ASC = $(TRADITIONAL_ASC) $(REARGUARD_ASC) \
   tzdb-$(VERSION).tar.lz.asc
 
 tarballs rearguard_tarballs traditional_tarballs \
-signatures rearguard_signatures traditional_signatures: version
+signatures rearguard_signatures traditional_signatures: \
+  version set-timestamps.out rearguard.zi
 		VERSION=`cat version` && \
 		$(MAKE) VERSION="$$VERSION" $@_version
 
@@ -963,7 +999,7 @@ tzdata$(VERSION)-rearguard.tar.gz: rearguard.zi set-timestamps.out
 		     gzip $(GZIPFLAGS)) >$@.out
 		mv $@.out $@
 
-tzdb-$(VERSION).tar.lz: set-timestamps.out
+tzdb-$(VERSION).tar.lz: set-timestamps.out set-tzs-timestamp.out
 		rm -fr tzdb-$(VERSION)
 		mkdir tzdb-$(VERSION)
 		ln $(ENCHILADA) tzdb-$(VERSION)
@@ -979,14 +1015,24 @@ tzdb-$(VERSION).tar.lz.asc: tzdb-$(VERSION).tar.lz
 $(ALL_ASC):
 		gpg2 --armor --detach-sign $?
 
-typecheck:
-		$(MAKE) clean
-		for i in "long long" unsigned; \
-		do \
-			$(MAKE) CFLAGS="-DTYPECHECK -D__time_t_defined -D_TIME_T \"-Dtime_t=$$i\"" ; \
-			./zdump -v Europe/Rome ; \
-			$(MAKE) clean ; \
-		done
+TYPECHECK_CFLAGS = $(CFLAGS) -DTYPECHECK -D__time_t_defined -D_TIME_T
+typecheck: typecheck_long_long typecheck_unsigned
+typecheck_long_long typecheck_unsigned: $(VERSION_DEPS)
+		rm -fr $@.dir
+		mkdir $@.dir
+		ln $(VERSION_DEPS) $@.dir
+		cd $@.dir && \
+		  case $@ in \
+		    *_long_long) i="long long";; \
+		    *_unsigned ) i="unsigned" ;; \
+		  esac && \
+		  typecheck_cflags='' && \
+		  $(MAKE) \
+		    CFLAGS="$(TYPECHECK_CFLAGS) \"-Dtime_t=$$i\"" \
+		    TOPDIR="`pwd`" \
+		    install
+		$@.dir/zdump -i -c 1970,1971 Europe/Rome
+		touch $@
 
 zonenames:	tzdata.zi
 		@$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi
@@ -1002,9 +1048,7 @@ zic.o:		private.h tzfile.h version.h
 .KEEP_STATE:
 
 .PHONY: ALL INSTALL all
-.PHONY: check check_character_set check_links check_name_lengths
-.PHONY: check_public check_sorted check_tables
-.PHONY: check_time_t_alternatives check_tzs check_web check_white_space
+.PHONY: check check_time_t_alternatives
 .PHONY: check_zishrink
 .PHONY: clean clean_misc dummy.zd force_tzs
 .PHONY: install install_data maintainer-clean names
-- 
2.7.4



More information about the tz mailing list