MakeHelpers.gmk 13.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#
# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.  Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#

################################################################
#
# This file contains helper functions for the top-level Makefile that does
# not depend on the spec.gmk file having been read. (The purpose of this 
# file is ju to avoid cluttering the top-level Makefile.)
#
################################################################

ifndef _MAKEHELPERS_GMK
_MAKEHELPERS_GMK := 1

##############################
# Stuff to run at include time
##############################

# Find out which variables were passed explicitely on the make command line. These
# will be passed on to sub-makes, overriding spec.gmk settings.
MAKE_ARGS=$(foreach var,$(subst =command,,$(filter %=command,$(foreach var,$(.VARIABLES),$(var)=$(firstword $(origin $(var)))))),$(var)=$($(var)))

list_alt_overrides_with_origins=$(filter ALT_%=environment ALT_%=command,$(foreach var,$(.VARIABLES),$(var)=$(firstword $(origin $(var)))))
list_alt_overrides=$(subst =command,,$(subst =environment,,$(list_alt_overrides_with_origins)))

O
ohair 已提交
48 49 50 51 52
# Store the build times in this directory.
BUILDTIMESDIR=$(OUTPUT_ROOT)/tmp/buildtimes

# Global targets are possible to run either with or without a SPEC. The prototypical
# global target is "help". 
53
global_targets=help jprt% bridgeBuild
O
ohair 已提交
54

55 56 57 58
##############################
# Functions
##############################

O
ohair 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
define CheckEnvironment
    # Find all environment or command line variables that begin with ALT.
    $(if $(list_alt_overrides),
        @$(PRINTF) "\nWARNING: You have the following ALT_ variables set:\n"
    @$(PRINTF) "$(foreach var,$(list_alt_overrides),$(var)=$$$(var))\n"
    @$(PRINTF) "ALT_ variables are deprecated and will be ignored. Please clean your environment.\n\n"
    )
endef

### Functions for timers

# Record starting time for build of a sub repository.
define RecordStartTime
    $(MKDIR) -p $(BUILDTIMESDIR)
    $(DATE) '+%Y %m %d %H %M %S' | $(NAWK) '{ print $$1,$$2,$$3,$$4,$$5,$$6,($$4*3600+$$5*60+$$6) }' > $(BUILDTIMESDIR)/build_time_start_$1
    $(DATE) '+%Y-%m-%d %H:%M:%S' > $(BUILDTIMESDIR)/build_time_start_$1_human_readable
endef

# Record ending time and calculate the difference and store it in a
# easy to read format. Handles builds that cross midnight. Expects
# that a build will never take 24 hours or more. 
define RecordEndTime
    $(DATE) '+%Y %m %d %H %M %S' | $(NAWK) '{ print $$1,$$2,$$3,$$4,$$5,$$6,($$4*3600+$$5*60+$$6) }' > $(BUILDTIMESDIR)/build_time_end_$1
    $(DATE) '+%Y-%m-%d %H:%M:%S' > $(BUILDTIMESDIR)/build_time_end_$1_human_readable
    $(ECHO) `$(CAT) $(BUILDTIMESDIR)/build_time_start_$1` `$(CAT) $(BUILDTIMESDIR)/build_time_end_$1` $1 | \
        $(NAWK) '{ F=$$7; T=$$14; if (F > T) { T+=3600*24 }; D=T-F; H=int(D/3600); \
        M=int((D-H*3600)/60); S=D-H*3600-M*60; printf("%02d:%02d:%02d %s\n",H,M,S,$$15); }' \
        > $(BUILDTIMESDIR)/build_time_diff_$1
endef

# Find all build_time_* files and print their contents in a list sorted
# on the name of the sub repository.
define ReportBuildTimes
    $(BUILD_LOG_WRAPPER) $(PRINTF) -- "----- Build times -------\nStart %s\nEnd   %s\n%s\n%s\n-------------------------\n" \
        "`$(CAT) $(BUILDTIMESDIR)/build_time_start_TOTAL_human_readable`" \
        "`$(CAT) $(BUILDTIMESDIR)/build_time_end_TOTAL_human_readable`" \
        "`$(LS) $(BUILDTIMESDIR)/build_time_diff_* | $(GREP) -v _TOTAL | $(XARGS) $(CAT) | $(SORT) -k 2`" \
        "`$(CAT) $(BUILDTIMESDIR)/build_time_diff_TOTAL`"
endef

define ResetAllTimers
    $$(shell $(MKDIR) -p $(BUILDTIMESDIR) &&  $(RM) $(BUILDTIMESDIR)/build_time_*)
endef

define StartGlobalTimer
    $(call RecordStartTime,TOTAL)
endef

define StopGlobalTimer
    $(call RecordEndTime,TOTAL)
endef

### Functions for managing makefile structure (start/end of makefile and individual targets)

# Do not indent this function, this will add whitespace at the start which the caller won't handle
define GetRealTarget
115
$(strip $(if $(MAKECMDGOALS),$(MAKECMDGOALS),default))
O
ohair 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128
endef

