changeset 1661:6849581ba4ab

8136695: Automatic build comparison with COMPARE_BUILD Reviewed-by: erikj
author ihse
date Mon, 21 Sep 2015 09:32:07 +0200
parents ce5c14d97d95
children b545f7d7cf6d
files common/autoconf/basics.m4 common/autoconf/generated-configure.sh common/autoconf/spec.gmk.in make/Init.gmk make/InitSupport.gmk
diffstat 5 files changed, 297 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/common/autoconf/basics.m4	Fri Sep 18 14:19:53 2015 -0700
+++ b/common/autoconf/basics.m4	Mon Sep 21 09:32:07 2015 +0200
@@ -935,6 +935,7 @@
   BASIC_PATH_PROGS(HG, hg)
   BASIC_PATH_PROGS(STAT, stat)
   BASIC_PATH_PROGS(TIME, time)
+  BASIC_PATH_PROGS(PATCH, [gpatch patch])
   # Check if it's GNU time
   IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU time'`
   if test "x$IS_GNU_TIME" != x; then
--- a/common/autoconf/generated-configure.sh	Fri Sep 18 14:19:53 2015 -0700
+++ b/common/autoconf/generated-configure.sh	Mon Sep 21 09:32:07 2015 +0200
@@ -859,6 +859,7 @@
 XATTR
 DSYMUTIL
 IS_GNU_TIME
+PATCH
 TIME
 STAT
 HG
@@ -1174,6 +1175,7 @@
 HG
 STAT
 TIME
+PATCH
 DSYMUTIL
 XATTR
 CODESIGN
@@ -2053,6 +2055,7 @@
   HG          Override default value for HG
   STAT        Override default value for STAT
   TIME        Override default value for TIME
+  PATCH       Override default value for PATCH
   DSYMUTIL    Override default value for DSYMUTIL
   XATTR       Override default value for XATTR
   CODESIGN    Override default value for CODESIGN
@@ -4359,7 +4362,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1441958217
+DATE_WHEN_GENERATED=1442820670
 
 ###############################################################################
 #
@@ -18865,6 +18868,192 @@
   fi
 
 
+
+
+  # Publish this variable in the help.
+
+
+  if test "x$PATCH" = x; then
+    # The variable is not set by user, try to locate tool using the code snippet
+    for ac_prog in gpatch patch
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PATCH+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PATCH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PATCH=$ac_cv_path_PATCH
+if test -n "$PATCH"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5
+$as_echo "$PATCH" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$PATCH" && break
+done
+
+  else
+    # The variable is set, but is it from the command line or the environment?
+
+    # Try to remove the string !PATCH! from our list.
+    try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!PATCH!/}
+    if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
+      # If it failed, the variable was not from the command line. Ignore it,
+      # but warn the user (except for BASH, which is always set by the calling BASH).
+      if test "xPATCH" != xBASH; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of PATCH from the environment. Use command line variables instead." >&5
+$as_echo "$as_me: WARNING: Ignoring value of PATCH from the environment. Use command line variables instead." >&2;}
+      fi
+      # Try to locate tool using the code snippet
+      for ac_prog in gpatch patch
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PATCH+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PATCH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PATCH=$ac_cv_path_PATCH
+if test -n "$PATCH"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5
+$as_echo "$PATCH" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$PATCH" && break
+done
+
+    else
+      # If it succeeded, then it was overridden by the user. We will use it
+      # for the tool.
+
+      # First remove it from the list of overridden variables, so we can test
+      # for unknown variables in the end.
+      CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
+
+      # Check if the provided tool contains a complete path.
+      tool_specified="$PATCH"
+      tool_basename="${tool_specified##*/}"
+      if test "x$tool_basename" = "x$tool_specified"; then
+        # A command without a complete path is provided, search $PATH.
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool PATCH=$tool_basename" >&5
+$as_echo "$as_me: Will search for user supplied tool PATCH=$tool_basename" >&6;}
+        # Extract the first word of "$tool_basename", so it can be a program name with args.
+set dummy $tool_basename; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PATCH+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PATCH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PATCH="$PATCH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PATCH="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PATCH=$ac_cv_path_PATCH
+if test -n "$PATCH"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PATCH" >&5
+$as_echo "$PATCH" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+        if test "x$PATCH" = x; then
+          as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
+        fi
+      else
+        # Otherwise we believe it is a complete path. Use it as it is.
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool PATCH=$tool_specified" >&5
+$as_echo "$as_me: Will use user supplied tool PATCH=$tool_specified" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PATCH" >&5
+$as_echo_n "checking for PATCH... " >&6; }
+        if test ! -x "$tool_specified"; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+          as_fn_error $? "User supplied tool PATCH=$tool_specified does not exist or is not executable" "$LINENO" 5
+        fi
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
+$as_echo "$tool_specified" >&6; }
+      fi
+    fi
+  fi
+
+
   # Check if it's GNU time
   IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU time'`
   if test "x$IS_GNU_TIME" != x; then
