1 #
2 # Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
3 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 #
5 # This code is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License version 2 only, as
7 # published by the Free Software Foundation. Oracle designates this
8 # particular file as subject to the "Classpath" exception as provided
9 # by Oracle in the LICENSE file that accompanied this code.
10 #
11 # This code is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 # version 2 for more details (a copy is included in the LICENSE file that
15 # accompanied this code).
16 #
17 # You should have received a copy of the GNU General Public License version
18 # 2 along with this work; if not, write to the Free Software Foundation,
19 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 #
21 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 # or visit www.oracle.com if you need additional information or have any
23 # questions.
24 #
25
26 include MakeIncludeStart.gmk
27 ifeq ($(INCLUDE), true)
28
29 ################################################################################
30 # This file contains helper functions for Init.gmk.
31 ################################################################################
32
33 # Define basic logging setup
34 BUILD_LOG := $(OUTPUTDIR)/build.log
35 BUILD_PROFILE_LOG := $(OUTPUTDIR)/build-profile.log
36
37 BUILD_LOG_PIPE := > >($(TEE) -a $(BUILD_LOG)) 2> >($(TEE) -a $(BUILD_LOG) >&2) && wait
38 # Use this for simple echo/printf commands that are never expected to print
39 # to stderr.
40 BUILD_LOG_PIPE_SIMPLE := | $(TEE) -a $(BUILD_LOG)
41
42 # Setup the build environment to match the requested specification on
43 # level of reproducible builds
44 define SetupReproducibleBuild
45 ifeq ($$(SOURCE_DATE), updated)
46 # For static values of SOURCE_DATE (not "updated"), these are set in spec.gmk
47 export SOURCE_DATE_EPOCH := $$(shell $$(DATE) +"%s")
48 export SOURCE_DATE_ISO_8601 := $$(call EpochToISO8601, $$(SOURCE_DATE_EPOCH))
49 endif
50 endef
51
52 # Parse COMPARE_BUILD into COMPARE_BUILD_*
53 # Syntax: COMPARE_BUILD=CONF=<configure options>:PATCH=<patch file>:
54 # MAKE=<make targets>:COMP_OPTS=<compare script options>:
55 # COMP_DIR=<compare script base dir>|<default>:
56 # FAIL=<bool>
57 # If neither CONF or PATCH is given, assume <default> means CONF if it
58 # begins with "--", otherwise assume it means PATCH.
59 # MAKE and COMP_OPTS can only be used with CONF and/or PATCH specified.
60 # If any value contains "+", it will be replaced by space.
61 # FAIL can be set to false to have the return value of compare be ignored.
62 define ParseCompareBuild
63 ifneq ($$(COMPARE_BUILD), )
64 COMPARE_BUILD_OUTPUTDIR := $(WORKSPACE_ROOT)/build/compare-build/$(CONF_NAME)
65 COMPARE_BUILD_FAIL := true
66
67 ifneq ($$(findstring :, $$(COMPARE_BUILD)), )
68 $$(foreach part, $$(subst :, , $$(COMPARE_BUILD)), \
69 $$(if $$(filter PATCH=%, $$(part)), \
70 $$(eval COMPARE_BUILD_PATCH = $$(strip $$(patsubst PATCH=%, %, $$(part)))) \
71 ) \
72 $$(if $$(filter CONF=%, $$(part)), \
73 $$(eval COMPARE_BUILD_CONF = $$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(part))))) \
74 ) \
75 $$(if $$(filter MAKE=%, $$(part)), \
76 $$(eval COMPARE_BUILD_MAKE = $$(strip $$(subst +, , $$(patsubst MAKE=%, %, $$(part))))) \
77 ) \
78 $$(if $$(filter COMP_OPTS=%, $$(part)), \
79 $$(eval COMPARE_BUILD_COMP_OPTS = $$(strip $$(subst +, , $$(patsubst COMP_OPTS=%, %, $$(part))))) \
80 ) \
81 $$(if $$(filter COMP_DIR=%, $$(part)), \
82 $$(eval COMPARE_BUILD_COMP_DIR = $$(strip $$(subst +, , $$(patsubst COMP_DIR=%, %, $$(part))))) \
83 ) \
84 $$(if $$(filter FAIL=%, $$(part)), \
85 $$(eval COMPARE_BUILD_FAIL = $$(strip $$(subst +, , $$(patsubst FAIL=%, %, $$(part))))) \
86 ) \
87 $$(if $$(filter NODRYRUN=%, $$(part)), \
88 $$(eval COMPARE_BUILD_NODRYRUN = $$(strip $$(subst +, , $$(patsubst NODRYRUN=%, %, $$(part))))) \
89 ) \
90 )
91 else
92 # Separate handling for single field case, to allow for spaces in values.
93 ifneq ($$(filter PATCH=%, $$(COMPARE_BUILD)), )
94 COMPARE_BUILD_PATCH = $$(strip $$(patsubst PATCH=%, %, $$(COMPARE_BUILD)))
95 else ifneq ($$(filter CONF=%, $$(COMPARE_BUILD)), )
96 COMPARE_BUILD_CONF = $$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(COMPARE_BUILD))))
97 else ifneq ($$(filter --%, $$(COMPARE_BUILD)), )
98 # Assume CONF if value begins with --
99 COMPARE_BUILD_CONF = $$(strip $$(subst +, , $$(COMPARE_BUILD)))
100 else
101 # Otherwise assume patch file
102 COMPARE_BUILD_PATCH = $$(strip $$(COMPARE_BUILD))
103 endif
104 endif
105 ifneq ($$(COMPARE_BUILD_PATCH), )
106 ifneq ($$(wildcard $$(WORKSPACE_ROOT)/$$(COMPARE_BUILD_PATCH)), )
107 # Assume relative path, if file exists
108 COMPARE_BUILD_PATCH := $$(wildcard $$(WORKSPACE_ROOT)/$$(COMPARE_BUILD_PATCH))
109 else ifeq ($$(wildcard $$(COMPARE_BUILD_PATCH)), )
110 $$(error Patch file $$(COMPARE_BUILD_PATCH) does not exist)
111 endif
112 ifneq ($$(COMPARE_BUILD_NODRYRUN), true)
113 PATCH_DRY_RUN := $$(shell cd $$(WORKSPACE_ROOT) && $$(PATCH) --dry-run -p1 < $$(COMPARE_BUILD_PATCH) > /dev/null 2>&1 || $$(ECHO) FAILED)
114 ifeq ($$(PATCH_DRY_RUN), FAILED)
115 $$(error Patch file $$(COMPARE_BUILD_PATCH) does not apply cleanly)
116 endif
117 endif
118 endif
119 ifneq ($$(COMPARE_BUILD_FAIL), true)
120 COMPARE_BUILD_IGNORE_RESULT := || true
121 endif
122 endif
123 endef
124
125 # Prepare for a comparison rebuild
126 define PrepareCompareBuild
127 $(ECHO) "Preparing for comparison rebuild"
128 # Apply patch, if any
129 $(if $(COMPARE_BUILD_PATCH), cd $(WORKSPACE_ROOT) && $(PATCH) -p1 < $(COMPARE_BUILD_PATCH))
130 # Move the first build away temporarily
131 $(RM) -r $(WORKSPACE_ROOT)/build/.compare-build-temp
132 $(MKDIR) -p $(WORKSPACE_ROOT)/build/.compare-build-temp
133 $(MV) $(OUTPUTDIR) $(WORKSPACE_ROOT)/build/.compare-build-temp
134 # Restore an old compare-build, or create a new compare-build directory.
135 if test -d $(COMPARE_BUILD_OUTPUTDIR); then \
136 $(MV) $(COMPARE_BUILD_OUTPUTDIR) $(OUTPUTDIR); \
137 else \
138 $(MKDIR) -p $(OUTPUTDIR); \
139 fi
140 # Re-run configure with the same arguments (and possibly some additional),
141 # must be done after patching.
142 ( cd $(CONFIGURE_START_DIR) && PATH="$(ORIGINAL_PATH)" \
143 $(BASH) $(WORKSPACE_ROOT)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
144 endef
145
146 # Cleanup after a compare build
147 define CleanupCompareBuild
148 # If running with a COMPARE_BUILD patch, reverse-apply it, but continue
149 # even if that fails (can happen with removed files).
150 $(if $(COMPARE_BUILD_PATCH), cd $(WORKSPACE_ROOT) && $(PATCH) -R -p1 < $(COMPARE_BUILD_PATCH) || true)
151 # Move this build away and restore the original build
152 $(MKDIR) -p $(WORKSPACE_ROOT)/build/compare-build
153 $(MV) $(OUTPUTDIR) $(COMPARE_BUILD_OUTPUTDIR)
154 $(MV) $(WORKSPACE_ROOT)/build/.compare-build-temp/$(CONF_NAME) $(OUTPUTDIR)
155 $(RM) -r $(WORKSPACE_ROOT)/build/.compare-build-temp
156 endef
157
158 # Do the actual comparison of two builds
159 define CompareBuildDoComparison
160 # Compare first and second build. Ignore any error code from compare.sh.
161 $(ECHO) "Comparing between comparison rebuild (this/new) and baseline (other/old)"
162 $(if $(COMPARE_BUILD_COMP_DIR), \
163 +(cd $(COMPARE_BUILD_OUTPUTDIR) && ./compare.sh --diffs $(COMPARE_BUILD_COMP_OPTS) \
164 -2dirs $(COMPARE_BUILD_OUTPUTDIR)/$(COMPARE_BUILD_COMP_DIR) \
165 $(OUTPUTDIR)/$(COMPARE_BUILD_COMP_DIR) $(COMPARE_BUILD_IGNORE_RESULT)), \
166 +(cd $(COMPARE_BUILD_OUTPUTDIR) && ./compare.sh --diffs $(COMPARE_BUILD_COMP_OPTS) \
167 -o $(OUTPUTDIR) $(COMPARE_BUILD_IGNORE_RESULT)) \
168 )
169 endef
170
171 define PrintFailureReports
172 $(if $(filter none, $(LOG_REPORT)), , \
173 $(RM) $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log ; \
174 $(if $(wildcard $(MAKESUPPORT_OUTPUTDIR)/failure-logs/*.log), \
175 ( \
176 $(ECHO) "" ; \
177 $(ECHO) "=== Output from failing command(s) repeated here ===" ; \
178 $(foreach logfile, $(sort $(wildcard $(MAKESUPPORT_OUTPUTDIR)/failure-logs/*.log)), \
179 $(ECHO) "* For target $(notdir $(basename $(logfile))):" ; \
180 $(if $(filter all, $(LOG_REPORT)), \
181 $(GREP) -v -e "^Note: including file:" < $(logfile) || true ; \
182 , \
183 ($(GREP) -v -e "^Note: including file:" < $(logfile) || true) | $(HEAD) -n 15 ; \
184 if test `$(WC) -l < $(logfile)` -gt 15; then \
185 $(ECHO) " ... (rest of output omitted)" ; \
186 fi ; \
187 ) \
188 ) \
189 $(ECHO) "" ; \
190 $(ECHO) "* All command lines available in $(MAKESUPPORT_OUTPUTDIR)/failure-logs." ; \
191 $(ECHO) "=== End of repeated output ===" ; \
192 ) >> $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log \
193 ) \
194 )
195 endef
196
197 define PrintBuildLogFailures
198 $(if $(filter none, $(LOG_REPORT)), , \
199 if $(GREP) -q "recipe for target .* failed" $(BUILD_LOG) 2> /dev/null; then \
200 $(ECHO) "" ; \
201 $(ECHO) "=== Make failed targets repeated here ===" ; \
202 $(GREP) "recipe for target .* failed" $(BUILD_LOG) ; \
203 $(ECHO) "=== End of repeated output ===" ; \
204 $(ECHO) "" ; \
205 $(ECHO) "HELP: Try searching the build log for the name of the first failed target." ; \
206 else \
207 $(ECHO) "" ; \
208 $(ECHO) "No indication of failed target found." ; \
209 $(ECHO) "HELP: Try searching the build log for '] Error'." ; \
210 fi >> $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log ; \
211 $(CAT) $(MAKESUPPORT_OUTPUTDIR)/failure-summary.log \
212 )
213 endef
214
215 define RotateLogFiles
216 $(RM) $(BUILD_LOG).old 2> /dev/null && \
217 $(MV) $(BUILD_LOG) $(BUILD_LOG).old 2> /dev/null || true
218 $(if $(findstring true, $(LOG_PROFILE_TIMES_FILE)), \
219 $(RM) $(BUILD_PROFILE_LOG).old 2> /dev/null && \
220 $(MV) $(BUILD_PROFILE_LOG) $(BUILD_PROFILE_LOG).old 2> /dev/null || true \
221 )
222 endef
223
224 # Failure logs are only supported for "parallel" main targets, not the
225 # (trivial) sequential make targets (such as clean and reconfigure),
226 # since the failure-logs directory creation will conflict with clean.
227 # We also make sure the javatmp directory exists, which is needed if a java
228 # process (like javac) is using java.io.tmpdir.
229 define PrepareFailureLogs
230 $(RM) -r $(MAKESUPPORT_OUTPUTDIR)/failure-logs 2> /dev/null && \
231 $(MKDIR) -p $(MAKESUPPORT_OUTPUTDIR)/failure-logs
232 $(MKDIR) -p $(JAVA_TMP_DIR)
233 $(RM) $(MAKESUPPORT_OUTPUTDIR)/exit-with-error 2> /dev/null
234 endef
235
236 # Remove any javac server logs and port files. This
237 # prevents a new make run to reuse the previous servers.
238 define PrepareJavacServer
239 $(if $(JAVAC_SERVER_DIR), \
240 $(RM) -r $(JAVAC_SERVER_DIR) 2> /dev/null && \
241 $(MKDIR) -p $(JAVAC_SERVER_DIR) \
242 )
243 endef
244
245 define CleanupJavacServer
246 [ -f $(JAVAC_SERVER_DIR)/server.port ] && $(ECHO) Stopping javac server && \
247 $(TOUCH) $(JAVAC_SERVER_DIR)/server.port.stop; true
248 endef
249
250 ifeq ($(call isBuildOs, windows), true)
251 # On windows we need to synchronize with the javac server to be able to
252 # move or remove the build output directory. Since we have no proper
253 # synchronization process, wait for a while and hope it helps. This is only
254 # used by build comparisons.
255 define WaitForJavacServerFinish
256 $(if $(JAVAC_SERVER_DIR), \
257 sleep 5 \
258 )
259 endef
260 else
261 define WaitForJavacServerFinish
262 endef
263 endif
264
265 ##############################################################################
266 # Functions for timers
267 ##############################################################################
268
269 # Store the build times in this directory.
270 BUILDTIMESDIR := $(OUTPUTDIR)/make-support/build-times
271
272 # Record starting time for build of a sub repository.
273 define RecordStartTime
274 $(DATE) '+%Y %m %d %H %M %S' | $(AWK) '{ print $$1,$$2,$$3,$$4,$$5,$$6,($$4*3600+$$5*60+$$6) }' > $(BUILDTIMESDIR)/build_time_start_$(strip $1) && \
275 $(DATE) '+%Y-%m-%d %H:%M:%S' > $(BUILDTIMESDIR)/build_time_start_$(strip $1)_human_readable
276 endef
277
278 # Record ending time and calculate the difference and store it in a
279 # easy to read format. Handles builds that cross midnight. Expects
280 # that a build will never take 24 hours or more.
281 define RecordEndTime
282 $(DATE) '+%Y %m %d %H %M %S' | $(AWK) '{ print $$1,$$2,$$3,$$4,$$5,$$6,($$4*3600+$$5*60+$$6) }' > $(BUILDTIMESDIR)/build_time_end_$(strip $1)
283 $(DATE) '+%Y-%m-%d %H:%M:%S' > $(BUILDTIMESDIR)/build_time_end_$(strip $1)_human_readable
284 $(ECHO) `$(CAT) $(BUILDTIMESDIR)/build_time_start_$(strip $1)` `$(CAT) $(BUILDTIMESDIR)/build_time_end_$(strip $1)` $1 | \
285 $(AWK) '{ F=$$7; T=$$14; if (F > T) { T+=3600*24 }; D=T-F; H=int(D/3600); \
286 M=int((D-H*3600)/60); S=D-H*3600-M*60; printf("%02d:%02d:%02d %s\n",H,M,S,$$15); }' \
287 > $(BUILDTIMESDIR)/build_time_diff_$(strip $1)
288 endef
289
290 define StartGlobalTimer
291 $(RM) -r $(BUILDTIMESDIR) 2> /dev/null && \
292 $(MKDIR) -p $(BUILDTIMESDIR) && \
293 $(call RecordStartTime,TOTAL)
294 endef
295
296 define StopGlobalTimer
297 $(call RecordEndTime,TOTAL)
298 endef
299
300 # Find all build_time_* files and print their contents in a list sorted
301 # on the name of the sub repository.
302 define ReportBuildTimes
303 $(PRINTF) $(LOG_INFO) -- \
304 "----- Build times -------\nStart %s\nEnd %s\n%s\n%s\n-------------------------\n" \
305 "`$(CAT) $(BUILDTIMESDIR)/build_time_start_TOTAL_human_readable`" \
306 "`$(CAT) $(BUILDTIMESDIR)/build_time_end_TOTAL_human_readable`" \
307 "`$(LS) $(BUILDTIMESDIR)/build_time_diff_* | $(GREP) -v _TOTAL | \
308 $(XARGS) $(CAT) | $(SORT) -k 2`" \
309 "`$(CAT) $(BUILDTIMESDIR)/build_time_diff_TOTAL`" \
310 $(BUILD_LOG_PIPE_SIMPLE)
311 endef
312
313 define ReportProfileTimes
314 $(if $(findstring true, $(LOG_PROFILE_TIMES_LOG)), \
315 [ ! -f $(BUILD_PROFILE_LOG) ] || \
316 { $(ECHO) Begin $(notdir $(BUILD_PROFILE_LOG)) && \
317 $(CAT) $(BUILD_PROFILE_LOG) && \
318 $(ECHO) End $(notdir $(BUILD_PROFILE_LOG)); \
319 } \
320 $(BUILD_LOG_PIPE_SIMPLE)
321 )
322 endef
323
324 ################################################################################
325
326 endif # include guard
327 include MakeIncludeEnd.gmk
--- EOF ---