xref: /src/contrib/bmake/mk/jobs.mk (revision b4c3e9b5b09c829b4135aff738bd2893ed052377)
1# $Id: jobs.mk,v 1.20 2025/08/09 22:42:24 sjg Exp $
2#
3#	@(#) Copyright (c) 2012-2025, Simon J. Gerraty
4#
5#	SPDX-License-Identifier: BSD-2-Clause
6#
7#	Please send copies of changes and bug-fixes to:
8#	sjg@crufty.net
9#
10
11# This makefile is used by top-level makefile.
12# With the following:
13#
14#	.if make(*-jobs)
15#	.include <jobs.mk>
16#	.endif
17#
18#
19# Then if you do:
20#
21#	mk target-jobs
22#
23# We will run:
24#
25#	${MAKE} -j${JOB_MAX} target > ${JOB_LOGDIR}/target.log 2>&1
26#
27# JOB_MAX should be something like 1.2 - 1.5 times the number of
28# available CPUs.
29# If bmake sets .MAKE.JOBS.C=yes we can use -jC and
30# JOB_MAX defaults to JOB_MAX_C (default 1.33C).
31# Otherwise we use 8.
32#
33
34now_utc ?= ${%s:L:localtime}
35.if !defined(start_utc)
36start_utc := ${now_utc}
37.endif
38
39.if make(*-jobs)
40.info ${.newline}${TIME_STAMP} Start ${.TARGETS}
41
42JOB_LOGDIR ?= ${SRCTOP:H}
43JOB_LOG = ${JOB_LOGDIR}/${.TARGET:S,-jobs,,:S,/,_,g}.log
44JOB_LOG_GENS ?= 4
45# we like to rotate logs
46.if empty(NEWLOG_SH)
47.for d in ${.SYSPATH:U${.PARSEDIR}:@x@$x $x/scripts@}
48.if exists($d/newlog.sh)
49NEWLOG_SH := $d/newlog.sh
50.if ${MAKE_VERSION} > 20220924
51.break
52.endif
53.endif
54.endfor
55.if empty(NEWLOG_SH)
56.ifdef M_whence
57NEWLOG_SH := ${newlog.sh:L:${M_whence}}
58.else
59NEWLOG_SH := ${(type newlog.sh) 2> /dev/null:L:sh:M/*}
60.endif
61.endif
62.endif
63.if !empty(NEWLOG_SH) && exists(${NEWLOG_SH})
64NEWLOG := ${.SHELL:Ush} ${NEWLOG_SH}
65JOB_NEWLOG_ARGS ?= -S -n ${JOB_LOG_GENS}
66.else
67NEWLOG = :
68.endif
69
70.if ${.MAKE.JOBS:U0} > 0
71JOB_MAX = ${.MAKE.JOBS}
72.else
73# This should be derrived from number of cpu's
74.if ${.MAKE.JOBS.C:Uno} == "yes"
75# 1.2 - 1.5 times nCPU works well on most machines that support -jC
76# if the factor is floating point, the C suffix isn't needed
77JOB_MAX_C ?= 1.33
78JOB_MAX ?= ${JOB_MAX_C}
79.endif
80JOB_MAX ?= 8
81JOB_ARGS += -j${JOB_MAX}
82.endif
83
84# we need to reset .MAKE.LEVEL to 0 so that
85# build orchestration works as expected (DIRDEPS_BUILD)
86${.TARGETS:M*-jobs}:
87	@${NEWLOG} ${JOB_NEWLOG_ARGS} ${JOB_LOG}
88	@echo "${TIME_STAMP} Start ${.TARGET:S,-jobs,,} ${JOB_ARGS} ${JOB_LOG_START} log=${JOB_LOG}" | tee ${JOB_LOG}
89	@cd ${.CURDIR} && env MAKELEVEL=0 \
90	${.MAKE} ${JOB_ARGS} _TARGETS=${.TARGET:S,-jobs,,} ${.TARGET:S,-jobs,,} >> ${JOB_LOG} 2>&1
91
92.endif
93
94.END: _build_finish
95.ERROR: _build_failed
96
97_build_finish:  .NOMETA
98	@echo "${TIME_STAMP} Finished ${.TARGETS} seconds=`expr ${now_utc} - ${start_utc}`"
99
100_build_failed: .NOMETA
101	@echo "${TIME_STAMP} Failed ${.TARGETS} seconds=`expr ${now_utc} - ${start_utc}`"
102