--- a/common/autoconf/spec.gmk.in	Fri Sep 18 14:19:53 2015 -0700
+++ b/common/autoconf/spec.gmk.in	Mon Sep 21 09:32:07 2015 +0200
@@ -495,6 +495,7 @@
 MKDIR:=@MKDIR@
 MV:=@MV@
 NAWK:=@NAWK@
+PATCH:=@PATCH@
 PRINTF:=@PRINTF@
 PWD:=@THEPWDCMD@
 RM:=@RM@
--- a/make/Init.gmk	Fri Sep 18 14:19:53 2015 -0700
+++ b/make/Init.gmk	Mon Sep 21 09:32:07 2015 +0200
@@ -50,7 +50,8 @@
   include $(topdir)/make/Help.gmk
 
   # Targets provided by Init.gmk.
-  ALL_INIT_TARGETS := print-modules print-targets print-configuration reconfigure
+  ALL_INIT_TARGETS := print-modules print-targets print-configuration \
+      reconfigure pre-compare-build post-compare-build
 
   # CALLED_TARGETS is the list of targets that the user provided,
   # or "default" if unspecified.
@@ -163,25 +164,39 @@
 	      $(COMMAND_LINE_VARIABLES) $(MAKECMDGOALS))')
         endif
 
+    MAKE_INIT_WITH_SPEC_ARGUMENTS := ACTUAL_TOPDIR=$(topdir) \
+        USER_MAKE_VARS="$(USER_MAKE_VARS)" MAKE_LOG_FLAGS=$(MAKE_LOG_FLAGS) \
+        LOG_LEVEL=$(LOG_LEVEL) LOG_NOFILE=$(LOG_NOFILE) \
+        INIT_TARGETS="$(INIT_TARGETS)" \
+        SEQUENTIAL_TARGETS="$(SEQUENTIAL_TARGETS)" \
+        PARALLEL_TARGETS="$(PARALLEL_TARGETS)"
+
     # Now the init and main targets will be called, once for each SPEC. The
     # recipe will be run once for every target specified, but we only want to
     # execute the recipe a single time, hence the TARGET_DONE with a dummy
     # command if true.
+    # The COMPARE_BUILD part implements special support for makefile development.
     $(ALL_INIT_TARGETS) $(ALL_MAIN_TARGETS): make-info
 	@$(if $(TARGET_DONE), \
 	  true \
 	, \
+	  ( cd $(topdir) && \
 	  $(foreach spec, $(SPECS), \
-	    ( cd $(topdir) && \
 	    $(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -j 1 -f $(topdir)/make/Init.gmk \
-	        SPEC=$(spec) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) \
-	        USER_MAKE_VARS="$(USER_MAKE_VARS)" MAKE_LOG_FLAGS=$(MAKE_LOG_FLAGS) \
-	        LOG_LEVEL=$(LOG_LEVEL) LOG_NOFILE=$(LOG_NOFILE) \
-	        INIT_TARGETS="$(INIT_TARGETS)" \
-	        SEQUENTIAL_TARGETS="$(SEQUENTIAL_TARGETS)" \
-	        PARALLEL_TARGETS="$(PARALLEL_TARGETS)"  \
-	        main ) && \
-	  ) true \
+	        SPEC=$(spec) HAS_SPEC=true $(MAKE_INIT_WITH_SPEC_ARGUMENTS) \
+	        main && \
+	    $(if $(and $(COMPARE_BUILD), $(PARALLEL_TARGETS)), \
+	        $(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -f $(topdir)/make/Init.gmk \
+	            SPEC=$(spec) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) \
+	            COMPARE_BUILD="$(COMPARE_BUILD)" pre-compare-build && \
+	        $(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -j 1 -f $(topdir)/make/Init.gmk \
+	            SPEC=$(spec) HAS_SPEC=true $(MAKE_INIT_WITH_SPEC_ARGUMENTS) \
+	            COMPARE_BUILD="$(COMPARE_BUILD)" main && \
+	        $(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -f $(topdir)/make/Init.gmk \
+	            SPEC=$(spec) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) \
+	            COMPARE_BUILD="$(COMPARE_BUILD)" post-compare-build && \
+	    ) \
+	  ) true ) \
 	  $(eval TARGET_DONE=true) \
 	)
 
