TextFileProcessing.gmk revision 1233:86ff430e9a2b
117680Spst# 2190207Srpaulo# Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. 3127668Sbms# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4172683Smlaier# 5111726Sfenner# This code is free software; you can redistribute it and/or modify it 6172683Smlaier# under the terms of the GNU General Public License version 2 only, as 7172683Smlaier# published by the Free Software Foundation. Oracle designates this 8127668Sbms# particular file as subject to the "Classpath" exception as provided 9127668Sbms# by Oracle in the LICENSE file that accompanied this code. 10127668Sbms# 11127668Sbms# This code is distributed in the hope that it will be useful, but WITHOUT 12127668Sbms# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1375115Sfenner# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14172683Smlaier# version 2 for more details (a copy is included in the LICENSE file that 15172683Smlaier# accompanied this code). 16127668Sbms# 17127668Sbms# You should have received a copy of the GNU General Public License version 18127668Sbms# 2 along with this work; if not, write to the Free Software Foundation, 19127668Sbms# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20127668Sbms# 21127668Sbms# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22172683Smlaier# or visit www.oracle.com if you need additional information or have any 23172683Smlaier# questions. 24172683Smlaier# 25172683Smlaier 26172683Smlaierifeq (,$(_MAKEBASE_GMK)) 27172683Smlaier $(error You must include MakeBase.gmk prior to including TextFileProcessing.gmk) 28127668Sbmsendif 2975115Sfenner 30172683Smlaier# Helper function for SetupTextFileProcessing; adds a rule for a single file 31172683Smlaier# to be processed. 32172683Smlaier# param 1 = The namespace argument, e.g. BUILD_VERSION_FILE 33172683Smlaier# param 2 = the source file name (full path) 34172683Smlaier# param 3 = the target base directory 35172683Smlaier# param 4 = the target file name (possibly with a partial path) 36172683Smlaierdefine SetupSingleTextFileForProcessing 37172683Smlaier $(strip $3)/$(strip $4): $2 38172683Smlaier $(ECHO) $(LOG_INFO) "Processing $(strip $4)" 39172683Smlaier $(MKDIR) -p '$$(@D)' 40172683Smlaier $(RM) '$$@' '$$@.includes.tmp' '$$@.replacements.tmp' 41172683Smlaier $$($1_INCLUDES_COMMAND_LINE) < '$$<' > '$$@.includes.tmp' 42172683Smlaier $$($1_REPLACEMENTS_COMMAND_LINE) < '$$@.includes.tmp' > '$$@.replacements.tmp' 43172683Smlaier $(RM) '$$@.includes.tmp' 44172683Smlaier $(MV) '$$@.replacements.tmp' '$$@' 45172683Smlaier 46172683Smlaier $1 += $(strip $3)/$(strip $4) 47172683Smlaierendef 48172683Smlaier 49172683Smlaier# Setup make rules for processing one or more text files, in which specified 50172683Smlaier# markers are replaced with a given text, or with the contents of a given file. 51172683Smlaier# 52172683Smlaier# Parameter 1 is the name of the rule. This name is used as variable prefix, 53172683Smlaier# and the targets generated are listed in a variable by that name. 54127668Sbms# 55172683Smlaier# Remaining parameters are named arguments. These include: 56127668Sbms# SOURCE_DIRS one or more directory roots to search for files to process 57127668Sbms# SOURCE_FILES complete paths to one or more files to process 58127668Sbms# OUTPUT_DIR the directory where we store the processed files. 59127668Sbms# OUTPUT_FILE the name of the resulting file. Only allowed if processing a 6075115Sfenner# single file. 6175115Sfenner# SOURCE_BASE_DIR a common root to all SOURCE_DIRS. 62172683Smlaier# If specified, files will keep the path relative to the base in the 63172683Smlaier# OUTPUT_DIR. Otherwise, the hierarchy will be flattened into the OUTPUT_DIR. 64172683Smlaier# INCLUDE_FILES only include files matching these patterns (used only with 65172683Smlaier# SOURCE_DIRS) 66172683Smlaier# EXCLUDE_FILES exclude files matching these patterns (used only with 67172683Smlaier# SOURCE_DIRS) 68172683Smlaier# INCLUDES replace the occurances of a pattern with the contents of a file; 69172683Smlaier# one or more such include pattern, using the syntax: 70172683Smlaier# PLACEHOLDER => FILE_TO_INCLUDE ; ... 71172683Smlaier# Each PLACEHOLDER must be on a single, otherwise empty line (whitespace 72172683Smlaier# padding is allowed). 73172683Smlaier# REPLACEMENTS one or more text replacement patterns, using the syntax: 74172683Smlaier# PATTERN => REPLACEMENT_TEXT ; ... 75172683Smlaier# 76172683Smlaier# At least one of INCLUDES or REPLACEMENTS must be present. If both are 77172683Smlaier# present, then the includes will be processed first, and replacements will be 78172683Smlaier# done on the included fragments as well. 79172683Smlaier# 80172683Smlaierdefine SetupTextFileProcessing 81172683Smlaier $(if $(16),$(error Internal makefile error: Too many arguments to SetupTextFileProcessing, please update TextFileProcessing.gmk)) 82172683Smlaier $(call EvalDebugWrapper,$(strip $1),$(call SetupTextFileProcessingInner,$(strip $1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15))) 83172683Smlaierendef 84172683Smlaier 85172683Smlaierdefine SetupTextFileProcessingInner 86172683Smlaier $(foreach i,2 3 4 5 6 7 8 9 10 11 12 13 14 15, $(if $(strip $($i)),$1_$(strip $($i)))$(NEWLINE)) 87172683Smlaier $(call LogSetupMacroEntry,SetupTextFileProcessing($1),$2,$3,$4,$5,$6,$7,$8,$9,$(10),$(11),$(12),$(13),$(14),$(15)) 88172683Smlaier $(if $(16),$(error Internal makefile error: Too many arguments to SetupTextFileProcessing, please update TextFileProcessing.gmk)) 89172683Smlaier 90172683Smlaier ifeq ($$($1_REPLACEMENTS)$$($1_INCLUDES),) 91172683Smlaier $$(error At least one of REPLACEMENTS or INCLUDES are required for $1) 92172683Smlaier endif 93172683Smlaier 94172683Smlaier ifneq ($$($1_SOURCE_FILES),) 95127668Sbms ifneq ($$($1_SOURCE_DIRS),) 96172683Smlaier $$(error Cannot use both SOURCE_FILES and SOURCE_DIRS (in $1)) 97172683Smlaier endif 98172683Smlaier ifneq ($$($1_SOURCE_BASE_DIR),) 99127668Sbms $$(error Cannot use SOURCE_BASE_DIR without SOURCE_DIRS (in $1)) 100127668Sbms endif 101127668Sbms ifneq ($$($1_EXCLUDE_FILES)$$($1_INCLUDE_FILES),) 10275115Sfenner $$(error Cannot INCLUDE/EXCLUDE_FILES with SOURCE_FILES (in $1)) 103127668Sbms endif 104127668Sbms else 105127668Sbms # Find all files in the source trees. Sort to remove duplicates. 106127668Sbms $$(foreach src, $$($1_SOURCE_DIRS), $$(if $$(wildcard $$(src)), , \ 107127668Sbms $$(error SOURCE_DIRS contains missing directory $$(src) (in $1)))) 108127668Sbms ifneq ($$($1_SOURCE_BASE_DIR),) 109172683Smlaier $$(foreach src, $$($1_SOURCE_DIRS), \ 110127668Sbms $$(if $$(findstring $$($1_SOURCE_BASE_DIR), $$(src)), , \ 111127668Sbms $$(error SOURCE_DIRS contains directory $$(src) outside \ 112172683Smlaier SOURCE_BASE_DIR $$($1_SOURCE_BASE_DIR) (in $1)))) 113127668Sbms endif 114127668Sbms $1_SOURCE_FILES := $$(sort $$(call CacheFind,$$($1_SOURCE_DIRS))) 11575115Sfenner $1_EXCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_EXCLUDE_FILES))) 116127668Sbms $1_INCLUDE_FILES:=$$(foreach i,$$($1_SOURCE_DIRS),$$(addprefix $$i/,$$($1_INCLUDE_FILES))) 117172683Smlaier $1_SOURCE_FILES := $$(filter-out $$($1_EXCLUDE_FILES),$$($1_SOURCE_FILES)) 118172683Smlaier ifneq (,$$(strip $$($1_INCLUDE_FILES))) 119127668Sbms $1_SOURCE_FILES := $$(filter $$($1_INCLUDE_FILES),$$($1_SOURCE_FILES)) 120127668Sbms endif 121127668Sbms ifeq (,$$($1_SOURCE_FILES)) 122127668Sbms $$(info No sources found for $1 when looking inside the dirs $$($1_SRC)) 12375115Sfenner endif 124172683Smlaier endif 125127668Sbms 126127668Sbms ifneq ($$($1_REPLACEMENTS),) 127127668Sbms # We have a replacement request, prepare it for the recipe 128127668Sbms ifneq ($$(findstring /,$$($1_REPLACEMENTS)),) 12975115Sfenner # Cannot use / as separator 13075115Sfenner ifneq ($$(findstring @,$$($1_REPLACEMENTS)),) 131127668Sbms # Cannot use @ as separator 132172683Smlaier ifneq ($$(findstring |,$$($1_REPLACEMENTS)),) 133127668Sbms # Cannot use | as separator 134127668Sbms ifneq ($$(findstring !,$$($1_REPLACEMENTS)),) 135172683Smlaier # Cannot use ! as separator. Give up. 136127668Sbms $$(error No suitable sed separator can be found for $1. Tested /, @, | and !) 137172683Smlaier else 138172683Smlaier $1_SEP := ! 139172683Smlaier endif 140172683Smlaier else 141172683Smlaier $1_SEP := | 142172683Smlaier endif 143172683Smlaier else 144172683Smlaier $1_SEP := @ 145172683Smlaier endif 146172683Smlaier else 147172683Smlaier $1_SEP := / 148172683Smlaier endif 149172683Smlaier 15075115Sfenner # If we have a trailing "=>" (i.e. last rule replaces with empty, and is not 151172683Smlaier # terminated by a ;), add a trailing ; to minimize the number of corner 152172683Smlaier # cases in the hairy subst expression.. 15375115Sfenner ifeq ($$(lastword $$($1_REPLACEMENTS)), =>) 15475115Sfenner $1_REPLACEMENTS += ; 155172683Smlaier endif 156172683Smlaier 157172683Smlaier # If we have a trailing ";", add a dummy replacement, since there is no easy 158172683Smlaier # way to delete the last word in make. 159172683Smlaier ifeq ($$(lastword $$($1_REPLACEMENTS)), ;) 160127668Sbms $1_REPLACEMENTS += DUMMY_REPLACEMENT => DUMMY_REPLACEMENT 16175115Sfenner endif 162172683Smlaier 163172683Smlaier # Convert the REPLACEMENTS syntax ( A => B ; C => D ; ...) to a sed command 164172683Smlaier # line (-e "s/A/B/" -e "s/C/D/" ...), basically by replacing '=>' with '/' 165172683Smlaier # and ';' with '/" -e "s/', and adjusting for edge cases. 166172683Smlaier $1_REPLACEMENTS_COMMAND_LINE := $(SED) -e "s$$($1_SEP)$$(subst $$(SPACE);$$(SPACE),$$($1_SEP)" \ 167172683Smlaier -e "s$$($1_SEP),$$(subst $$(SPACE)=>$$(SPACE),$$($1_SEP),$$(subst $$(SPACE)=>$$(SPACE);$$(SPACE),//" \ 168172683Smlaier -e "s$$($1_SEP),$$(strip $$($1_REPLACEMENTS)))))$$($1_SEP)" 169172683Smlaier else 170172683Smlaier # We don't have any replacements, just pipe the file through cat. 171172683Smlaier $1_REPLACEMENTS_COMMAND_LINE := $(CAT) 172172683Smlaier endif 173172683Smlaier 174172683Smlaier ifneq ($$($1_INCLUDES),) 175172683Smlaier # We have a include request, prepare it for the recipe. 176172683Smlaier # Convert an INCLUDE like this PATTERN_1 => file1 ; PATTERN_2 => file2 ; 177172683Smlaier # into an awk script fragment like this: 17875115Sfenner # { 179172683Smlaier # if (matches("PATTERN_1")) { include("file1") } else 180172683Smlaier # if (matches("PATTERN_2")) { include("file2") } else 181172683Smlaier # print 182172683Smlaier # } 183172683Smlaier 184172683Smlaier $1_INCLUDES_HEADER_AWK := \ 185172683Smlaier function matches(pattern) { return ($$$$0 ~ "^[ \t]*" pattern "[ \t]*$$$$") } \ 18675115Sfenner function include(filename) { while ((getline < filename) == 1) print ; close(filename) } 187172683Smlaier $1_INCLUDES_PARTIAL_AWK := $$(subst $$(SPACE);,,$$(subst $$(SPACE)=>$$(SPACE),"$$(RIGHT_PAREN)$$(RIGHT_PAREN) \ 188172683Smlaier { include$$(LEFT_PAREN)",$$(subst $$(SPACE);$$(SPACE),"$$(RIGHT_PAREN) } \ 189172683Smlaier else if $$(LEFT_PAREN)matches$$(LEFT_PAREN)",$$(strip $$($1_INCLUDES))))) 190172683Smlaier $1_INCLUDES_COMMAND_LINE := $(NAWK) '$$($1_INCLUDES_HEADER_AWK) \ 191172683Smlaier { if (matches("$$($1_INCLUDES_PARTIAL_AWK)") } else print }' 192172683Smlaier else 193172683Smlaier # We don't have any includes, just pipe the file through cat. 194172683Smlaier $1_INCLUDES_COMMAND_LINE := $(CAT) 195172683Smlaier endif 196172683Smlaier 197172683Smlaier # Reset target list before populating it 198172683Smlaier $1 := 199172683Smlaier 200172683Smlaier ifneq ($$($1_OUTPUT_FILE),) 201172683Smlaier ifneq ($$(words $$($1_SOURCE_FILES)), 1) 202172683Smlaier $$(error Cannot use OUTPUT_FILE for more than one source file (in $1)) 203172683Smlaier endif 204172683Smlaier 205172683Smlaier # Note that $1 is space sensitive and must disobey whitespace rules 206172683Smlaier $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$($1_SOURCE_FILES), \ 207172683Smlaier $$(dir $$($1_OUTPUT_FILE)), $$(notdir $$($1_OUTPUT_FILE)))) 208172683Smlaier else 209172683Smlaier ifeq ($$($1_OUTPUT_DIR),) 210172683Smlaier $$(error Neither OUTPUT_FILE nor OUTPUT_DIR was specified (in $1)) 211172683Smlaier endif 212172683Smlaier 213172683Smlaier # Now call add_native_source for each source file we are going to process. 214172683Smlaier ifeq ($$($1_SOURCE_BASE_DIR),) 215172683Smlaier # With no base dir specified, put all files in target dir, flattening any 216172683Smlaier # hierarchies. Note that $1 is space sensitive and must disobey whitespace 217172683Smlaier # rules. 218172683Smlaier $$(foreach src, $$($1_SOURCE_FILES), \ 219172683Smlaier $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$(src), \ 220172683Smlaier $$($1_OUTPUT_DIR), $$(notdir $$(src))))) 221172683Smlaier else 222127668Sbms # With a base dir, extract the relative portion of the path. Note that $1 223127668Sbms # is space sensitive and must disobey whitespace rules, and so is the 224127668Sbms # arguments to patsubst. 225127668Sbms $$(foreach src, $$($1_SOURCE_FILES), \ 226127668Sbms $$(eval $$(call SetupSingleTextFileForProcessing,$1, $$(src), \ 227172683Smlaier $$($1_OUTPUT_DIR), $$(patsubst $$($1_SOURCE_BASE_DIR)/%,%,$$(src))))) 228127668Sbms endif 229172683Smlaier endif 230172683Smlaierendef 231172683Smlaier