1 # 2 # Copyright (c) 2013, 2014 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 define EvalDebugWrapper 27 $(if $(DEBUG_$1), 28 $(info -------- <<< Begin expansion of $1) 29 $(info $2) 30 $(info -------- >>> End expansion of $1) 31 ) 32 33 $2 34 endef 35 36 # Helper function for SetupTextFileProcessing; adds a rule for a single file 37 # to be processed. 38 # param 1 = The namespace argument, e.g. BUILD_VERSION_FILE 39 # param 2 = the source file name (full path) 40 # param 3 = the target base directory 41 # param 4 = the target file name (possibly with a partial path) 42 define SetupSingleTextFileForProcessing 43 $(strip $3)/$(strip $4): $2 44 $(ECHO) $(LOG_INFO) "Processing $(strip $4)" 45 $(MKDIR) -p '$$(@D)' 46 $(RM) '$$@' '$$@.includes.tmp' '$$@.replacements.tmp' 47 $$($1_INCLUDES_COMMAND_LINE) < '$$<' > '$$@.includes.tmp' 48 $$($1_REPLACEMENTS_COMMAND_LINE) < '$$@.includes.tmp' > '$$@.replacements.tmp' 49 $(RM) '$$@.includes.tmp' 50 $(MV) '$$@.replacements.tmp' '$$@' 51 52 $1 += $(strip $3)/$(strip $4) 53 endef 54 55 # Setup a text file for processing, in which specified markers are replaced with 56 # a given text, or with the contents of a given file. 57 # 58 # param 1 is the name space for this setup, e.g. BUILD_VERSION_FILE 59 # param 2, 3, .. etc are named args: 60 # SOURCE_DIRS one or more directory roots to search for files to process 61 # SOURCE_FILES complete paths to one or more files to process 62 # OUTPUT_DIR the directory where we store the processed files. 63 # OUTPUT_FILE the name of the resulting file. Only allowed if processing a 64 # single file. 65 # SOURCE_BASE_DIR a common root to all SOURCE_DIRS. 66 # If specified, files will keep the path relative to the base in the 67 # OUTPUT_DIR. Otherwise, the hierarchy will be flattened into the OUTPUT_DIR. 68 # INCLUDE_FILES only include files matching these patterns (used only with 69 # SOURCE_DIRS) 70 # EXCLUDE_FILES exclude files matching these patterns (used only with 71 # SOURCE_DIRS) 72 # INCLUDES replace the occurances of a pattern with the contents of a file; 73 # one or more such include pattern, using the syntax: 74 # PLACEHOLDER => FILE_TO_INCLUDE ; ... 75 # Each PLACEHOLDER must be on a single, otherwise empty line (whitespace 76 # padding is allowed). 77 # REPLACEMENTS one or more text replacement patterns, using the syntax: 78 # PATTERN => REPLACEMENT_TEXT ; ... 79 # 80 # At least one of INCLUDES or REPLACEMENTS must be present. If both are 81 # present, then the includes will be processed first, and replacements will be 82 # done on the included fragments as well. 83 # 84 define SetupTextFileProcessing 85 $(if $(16),$(error Internal makefile error: Too many arguments to SetupTextFileProcessing, please update TextFileProcessing.gmk)) 86 $(call EvalDebugWrapper,$(strip $1),$(call SetupTextFileProcessingInner,$(strip $1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15))) 87 endef 88 89 define SetupTextFileProcessingInner 90 $(foreach i,2 3 4 5 6 7 8 9 10 11 12 13 14 15, $(if $(strip $($i)),$1_$(strip $($i)))$(NEWLINE)) 91 $(call LogSetupMacroEntry,SetupTextFileProcessing($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15)) 92 $(if $(16),$(error Internal makefile error: Too many arguments to SetupTextFileProcessing, please update TextFileProcessing.gmk)) 93 94 ifeq ($$($1_REPLACEMENTS)$$($1_INCLUDES),) 95 $$(error At least one of REPLACEMENTS or INCLUDES are required for $1) 96 endif 97 98 ifneq ($$($1_SOURCE_FILES),) 99 ifneq ($$($1_SOURCE_DIRS),) 100 $$(error Cannot use both SOURCE_FILES and SOURCE_DIRS (in $1)) 101 endif 102 ifneq ($$($1_SOURCE_BASE_DIR),) 103 $$(error Cannot use SOURCE_BASE_DIR without SOURCE_DIRS (in $1)) 104 endif 105 ifneq ($$($1_EXCLUDE_FILES)$$($1_INCLUDE_FILES),) 106 $$(error Cannot INCLUDE/EXCLUDE_FILES with SOURCE_FILES (in $1)) 107 endif 108 else 109 # Find all files in the source trees. Sort to remove duplicates. 110 $$(foreach src, $$($1_SOURCE_DIRS), $$(if $$(wildcard $$(src)), , \ 111 $$(error SOURCE_DIRS contains missing directory $$(src) (in $1)))) 112 ifneq ($$($1_SOURCE_BASE_DIR),) 113 $$(foreach src, $$($1_SOURCE_DIRS), \ 114 $$(if $$(findstring $$($1_SOURCE_BASE_DIR), $$(src)), , \ 115 $$(error SOURCE_DIRS contains directory $$(src) outside \ 116 SOURCE_BASE_DIR $$($1_SOURCE_BASE_DIR) (in $1)))) 117 endif 118 $1_SOURCE_FILES := $$(sort $$(call CacheFind,$$($1_SOURCE_DIRS))) 119 $1_EXCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_EXCLUDE_FILES))) 120 $1_INCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_INCLUDE_FILES))) 121 $1_SOURCE_FILES := $$(filter-out $$($1_EXCLUDE_FILES),$$($1_SOURCE_FILES)) 122 ifneq (,$$(strip $$($1_INCLUDE_FILES))) 123 $1_SOURCE_FILES := $$(filter $$($1_INCLUDE_FILES),$$($1_SOURCE_FILES)) 124 endif 125 ifeq (,$$($1_SOURCE_FILES)) 126 $$(info No sources found for $1 when looking inside the dirs $$($1_SRC)) 127 endif 128 endif 129 130 ifneq ($$($1_REPLACEMENTS),) 131 # We have a replacement request, prepare it for the recipe 132 ifneq ($$(findstring /,$$($1_REPLACEMENTS)),) 133 # Cannot use / as separator 134 ifneq ($$(findstring @,$$($1_REPLACEMENTS)),) 135 # Cannot use @ as separator 136 ifneq ($$(findstring |,$$($1_REPLACEMENTS)),) 137 # Cannot use | as separator 138 ifneq ($$(findstring !,$$($1_REPLACEMENTS)),) 139 # Cannot use ! as separator. Give up. 140 $$(error No suitable sed separator can be found for $1. Tested /, @, | and !) 141 else 142 $1_SEP := ! 143 endif 144 else 145 $1_SEP := | 146 endif 147 else 148 $1_SEP := @ 149 endif 150 else 151 $1_SEP := / 152 endif 153 154 # If we have a trailing "=>" (i.e. last rule replaces with empty, and is not 155 # terminated by a ;), add a trailing ; to minimize the number of corner 156 # cases in the hairy subst expression.. 157 ifeq ($$(lastword $$($1_REPLACEMENTS)), =>) 158 $1_REPLACEMENTS += ; 159 endif 160 161 # If we have a trailing ";", add a dummy replacement, since there is no easy 162 # way to delete the last word in make. 163 ifeq ($$(lastword $$($1_REPLACEMENTS)), ;) 164 $1_REPLACEMENTS += DUMMY_REPLACEMENT => DUMMY_REPLACEMENT 165 endif 166 167 # Convert the REPLACEMENTS syntax ( A => B ; C => D ; ...) to a sed command 168 # line (-e "s/A/B/" -e "s/C/D/" ...), basically by replacing '=>' with '/' 169 # and ';' with '/" -e "s/', and adjusting for edge cases. 170 $1_REPLACEMENTS_COMMAND_LINE := $(SED) -e "s$$($1_SEP)$$(subst $$(SPACE);$$(SPACE),$$($1_SEP)" \ 171 -e "s$$($1_SEP),$$(subst $$(SPACE)=>$$(SPACE),$$($1_SEP),$$(subst $$(SPACE)=>$$(SPACE);$$(SPACE),//" \ 172 -e "s$$($1_SEP),$$(strip $$($1_REPLACEMENTS)))))$$($1_SEP)" 173 else 174 # We don't have any replacements, just pipe the file through cat. 175 $1_REPLACEMENTS_COMMAND_LINE := $(CAT) 176 endif 177 178 ifneq ($$($1_INCLUDES),) 179 # We have a include request, prepare it for the recipe. 180 # Convert an INCLUDE like this PATTERN_1 => file1 ; PATTERN_2 => file2 ; 181 # into an awk script fragment like this: 182 # { 183 # if (matches("PATTERN_1")) { include("file1") } else 184 # if (matches("PATTERN_2")) { include("file2") } else 185 # print 186 # } 187 188 $1_INCLUDES_HEADER_AWK := \ 189 function matches(pattern) { return ($$$$0 ~ "^[ \t]*" pattern "[ \t]*$$$$") } \ 190 function include(filename) { while ((getline < filename) == 1) print ; close(filename) } 191 $1_INCLUDES_PARTIAL_AWK := $$(subst $$(SPACE);,,$$(subst $$(SPACE)=>$$(SPACE),"$$(RIGHT_PAREN)$$(RIGHT_PAREN) \ 192 { include$$(LEFT_PAREN)",$$(subst $$(SPACE);$$(SPACE),"$$(RIGHT_PAREN) } \ 193 else if $$(LEFT_PAREN)matches$$(LEFT_PAREN)",$$(strip $$($1_INCLUDES))))) 194 $1_INCLUDES_COMMAND_LINE := $(NAWK) '$$($1_INCLUDES_HEADER_AWK) \ 195 { if (matches("$$($1_INCLUDES_PARTIAL_AWK)") } else print }' 196 else 197 # We don't have any includes, just pipe the file through cat. 198 $1_INCLUDES_COMMAND_LINE := $(CAT) 199 endif 200 201 # Reset target list before populating it 202 $1 := 203 204 ifneq ($$($1_OUTPUT_FILE),) 205 ifneq ($$(words $$($1_SOURCE_FILES)), 1) 206 $$(error Cannot use OUTPUT_FILE for more than one source file (in $1)) 207 endif 208 209 # Note that $1 is space sensitive and must disobey whitespace rules 210 $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$($1_SOURCE_FILES), \ 211 $$(dir $$($1_OUTPUT_FILE)), $$(notdir $$($1_OUTPUT_FILE)))) 212 else 213 ifeq ($$($1_OUTPUT_DIR),) 214 $$(error Neither OUTPUT_FILE nor OUTPUT_DIR was specified (in $1)) 215 endif 216 217 # Now call add_native_source for each source file we are going to process. 218 ifeq ($$($1_SOURCE_BASE_DIR),) 219 # With no base dir specified, put all files in target dir, flattening any 220 # hierarchies. Note that $1 is space sensitive and must disobey whitespace 221 # rules. 222 $$(foreach src, $$($1_SOURCE_FILES), \ 223 $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$(src), \ 224 $$($1_OUTPUT_DIR), $$(notdir $$(src))))) 225 else 226 # With a base dir, extract the relative portion of the path. Note that $1 227 # is space sensitive and must disobey whitespace rules, and so is the 228 # arguments to patsubst. 229 $$(foreach src, $$($1_SOURCE_FILES), \ 230 $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$(src), \ 231 $$($1_OUTPUT_DIR), $$(patsubst $$($1_SOURCE_BASE_DIR)/%,%,$$(src))))) 232 endif 233 endif 234 endef