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