TextFileProcessing.gmk 10.0 KB
Newer Older
1
#
C
clanger 已提交
2
# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
# 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.
#

26 27 28
ifeq (,$(_MAKEBASE_GMK))
  $(error You must include MakeBase.gmk prior to including TextFileProcessing.gmk)
endif
29 30 31 32 33 34 35 36

# Helper function for SetupTextFileProcessing; adds a rule for a single file
# to be processed.
# param 1 = The namespace argument, e.g. BUILD_VERSION_FILE
# param 2 = the source file name (full path)
# param 3 = the target base directory
# param 4 = the target file name (possibly with a partial path)
define SetupSingleTextFileForProcessing
37
  $(strip $3)/$(strip $4): $2 $$($1_VARDEPS_FILE)
E
erikj 已提交
38 39 40 41 42 43
	$$(call LogInfo, Processing $(strip $4))
	$$(call MakeDir, $$(@D))
	$(RM) '$$@' '$$@.includes.tmp' '$$@.replacements.tmp' ; \
	$$($1_INCLUDES_COMMAND_LINE) < '$$<' > '$$@.includes.tmp' ; \
	$$($1_REPLACEMENTS_COMMAND_LINE) < '$$@.includes.tmp' > '$$@.replacements.tmp' ; \
	$(RM) '$$@.includes.tmp' ; \
44 45 46 47 48
	$(MV) '$$@.replacements.tmp' '$$@'

  $1 += $(strip $3)/$(strip $4)
endef

49 50 51 52 53
# Setup make rules for processing one or more text files, in which specified
# markers are replaced with a given text, or with the contents of a given file.
#
# Parameter 1 is the name of the rule. This name is used as variable prefix,
# and the targets generated are listed in a variable by that name.
54
#
55
# Remaining parameters are named arguments. These include:
56 57 58 59 60 61
#   SOURCE_DIRS one or more directory roots to search for files to process
#   SOURCE_FILES complete paths to one or more files to process
#   OUTPUT_DIR the directory where we store the processed files.
#   OUTPUT_FILE the name of the resulting file. Only allowed if processing a
#       single file.
#   SOURCE_BASE_DIR a common root to all SOURCE_DIRS.
62
#       If specified, files will keep the path relative to the base in the
63 64 65 66 67 68 69 70 71 72 73 74 75
#       OUTPUT_DIR. Otherwise, the hierarchy will be flattened into the OUTPUT_DIR.
#   INCLUDE_FILES only include files matching these patterns (used only with
#       SOURCE_DIRS)
#   EXCLUDE_FILES exclude files matching these patterns (used only with
#       SOURCE_DIRS)
#   INCLUDES replace the occurances of a pattern with the contents of a file;
#       one or more such include pattern, using the syntax:
#       PLACEHOLDER => FILE_TO_INCLUDE ; ...
#       Each PLACEHOLDER must be on a single, otherwise empty line (whitespace
#       padding is allowed).
#   REPLACEMENTS one or more text replacement patterns, using the syntax:
#       PATTERN => REPLACEMENT_TEXT ; ...
#
76 77 78
#   If both INCLUDES or REPLACEMENTS are present, then the includes will be
#   processed first, and replacements will be done on the included fragments as well.
#   If neither is present, the files will just be copied without modifications.
79
#
80 81
SetupTextFileProcessing = $(NamedParamsMacroTemplate)
define SetupTextFileProcessingBody
82 83 84 85 86 87 88 89 90 91 92 93

  ifneq ($$($1_SOURCE_FILES),)
    ifneq ($$($1_SOURCE_DIRS),)
      $$(error Cannot use both SOURCE_FILES and SOURCE_DIRS (in $1))
    endif
    ifneq ($$($1_SOURCE_BASE_DIR),)
      $$(error Cannot use SOURCE_BASE_DIR without SOURCE_DIRS (in $1))
    endif
    ifneq ($$($1_EXCLUDE_FILES)$$($1_INCLUDE_FILES),)
      $$(error Cannot INCLUDE/EXCLUDE_FILES with SOURCE_FILES (in $1))
    endif
  else
