Add files from parent branch HEAD:
[pkgsrc.git] / mk / subst.mk
1 # $NetBSD: subst.mk,v 1.52 2008/01/23 01:44:28 rillig Exp $
2 #
3 # This Makefile fragment implements a general text replacement facility.
4 # Package makefiles define a ``class'', for each of which a particular
5 # substitution description can be defined.  For each class of files, a
6 # target subst-<class> is created to perform the text replacement.
7 #
8 # Package-settable variables:
9 #
10 # SUBST_CLASSES
11 #       A list of class names.  When adding new classes to this list, be
12 #       sure to append them (+=) instead of overriding them (=).
13 #
14 # SUBST_STAGE.<class>
15 #       "stage" at which we do the text replacement. Should be one of
16 #       {pre,do,post}-{extract,patch,configure,build,install}.
17 #
18 # SUBST_MESSAGE.<class>
19 #       The message to display before doing the substitution.
20 #
21 # SUBST_FILES.<class>
22 #       A list of file patterns on which to run the substitution;
23 #       the filenames are either absolute or relative to ${WRKSRC}.
24 #
25 # SUBST_SED.<class>
26 #       List of sed(1) arguments to run on the specified files. Multiple
27 #       commands can be specified using the -e option of sed.
28 #
29 # SUBST_VARS.<class>
30 #       List of variables that are substituted whenever they appear in
31 #       the form @VARNAME@. This is basically a short-cut for
32 #
33 #               -e 's,@VARNAME@,${VARNAME},g'
34 #
35 #       also taking care of (most) quoting issues. You can use both
36 #       SUBST_SED and SUBST_VARS in a single class.
37 #
38 # SUBST_FILTER_CMD.<class>
39 #       Filter used to perform the actual substitution on the specified
40 #       files.  Defaults to ${SED} ${SUBST_SED.<class>}.
41 #
42 # SUBST_POSTCMD.<class>
43 #       Command to clean up after sed(1). Defaults to ${RM} -f
44 #       $$file${_SUBST_BACKUP_SUFFIX}. For debugging, set it to ${DO_NADA}.
45 #
46 # SUBST_SKIP_TEXT_CHECK.<class>
47 #       By default, each file is checked whether it really is a text file
48 #       before any substitutions are done to it. Since that test is not
49 #       perfect, it can be disabled by setting this variable to "yes".
50 #
51 # See also:
52 #       PLIST_SUBST
53 #
54 # Keywords: subst
55 #
56
57 _VARGROUPS+=            subst
58 _PKG_VARS.subst=        SUBST_CLASSES
59 .for c in ${SUBST_CLASSES}
60 .  for pv in SUBST_STAGE SUBST_MESSAGE SUBST_FILES SUBST_SED SUBST_VARS \
61         SUBST_FILTER_CMD SUBST_POSTCMD SUBST_SKIP_TEXT_CHECK
62 _PKG_VARS.subst+=       ${pv}.${c}
63 .  endfor
64 .endfor
65
66 ECHO_SUBST_MSG?=        ${STEP_MSG}
67
68 # _SUBST_IS_TEXT_FILE returns 0 if $${file} is a text file.
69 _SUBST_IS_TEXT_FILE?= \
70         { nchars=`${WC} -c < "$$file"`;                                 \
71           notnull=`LC_ALL=C ${TR} -d '\\0' < "$$file" | ${WC} -c`;      \
72           [ "$$nchars" = "$$notnull" ] || ${FALSE} ;                    \
73         }
74
75 _SUBST_BACKUP_SUFFIX=   .subst.sav
76
77 .for _class_ in ${SUBST_CLASSES}
78 _SUBST_COOKIE.${_class_}=       ${WRKDIR}/.subst_${_class_}_done
79
80 SUBST_FILTER_CMD.${_class_}?=   ${SED} ${SUBST_SED.${_class_}}
81 SUBST_VARS.${_class_}?=         # none
82 SUBST_MESSAGE.${_class_}?=      Substituting "${_class_}" in ${SUBST_FILES.${_class_}}
83 .  for v in ${SUBST_VARS.${_class_}}
84 SUBST_FILTER_CMD.${_class_} +=  -e s,@${v}@,${${v}:S|\\|\\\\|gW:S|,|\\,|gW:S|&|\\\&|gW:Q},g
85 .  endfor
86 SUBST_POSTCMD.${_class_}?=      ${RM} -f "$$tmpfile"
87 SUBST_SKIP_TEXT_CHECK.${_class_}?=      no
88
89 .if !empty(SUBST_SKIP_TEXT_CHECK.${_class_}:M[Yy][Ee][Ss])
90 _SUBST_IS_TEXT_FILE.${_class_}= ${TRUE}
91 .else
92 _SUBST_IS_TEXT_FILE.${_class_}= ${_SUBST_IS_TEXT_FILE}
93 .endif
94
95 SUBST_TARGETS+=                 subst-${_class_}
96
97 .  if defined(SUBST_STAGE.${_class_})
98 ${SUBST_STAGE.${_class_}}: subst-${_class_}
99 .  else
100 # SUBST_STAGE.* does not need to be defined.
101 #PKG_FAIL_REASON+=      "SUBST_STAGE missing for ${_class_}."
102 .  endif
103
104 .PHONY: subst-${_class_}
105 subst-${_class_}: ${_SUBST_COOKIE.${_class_}}
106
107 ${_SUBST_COOKIE.${_class_}}:
108 .  if !empty(SUBST_MESSAGE.${_class_})
109         ${RUN} ${ECHO_SUBST_MSG} ${SUBST_MESSAGE.${_class_}:Q}
110 .  endif
111         ${RUN} cd ${WRKSRC:Q};                                          \
112         files=${SUBST_FILES.${_class_}:Q};                              \
113         for file in $$files; do                                         \
114                 case $$file in /*) ;; *) file="./$$file";; esac;        \
115                 tmpfile="$$file"${_SUBST_BACKUP_SUFFIX:Q};              \
116                 if [ ! -f "$$file" ]; then                              \
117                         ${WARNING_MSG} "[subst.mk:${_class_}] Ignoring non-existent file \"$$file\"."; \
118                 elif ${_SUBST_IS_TEXT_FILE.${_class_}}; then            \
119                         ${MV} -f "$$file" "$$tmpfile" || exit 1;        \
120                         ${SUBST_FILTER_CMD.${_class_}}                  \
121                         < "$$tmpfile"                                   \
122                         > "$$file";                                     \
123                         if ${TEST} -x "$$tmpfile"; then                 \
124                                 ${CHMOD} +x "$$file";                   \
125                         fi;                                             \
126                         if ${CMP} -s "$$tmpfile" "$$file"; then         \
127                                 ${INFO_MSG} "[subst.mk:${_class_}] Nothing changed in $$file."; \
128                                 ${MV} -f "$$tmpfile" "$$file";          \
129                         else                                            \
130                                 ${SUBST_POSTCMD.${_class_}};            \
131                                 ${ECHO} "$$file" >> ${.TARGET};         \
132                         fi;                                             \
133                 else                                                    \
134                         ${WARNING_MSG} "[subst.mk:${_class_}] Ignoring non-text file \"$$file\"."; \
135                 fi;                                                     \
136         done
137         ${RUN} ${TOUCH} ${TOUCH_FLAGS} ${.TARGET:Q}
138 .endfor