# Do not indent this function, this will add whitespace at the start which the caller won't handle
define LastGoal
$(strip $(lastword $(call GetRealTarget)))
endef

# Check if the current target is the final target, as specified by
# the user on the command line. If so, call AtRootMakeEnd.
define CheckIfMakeAtEnd
    # Check if the current target is the last goal
    $(if $(filter $@,$(call LastGoal)),$(call AtMakeEnd))
    # If the target is 'foo-only', check if our goal was stated as 'foo'
129
    $(if $(filter $@,$(call LastGoal)-only),$(call AtMakeEnd))
O
ohair 已提交
130 131 132 133 134 135 136 137 138 139 140 141
endef

# Hook to be called when starting to execute a top-level target
define TargetEnter
    $(BUILD_LOG_WRAPPER) $(PRINTF) "## Starting $(patsubst %-only,%,$@)\n"
    $(call RecordStartTime,$(patsubst %-only,%,$@))
endef

# Hook to be called when finish executing a top-level target
define TargetExit
    $(call RecordEndTime,$(patsubst %-only,%,$@))
    $(BUILD_LOG_WRAPPER) $(PRINTF) "## Finished $(patsubst %-only,%,$@) (build time %s)\n\n" \
142
        "`$(CAT) $(BUILDTIMESDIR)/build_time_diff_$(patsubst %-only,%,$@) | $(CUT) -f 1 -d ' '`"
O
ohair 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156
    $(call CheckIfMakeAtEnd)
endef

# Hook to be called as the very first thing when running a normal build
define AtMakeStart
    $(if $(findstring --jobserver,$(MAKEFLAGS)),$(error make -j is not supported, use make JOBS=n))
    $(call CheckEnvironment)
    @$(PRINTF) $(LOG_INFO) "Running make as '$(MAKE) $(MFLAGS) $(MAKE_ARGS)'\n"
    @$(PRINTF) "Building $(PRODUCT_NAME) for target '$(call GetRealTarget)' in configuration '$(CONF_NAME)'\n\n"
    $(call StartGlobalTimer)
endef

# Hook to be called as the very last thing for targets that are "top level" targets
define AtMakeEnd
157
    [ -f $(SJAVAC_SERVER_DIR)/server.port ] && echo Stopping sjavac server && $(TOUCH) $(SJAVAC_SERVER_DIR)/server.port.stop; true
O
ohair 已提交
158 159 160 161 162 163 164 165 166
    $(call StopGlobalTimer)
    $(call ReportBuildTimes)
    @$(PRINTF) "Finished building $(PRODUCT_NAME) for target '$(call GetRealTarget)'\n"
    $(call CheckEnvironment)
endef

### Functions for parsing and setting up make options from command-line

define FatalError
167
    # If the user specificed a "global" target (e.g. 'help'), do not exit but continue running
O
ohair 已提交
168
    $$(if $$(filter-out $(global_targets),$$(call GetRealTarget)),$$(error Cannot continue))
169 170 171 172 173
endef

define ParseLogLevel
    ifeq ($$(origin VERBOSE),undefined)
        # Setup logging according to LOG (but only if VERBOSE is not given)
174 175

        # If the "nofile" argument is given, act on it and strip it away
176 177 178 179 180 181 182 183 184 185 186
        ifneq ($$(findstring nofile,$$(LOG)),)
          # Reset the build log wrapper, regardless of other values
          override BUILD_LOG_WRAPPER=
          # COMMA is defined in spec.gmk, but that is not included yet
          COMMA=,
          # First try to remove ",nofile" if it exists
          LOG_STRIPPED1=$$(subst $$(COMMA)nofile,,$$(LOG))
          # Otherwise just remove "nofile"
          LOG_STRIPPED2=$$(subst nofile,,$$(LOG_STRIPPED1))
          # We might have ended up with a leading comma. Remove it
          LOG_STRIPPED3=$$(strip $$(patsubst $$(COMMA)%,%,$$(LOG_STRIPPED2)))
187 188 189
          LOG_LEVEL:=$$(LOG_STRIPPED3)
        else
          LOG_LEVEL:=$$(LOG)
190 191
        endif

192
        ifeq ($$(LOG_LEVEL),)
193
            # Set LOG to "warn" as default if not set (and no VERBOSE given)
194
            override LOG_LEVEL=warn
195
        endif
196
        ifeq ($$(LOG_LEVEL),warn)
197
            VERBOSE=-s
198
        else ifeq ($$(LOG_LEVEL),info)
O
ohair 已提交
199
            VERBOSE=-s
200
        else ifeq ($$(LOG_LEVEL),debug)
201
            VERBOSE=
202
        else ifeq ($$(LOG_LEVEL),trace)
O
ohair 已提交
203
            VERBOSE=
204 205
        else
            $$(info Error: LOG must be one of: warn, info, debug or trace.)
O
ohair 已提交
206
            $$(eval $$(call FatalError))
207 208
        endif
    else