94 95 96
    ifeq ($$($1_SOURCE_DIRS),)
      $$(error Must specify either SOURCE_FILES or SOURCE_DIRS (in $1))
    endif
97 98 99 100 101 102 103 104 105
    # Find all files in the source trees. Sort to remove duplicates.
    $$(foreach src, $$($1_SOURCE_DIRS), $$(if $$(wildcard $$(src)), , \
        $$(error SOURCE_DIRS contains missing directory $$(src) (in $1))))
    ifneq ($$($1_SOURCE_BASE_DIR),)
      $$(foreach src, $$($1_SOURCE_DIRS), \
          $$(if $$(findstring $$($1_SOURCE_BASE_DIR), $$(src)), , \
          $$(error SOURCE_DIRS contains directory $$(src) outside \
              SOURCE_BASE_DIR $$($1_SOURCE_BASE_DIR) (in $1))))
    endif
C
clanger 已提交
106
    $1_SOURCE_FILES := $$(sort $$(call FindFiles,$$($1_SOURCE_DIRS)))
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    $1_EXCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_EXCLUDE_FILES)))
    $1_INCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_INCLUDE_FILES)))
    $1_SOURCE_FILES := $$(filter-out $$($1_EXCLUDE_FILES),$$($1_SOURCE_FILES))
    ifneq (,$$(strip $$($1_INCLUDE_FILES)))
      $1_SOURCE_FILES := $$(filter $$($1_INCLUDE_FILES),$$($1_SOURCE_FILES))
    endif
    ifeq (,$$($1_SOURCE_FILES))
      $$(info No sources found for $1 when looking inside the dirs $$($1_SRC))
    endif
  endif

  ifneq ($$($1_REPLACEMENTS),)
    # We have a replacement request, prepare it for the recipe
    ifneq ($$(findstring /,$$($1_REPLACEMENTS)),)
      # Cannot use / as separator
      ifneq ($$(findstring @,$$($1_REPLACEMENTS)),)
        # Cannot use @ as separator
        ifneq ($$(findstring |,$$($1_REPLACEMENTS)),)
          # Cannot use | as separator
          ifneq ($$(findstring !,$$($1_REPLACEMENTS)),)
            # Cannot use ! as separator. Give up.
            $$(error No suitable sed separator can be found for $1. Tested /, @, | and !)
          else
            $1_SEP := !
          endif
        else
          $1_SEP := |
        endif
      else
        $1_SEP := @
      endif
    else
      $1_SEP := /
    endif

    # If we have a trailing "=>" (i.e. last rule replaces with empty, and is not
    # terminated by a ;), add a trailing ; to minimize the number of corner
    # cases in the hairy subst expression..
    ifeq ($$(lastword $$($1_REPLACEMENTS)), =>)
      $1_REPLACEMENTS += ;
    endif

149
    # If we have a trailing ";", add a dummy replacement, since there is no easy
150 151 152 153 154 155
    # way to delete the last word in make.
    ifeq ($$(lastword $$($1_REPLACEMENTS)), ;)
      $1_REPLACEMENTS += DUMMY_REPLACEMENT => DUMMY_REPLACEMENT
    endif

    # Convert the REPLACEMENTS syntax ( A => B ; C => D ; ...) to a sed command
156 157 158 159 160
    # line (-e "s/A/B/g" -e "s/C/D/g" ...), basically by replacing '=>' with '/'
    # and ';' with '/g" -e "s/', and adjusting for edge cases.
    $1_REPLACEMENTS_COMMAND_LINE := $(SED) -e 's$$($1_SEP)$$(subst $$(SPACE);$$(SPACE),$$($1_SEP)g' \
        -e 's$$($1_SEP),$$(subst $$(SPACE)=>$$(SPACE),$$($1_SEP),$$(subst $$(SPACE)=>$$(SPACE);$$(SPACE),$$($1_SEP)$$($1_SEP)g' \
        -e 's$$($1_SEP),$$(strip $$($1_REPLACEMENTS)))))$$($1_SEP)g'