@@ -205,6 +220,9 @@
   # Verify that the spec file we included seems okay.
   $(eval $(call CheckSpecSanity))
 
+  # Parse COMPARE_BUILD (for makefile development)
+  $(eval $(call ParseCompareBuild))
+
   ifeq ($(LOG_NOFILE), true)
     # Disable log wrapper if LOG=[level,]nofile was given
     override BUILD_LOG_WRAPPER :=
@@ -244,7 +262,7 @@
   # The main target, for delegating into Main.gmk
   ##############################################################################
 
-  MAIN_TARGETS := $(SEQUENTIAL_TARGETS) $(PARALLEL_TARGETS)
+  MAIN_TARGETS := $(SEQUENTIAL_TARGETS) $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE)
   TARGET_DESCRIPTION := target$(if $(word 2, $(MAIN_TARGETS)),s) \
       '$(strip $(MAIN_TARGETS))' in configuration '$(CONF_NAME)'
 
@@ -271,7 +289,7 @@
 	    ( cd $(TOPDIR) && \
 	        $(BUILD_LOG_WRAPPER) $(MAKE) $(MAKE_ARGS) $(OUTPUT_SYNC_FLAG) \
 	            -j $(JOBS) -f make/Main.gmk $(USER_MAKE_VARS) \
-	            $(PARALLEL_TARGETS) || \
+	            $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) || \
 	        ( exitcode=$$? && $(BUILD_LOG_WRAPPER) \
 	        $(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" && \
 	        cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk \
@@ -304,5 +322,26 @@
 	fi
 	$(PRINTF) "Hint: If caused by a warning, try configure --disable-warnings-as-errors.\n\n"
 
+    # Support targets for COMPARE_BUILD, used for makefile development
+    pre-compare-build:
+	$(ECHO) "Preparing for comparison rebuild"
+        # Apply patch, if any
+        ifneq ($(COMPARE_BUILD_PATCH), )
+	  $(PATCH) -p1 < $(COMPARE_BUILD_PATCH)
+        endif
+        # Move the first build away and re-create the output directory
+	( cd $(TOPDIR) && \
+	    $(MV) $(OUTPUT_ROOT) $(OUTPUT_ROOT).OLD && \
+	    $(MKDIR) -p $(OUTPUT_ROOT) )
+        # Re-run configure with the same arguments (and possibly some additional),
+	# must be done after patching.
+	( cd $(OUTPUT_ROOT) && PATH="$(ORIGINAL_PATH)" \
+	    $(BASH) $(TOPDIR)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
+
+    post-compare-build:
+        # Compare first and second build. Ignore any error code from compare.sh.
+	$(ECHO) "Comparing between comparison rebuild (this/new) and baseline (other/old)"
+	+(cd $(OUTPUT_ROOT) && ./compare.sh $(COMPARE_BUILD_COMP_OPTS) -o $(OUTPUT_ROOT).OLD || true)
+
   .PHONY: print-targets print-modules reconfigure main on-failure
 endif
--- a/make/InitSupport.gmk	Fri Sep 18 14:19:53 2015 -0700
+++ b/make/InitSupport.gmk	Mon Sep 21 09:32:07 2015 +0200
@@ -40,7 +40,7 @@
   ##############################################################################
 
   # Make control variables, handled by Init.gmk
-  INIT_CONTROL_VARIABLES := LOG CONF SPEC JOBS CONF_CHECK
+  INIT_CONTROL_VARIABLES := LOG CONF SPEC JOBS CONF_CHECK COMPARE_BUILD
 
   # All known make control variables
   MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER
@@ -53,12 +53,14 @@
 
   # The variable MAKEOVERRIDES contains variable assignments from the command
   # line, but in reverse order to what the user entered.
+  # The '\#' <=> '\ 'dance is needed to keep values with space in them connected.
   COMMAND_LINE_VARIABLES := $(subst \#,\ , $(call reverse, $(subst \ ,\#,$(MAKEOVERRIDES))))
 
   # A list like FOO="val1" BAR="val2" containing all user-supplied make
   # variables that we should propagate.
-  USER_MAKE_VARS := $(filter-out $(addsuffix =%, $(INIT_CONTROL_VARIABLES)), \
-      $(MAKEOVERRIDES))
+  # The '\#' <=> '\ 'dance is needed to keep values with space in them connected.
+  USER_MAKE_VARS := $(subst \#,\ , $(filter-out $(addsuffix =%, $(INIT_CONTROL_VARIABLES)), \
+      $(subst \ ,\#,$(MAKEOVERRIDES))))
 
   # Setup information about available configurations, if any.
   build_dir=$(topdir)/build
@@ -309,6 +311,55 @@
     endif
   endef
 
+  # Parse COMPARE_BUILD into COMPARE_BUILD_*
+  # Syntax: COMPARE_BUILD=CONF=<configure options>:PATCH=<patch file>:
+  #         MAKE=<make targets>:COMP_OPTS=<compare script options>|<default>
+  # If neither CONF or PATCH is given, assume <default> means CONF if it
+  # begins with "--", otherwise assume it means PATCH.
+  # MAKE and COMP_OPTS can only be used with CONF and/or PATCH specified.
+  # If any value contains "+", it will be replaced by space.
+  define ParseCompareBuild
+    ifneq ($$(COMPARE_BUILD), )
+      ifneq ($$(findstring :, $$(COMPARE_BUILD)), )
+        $$(foreach part, $$(subst :, , $$(COMPARE_BUILD)), \
+          $$(if $$(filter PATCH=%, $$(part)), \
+            $$(eval COMPARE_BUILD_PATCH=$$(strip $$(patsubst PATCH=%, %, $$(part)))) \
+          ) \
+          $$(if $$(filter CONF=%, $$(part)), \
+            $$(eval COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(part))))) \
+          ) \
+          $$(if $$(filter MAKE=%, $$(part)), \
+            $$(eval COMPARE_BUILD_MAKE=$$(strip $$(subst +, , $$(patsubst MAKE=%, %, $$(part))))) \
+          ) \
+          $$(if $$(filter COMP_OPTS=%, $$(part)), \
+            $$(eval COMPARE_BUILD_COMP_OPTS=$$(strip $$(subst +, , $$(patsubst COMP_OPTS=%, %, $$(part))))) \
+          ) \
+        )
+      else
+        # Separate handling for single field case, to allow for spaces in values.
+        ifneq ($$(filter PATCH=%, $$(COMPARE_BUILD)), )
+          COMPARE_BUILD_PATCH=$$(strip $$(patsubst PATCH=%, %, $$(COMPARE_BUILD)))
+        else ifneq ($$(filter CONF=%, $$(COMPARE_BUILD)), )
+          COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(patsubst CONF=%, %, $$(COMPARE_BUILD))))
+        else ifneq ($$(filter --%, $$(COMPARE_BUILD)), )
+          # Assume CONF if value begins with --
+          COMPARE_BUILD_CONF=$$(strip $$(subst +, , $$(COMPARE_BUILD)))
+        else
+          # Otherwise assume patch file
+          COMPARE_BUILD_PATCH=$$(strip $$(COMPARE_BUILD))
+        endif
+      endif
+      ifneq ($$(COMPARE_BUILD_PATCH), )
+        ifneq ($$(wildcard $$(TOPDIR)/$$(COMPARE_BUILD_PATCH)), )
+          # Assume relative path, if file exists
+          COMPARE_BUILD_PATCH := $$(wildcard $$(TOPDIR)/$$(COMPARE_BUILD_PATCH))
+        else ifeq ($$(wildcard $$(COMPARE_BUILD_PATCH)), )
+          $$(error Patch file $$(COMPARE_BUILD_PATCH) does not exist)
+        endif
+      endif
+    endif
+  endef
+
   define RotateLogFiles
 	$(RM) $(BUILD_LOG).old 2> /dev/null
 	$(MV) $(BUILD_LOG) $(BUILD_LOG).old 2> /dev/null || true