Current-Users archive

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

Re: parallel build failure with .c.o rule interrupted mid-step!



Ah ha!

I can reproduce the problem frequently now with the makefile below, both
with the patched make on NetBSD and as nbmake on macOS.

I cannot reproduce any problem, not even left-over intermediate files,
with bmake-20200524nb1 from pkgsrc on macOS.

However the problem does exist with bmake-20200710 and bmake-20240414,
both hand-built on NetBSD.

--
					Greg A. Woods <gwoods%acm.org@localhost>

Kelowna, BC     +1 250 762-7675           RoboHack <woods%robohack.ca@localhost>
Planix, Inc. <woods%planix.com@localhost>     Avoncote Farms <woods%avoncote.ca@localhost>


#
#	tfail.mk:
#
# Demo two-commands-in-one-script failure
#
# Run with (remove the trailing 'exit' unless running it in emacs!):
#
#	rm -rf tfail; mkdir -p tfail; touch tfail/tfail.trace; make MAKEOBJDIR=tfail -T tfail.trace -f tfail.mk -j 20; rc=$?; sleep 2; ls -l tfail/*.int
#
# or:
#
#	rm -rf tfail; mkdir -p tfail; cd tfail; touch tfail.trace; make -T tfail.trace -f ../tfail.mk -j 20; rc=$?; sleep 2; ls -l *.int
#
# or:
#
#	rm -rf tfail; mkdir -p tfail; touch tfail/tfail.trace; make MAKEOBJDIR=tfail -T tfail.trace -f tfail.mk -j 20; rc=$?; sleep 2; ls -l tfail/*.int; for file in tfail/*.int; do if [ -f $file ]; then ls -l $(basename $file .int); fi; done
#
# When it fails, if it behaves the same as I see in a NetBSD build, then there
# will be one or more .int files, and for each there might also be an empty
# associated .obj file too.
#
# A left-over .int file means the script ended early, and that shouldn't happen
# -- all scripts should run to completion.
#
# An empty .obj file means something interrupted the script and that causes
# errors as it is an incorrectly built, incomplete, product file.
#

# prevent Ksh or NetBSD sh from running any user-controlled setup
#
# This should speed up builds where $ENV is accidentally set to a valid
# pathname.  Even in running this test it appears to shave off about 1/3 of a
# second of user CPU time, and maybe as much as half the system CPU time.  (In
# my own setup with a login shell of Ksh, it is set to a variable expansion that
# fails, but this should still speed up builds by avoiding having to try to
# parse and expand it.)
#
# Note by default on NetBSD the default shell used by make is /bin/sh and by
# default it is passed the options "-q" (which show up in "$-" as "eLqs") as the
# .echoFlag is set to this undocumented 'q' option (which, FYI, /bin/ksh doesn't
# have).  This has the effect of hiding what is being read from $ENV, if
# anything.
#
ENV = 		# empty
.export ENV

# This should, and appears to, mimic how the "DEFSHELL" is set up now for use in
# NetBSD:
#
#.SHELL: name=sh path=/bin/sh hasErrCtl=false \
#	newline="\n" \
#	check="echo \"%s\"\n" \
#	ignore="%s\n" \
#	errout="{ %s \n} || exit $?\n" \
#	echoFlag=q
#	comment="\#"

# This sets up NetBSD sh to be used like a modern shell:
#
# Note the echoFlag=qv!  Without the 'v' it doesn't have the desired effect, yet
# it still doesn't show up in the executed shell's "$-"!
#
# This is slightly more efficient than the default old Bourne sh setup.
#
#.SHELL: name=sh path=/bin/sh hasErrCtl=true \
#	check="set -e" ignore="set +e" \
#	echo="set -v" quiet="set +v" filter="set +v" \
#	echoFlag=qv errFlag=e newline="'\n'" \
#	comment="\#"

# This should set up ksh to be used in the same antiquated way /bin/sh is set up
# to work as the "DEFSHELL" in NetBSD make, i.e. without Echo or Error control
# (as in the original KSH setup in Make, sans using "print" instead of "echo")
#
#.SHELL: name=ksh path=/bin/ksh hasErrCtl=false \
#	newline="\n" \
#	check="print \"%s\"\n" \
#	ignore="%s\n" \
#	errout="{ %s \n} || exit $?\n" \
#	comment="\#"