209 210 211 212 213 214
        # Provide resonable interpretations of LOG_LEVEL if VERBOSE is given.
        ifeq ($(VERBOSE),)
            LOG_LEVEL:=debug
        else
            LOG_LEVEL:=warn
        endif
215 216 217 218 219
        ifneq ($$(LOG),)
            # We have both a VERBOSE and a LOG argument. This is OK only if this is a repeated call by ourselves,
            # but complain if this is the top-level make call.
            ifeq ($$(MAKELEVEL),0)
                $$(info Cannot use LOG=$$(LOG) and VERBOSE=$$(VERBOSE) at the same time. Choose one.)
O
ohair 已提交
220
                $$(eval $$(call FatalError))
221 222 223 224 225 226
            endif
        endif
    endif
endef

define ParseConfAndSpec
O
ohair 已提交
227 228 229 230 231 232 233
    ifneq ($$(filter-out $(global_targets),$$(call GetRealTarget)),)
        # If we only have global targets, no need to bother with SPEC or CONF
        ifneq ($$(origin SPEC),undefined)
            # We have been given a SPEC, check that it works out properly
            ifeq ($$(wildcard $$(SPEC)),)
                $$(info Cannot locate spec.gmk, given by SPEC=$$(SPEC))
                $$(eval $$(call FatalError))
234
            endif
O
ohair 已提交
235 236 237 238 239 240
            ifneq ($$(origin CONF),undefined)
                # We also have a CONF argument. This is OK only if this is a repeated call by ourselves,
                # but complain if this is the top-level make call.
                ifeq ($$(MAKELEVEL),0)
                    $$(info Cannot use CONF=$$(CONF) and SPEC=$$(SPEC) at the same time. Choose one.)
                    $$(eval $$(call FatalError))
241 242
                endif
            endif
O
ohair 已提交
243
            # ... OK, we're satisfied, we'll use this SPEC later on
244
        else
O
ohair 已提交
245 246 247 248 249 250
            # Find all spec.gmk files in the build output directory
            output_dir=$$(root_dir)/build
            all_spec_files=$$(wildcard $$(output_dir)/*/spec.gmk)
            ifeq ($$(all_spec_files),)
                $$(info No configurations found for $$(root_dir)! Please run configure to create a configuration.)
                $$(eval $$(call FatalError))
251
            endif
O
ohair 已提交
252 253
            # Extract the configuration names from the path
            all_confs=$$(patsubst %/spec.gmk,%,$$(patsubst $$(output_dir)/%,%,$$(all_spec_files)))
254

O
ohair 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
            ifneq ($$(origin CONF),undefined)
                # User have given a CONF= argument.
                ifeq ($$(CONF),)
                    # If given CONF=, match all configurations
                    matching_confs=$$(strip $$(all_confs))
                else
                    # Otherwise select those that contain the given CONF string
                    matching_confs=$$(strip $$(foreach var,$$(all_confs),$$(if $$(findstring $$(CONF),$$(var)),$$(var))))
                endif
                ifeq ($$(matching_confs),)
                    $$(info No configurations found matching CONF=$$(CONF))
                    $$(info Available configurations:)
                    $$(foreach var,$$(all_confs),$$(info * $$(var)))
                    $$(eval $$(call FatalError))
                else
                    ifeq ($$(words $$(matching_confs)),1)
                        $$(info Building '$$(matching_confs)' (matching CONF=$$(CONF)))
                    else
                        $$(info Building target '$(call GetRealTarget)' in the following configurations (matching CONF=$$(CONF)):)
                        $$(foreach var,$$(matching_confs),$$(info * $$(var)))
                    endif
                endif
277

O
ohair 已提交
278 279 280 281 282 283 284 285 286 287 288
                # Create a SPEC definition. This will contain the path to one or more spec.gmk files.
                SPEC=$$(addsuffix /spec.gmk,$$(addprefix $$(output_dir)/,$$(matching_confs)))
            else
                # No CONF or SPEC given, check the available configurations
                ifneq ($$(words $$(all_spec_files)),1)
                    $$(info No CONF given, but more than one configuration found in $$(output_dir).)
                    $$(info Available configurations:)
                    $$(foreach var,$$(all_confs),$$(info * $$(var)))
                    $$(info Please retry building with CONF=<config pattern> (or SPEC=<specfile>))
                    $$(eval $$(call FatalError))
                endif
289

O
ohair 已提交
290 291 292 293 294
                # We found exactly one configuration, use it
                SPEC=$$(strip $$(all_spec_files))
            endif
        endif
    endif
295 296
endef

O
ohair 已提交
297
### Convenience functions from Main.gmk
298

299 300 301 302 303 304 305
# Cleans the component given as $1
define CleanComponent
    @$(PRINTF) "Cleaning $1 build artifacts ..."
    @($(CD) $(OUTPUT_ROOT) && $(RM) -r $1)
    @$(PRINTF) " done\n"
endef

306
endif # _MAKEHELPERS_GMK