161
  else
162
    # We don't have any replacements, just pipe the file through cat.
163 164 165 166 167 168 169 170
    $1_REPLACEMENTS_COMMAND_LINE := $(CAT)
  endif

  ifneq ($$($1_INCLUDES),)
    # We have a include request, prepare it for the recipe.
    # Convert an INCLUDE like this PATTERN_1 => file1 ; PATTERN_2 => file2 ;
    # into an awk script fragment like this:
    # {
171 172
    #   if (matches("PATTERN_1")) { include("file1") } else
    #   if (matches("PATTERN_2")) { include("file2") } else
173 174 175 176 177 178 179 180 181 182 183 184
    #   print
    # }

    $1_INCLUDES_HEADER_AWK := \
        function matches(pattern) { return ($$$$0 ~ "^[ \t]*" pattern "[ \t]*$$$$") } \
        function include(filename) { while ((getline < filename) == 1) print ; close(filename) }
    $1_INCLUDES_PARTIAL_AWK := $$(subst $$(SPACE);,,$$(subst $$(SPACE)=>$$(SPACE),"$$(RIGHT_PAREN)$$(RIGHT_PAREN) \
        { include$$(LEFT_PAREN)",$$(subst $$(SPACE);$$(SPACE),"$$(RIGHT_PAREN) } \
        else if $$(LEFT_PAREN)matches$$(LEFT_PAREN)",$$(strip $$($1_INCLUDES)))))
    $1_INCLUDES_COMMAND_LINE := $(NAWK) '$$($1_INCLUDES_HEADER_AWK) \
        { if (matches("$$($1_INCLUDES_PARTIAL_AWK)") } else print }'
  else
185
    # We don't have any includes, just pipe the file through cat.
186 187 188
    $1_INCLUDES_COMMAND_LINE := $(CAT)
  endif

189 190 191
  $1_VARDEPS := $$($1_INCLUDES_COMMAND_LINE) $$($1_REPLACEMENTS_COMMAND_LINE)
  $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS)

192
  # Reset target list before populating it
193
  $1 :=
194 195 196 197 198 199 200 201

  ifneq ($$($1_OUTPUT_FILE),)
    ifneq ($$(words $$($1_SOURCE_FILES)), 1)
      $$(error Cannot use OUTPUT_FILE for more than one source file (in $1))
    endif

    # Note that $1 is space sensitive and must disobey whitespace rules
    $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$($1_SOURCE_FILES), \
202
        $$(patsubst %/, %, $$(dir $$($1_OUTPUT_FILE))), $$(notdir $$($1_OUTPUT_FILE))))
203 204 205 206 207 208 209
  else
    ifeq ($$($1_OUTPUT_DIR),)
      $$(error Neither OUTPUT_FILE nor OUTPUT_DIR was specified (in $1))
    endif

    # Now call add_native_source for each source file we are going to process.
    ifeq ($$($1_SOURCE_BASE_DIR),)
210
      # With no base dir specified, put all files in target dir, flattening any
211 212 213 214
      # hierarchies. Note that $1 is space sensitive and must disobey whitespace
      # rules.
      $$(foreach src, $$($1_SOURCE_FILES), \
          $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$(src), \
215
              $$(patsubst %/, %, $$($1_OUTPUT_DIR)), $$(notdir $$(src)))))
216 217 218 219 220 221
    else
      # With a base dir, extract the relative portion of the path. Note that $1
      # is space sensitive and must disobey whitespace rules, and so is the
      # arguments to patsubst.
      $$(foreach src, $$($1_SOURCE_FILES), \
          $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$(src), \
222 223
              $$(patsubst %/, %, $$($1_OUTPUT_DIR)), \
              $$(patsubst $$($1_SOURCE_BASE_DIR)/%,%,$$(src)))))
224 225 226
    endif
  endif
endef