# This sets up ksh to be used like a modern shell
#
#.SHELL: name=ksh path=/bin/ksh hasErrCtl=true \
#	check="set -e" ignore="set +e" \
#	echo="set -v" quiet="set +v" filter="set +v" \
#	echoFlag=v errFlag=e newline="'\n'" \
#	comment="\#"

# This sets up ksh to be used like a modern shell with tracing support
#
#.SHELL: name=sh path=/bin/ksh hasErrCtl=true \
#	check="set -e" ignore="set +e" \
#	echo="set -v" quiet="set +v" filter="set +v" \
#	echoFlag=v errFlag=e newline="'\n'" \
#	comment="\#"

#.SHELL: name=sh path=/bin/dash hasErrCtl=true \
#	check="set -e" ignore="set +e" \
#	echo="set -v" quiet="set +v" filter="set +v" \
#	echoFlag=v errFlag=e newline="'\n'" \
#	comment="\#"

#.SHELL: name=ksh path=/usr/pkg/bin/dash

# Clear th list first just to eliminate any possible side-effects from
# <sys.mk>...
#
.SUFFIXES:

.SUFFIXES: .src .obj

OBJECT_TARGET	= ${.TARGET}.int

# N.B.:  In this form it is common for ${OBJECT_TARGET} to remain, and sometimes
# for the corresponding ${.TARGET} to also be the, but complete.
#
#.src.obj:
## pretend one compile has a syntax error
#	if [ ${.TARGET} = "src-3-9.obj" ]; then  exit 1; fi
## simulate compilation
#	touch ${OBJECT_TARGET} && sleep 0.1 && cat ${.IMPSRC} >> ${OBJECT_TARGET}
## simulate ctfconvert
#	touch ${.TARGET} && sleep 0.2 && cat ${OBJECT_TARGET} >> ${.TARGET} && rm -f ${OBJECT_TARGET}

# This form often reproduces the problem
#
.src.obj:
# pretend one compile has a syntax error
	if [ ${.TARGET} = "src-3-9.obj" ]; then  exit 1; fi
# simulate compilation
	touch ${OBJECT_TARGET}
	sleep 0.1
	cat ${.IMPSRC} >> ${OBJECT_TARGET}
# simulate ctfconvert
	touch ${.TARGET}
	sleep 0.2
	cat ${OBJECT_TARGET} >> ${.TARGET} && rm -f ${OBJECT_TARGET}


PROD_ITERS ?= 20
SRC_ITERS ?= 20

all: .PHONY info .WAIT

info: .PHONY
	@printf ".SHELL = '${.SHELL}'\n"
	@printf "ENV = '${ENV}'($${ENV})\n"
	@printf "shell params = $${#}:'$${-}'\n"

# magic range expansions from Roland Illig
#
.for _i in ${:U:${:Urange=${PROD_ITERS}}}

all: dir-${_i}

.for _j in ${:U:${:Urange=${SRC_ITERS}}}

SRCS.${_i} += src-${_i}-${_j}.src
OBJS.${_i} += src-${_i}-${_j}.obj

src-${_i}-${_j}.src:
	echo ${.TARGET} > ${.TARGET}
.endfor

#
# pretend each "foo-*" is built in a separate subdirectory so that they can be
# built in parallel
#
dir-${_i}: .PHONY srcs-${_i}
	${MAKE} -f ${MAKEFILE} foo-${_i}

foo-${_i}: ${OBJS.${_i}}
	cat ${OBJS.${_i}} > ${.TARGET} || rm -f ${.TARGET}

# make each set of sources separately just to be sure they exist before the
# "dir-N" is built...
#
srcs-${_i}: .PHONY
	${MAKE} -f ${MAKEFILE} do-srcs-${_i}

do-srcs-${_i}: .PHONY ${SRCS.${_i}}

.endfor


#
# Local Variables:
# eval: (make-local-variable 'compile-command)
# compile-command: (concat "rm -rf tfail; mkdir -p tfail; touch tfail/tfail.trace; ENV=$HOME/.shrc time make MAKEOBJDIR=tfail -T tfail.trace -f tfail.mk -j 20; rc=$?; sleep 2; ls -l tfail/*.int; for file in tfail/*.int; do if [ -f $file ]; then ls -l $(basename $file .int); fi; done; exit $rc")
# End:
#

Attachment: pgpZM4gR1BwZu.pgp
Description: OpenPGP Digital Signature



Home | Main Index | Thread Index | Old Index