Home | History | Annotate | Line # | Download | only in unit-tests
      1 # $NetBSD: varname-makeflags.mk,v 1.8 2023/06/01 07:27:30 rillig Exp $
      2 #
      3 # Tests for the environment variable 'MAKEFLAGS', from which additional
      4 # command line arguments are read before the actual command line arguments.
      5 #
      6 # After reading the makefiles and before making the targets, the arguments
      7 # that were collected in '.MAKEFLAGS' and '.MAKEOVERRIDES' are written back to
      8 # the environment variable 'MAKEFLAGS'.
      9 
     10 all: spaces_stage_0 dollars_stage_0 append_stage_0 override_stage_0
     11 
     12 
     13 .if !make(*stage*)
     14 
     15 # The unit tests are run with an almost empty environment.  In particular,
     16 # the variable MAKEFLAGS is not set.
     17 .  if ${MAKEFLAGS:Uundefined} != "undefined"
     18 .    error
     19 .  endif
     20 
     21 # The special variable .MAKEFLAGS is influenced though.
     22 # See varname-dot-makeflags.mk for more details.
     23 .  if ${.MAKEFLAGS} != " -r -k"
     24 .    error
     25 .  endif
     26 
     27 
     28 # In POSIX mode, the environment variable MAKEFLAGS can contain letters only,
     29 # for compatibility.  These letters are exploded to form regular options.
     30 OUTPUT!=	env MAKEFLAGS=ikrs ${MAKE} -f /dev/null -v .MAKEFLAGS
     31 .  if ${OUTPUT} != " -i -k -r -s -V .MAKEFLAGS"
     32 .    error
     33 .  endif
     34 
     35 # As soon as there is a single non-alphabetic character in the environment
     36 # variable MAKEFLAGS, it is no longer split.  In this example, the word
     37 # "d0ikrs" is treated as a target, but the option '-v' prevents any targets
     38 # from being built.
     39 OUTPUT!=	env MAKEFLAGS=d0ikrs ${MAKE} -r -f /dev/null -v .MAKEFLAGS
     40 .  if ${OUTPUT} != " -r -V .MAKEFLAGS"
     41 .    error ${OUTPUT}
     42 .  endif
     43 
     44 .endif
     45 
     46 
     47 # When options are parsed, the option and its argument are appended as
     48 # separate words to the MAKEFLAGS for the child processes.  Special characters
     49 # in the option arguments are not quoted though.
     50 spaces_stage_0:
     51 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
     52 	@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
     53 	@${MAKE} -f ${MAKEFILE} spaces_stage_1 -d00000 -D"VARNAME WITH SPACES"
     54 
     55 # At this point, the 'VARNAME WITH SPACES' is no longer recognizable as a
     56 # single command line argument.  In practice, variable names don't contain
     57 # spaces.
     58 spaces_stage_1:
     59 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
     60 	@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
     61 
     62 
     63 # Demonstrate that '$' characters are altered when they are passed on to child
     64 # make processes via MAKEFLAGS.
     65 dollars_stage_0:
     66 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
     67 
     68 	# The '$$$$' becomes a literal '$$' when building the '${MAKE}'
     69 	# command line, making the actual argument 'DOLLARS=$${varname}'.
     70 	# At this stage, MAKEFLAGS is not yet involved.
     71 	@${MAKE} -f ${MAKEFILE} dollars_stage_1 DOLLARS='$$$${varname}'
     72 
     73 .if make(dollars_stage_1)
     74 # At this point, the variable 'DOLLARS' contains '$${varname}', which
     75 # evaluates to a literal '$' followed by '{varname}'.
     76 .  if ${DOLLARS} != "\${varname}"
     77 .    error
     78 .  endif
     79 .endif
     80 dollars_stage_1:
     81 	# At this point, the stage 1 make provides the environment variable
     82 	# 'MAKEFLAGS' to its child processes, even if the child process is not
     83 	# another make.
     84 	#
     85 	# expect: dollars_stage_1: env MAKEFLAGS=< -r -k DOLLARS=\$\{varname\}>
     86 	#
     87 	# The 'DOLLARS=\$\{varname\}' assignment is escaped so that the stage
     88 	# 2 make will see it as a single word.
     89 	@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
     90 
     91 	# At this point, evaluating the environment variable 'MAKEFLAGS' leads
     92 	# to strange side effects as the string '\$\{varname\}' is interpreted
     93 	# as:
     94 	#
     95 	#	\		a literal string of a single backslash
     96 	#	$\		the value of the variable named '\'
     97 	#	{varname\}	a literal string
     98 	#
     99 	# Since the variable named '\' is not defined, the resulting value is
    100 	# '\{varname\}'.  Make doesn't handle isolated '$' characters in
    101 	# strings well, instead each '$' has to be part of a '$$' or be part
    102 	# of a subexpression like '${VAR}'.
    103 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    104 
    105 	# The modifier ':q' preserves a '$$' in an expression value instead of
    106 	# expanding it to a single '$', but it's already too late, as that
    107 	# modifier applies after the expression has been evaluated.  Except
    108 	# for debug logging, there is no way to process strings that contain
    109 	# isolated '$'.
    110 	@echo '$@: MAKEFLAGS:q=<'${MAKEFLAGS:q}'>'
    111 
    112 	@${MAKE} -f ${MAKEFILE} dollars_stage_2
    113 
    114 .if make(dollars_stage_2)
    115 # At this point, the variable 'DOLLARS' contains '${varname}', and since
    116 # 'varname' is undefined, that expression evaluates to an empty string.
    117 .  if ${DOLLARS} != ""
    118 .    error
    119 .  endif
    120 varname=	varvalue
    121 .  if ${DOLLARS} != "varvalue"
    122 .    error
    123 .  endif
    124 .  undef varname
    125 .endif
    126 dollars_stage_2:
    127 	@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
    128 	@echo '$@: dollars=<'${DOLLARS:Q}'>'
    129 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    130 	@${MAKE} -f ${MAKEFILE} dollars_stage_3
    131 
    132 dollars_stage_3:
    133 	@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
    134 	@echo '$@: dollars=<'${DOLLARS:Uundefined:Q}'>'
    135 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    136 
    137 
    138 # Demonstrates in which exact order the MAKEFLAGS are built from the parent
    139 # MAKEFLAGS and the flags from the command line, in particular that variable
    140 # assignments are passed at the end, after the options.
    141 append_stage_0:
    142 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    143 	@${MAKE} -Dbefore-0 -f ${MAKEFILE} append_stage_1 VAR0=value -Dafter-0
    144 
    145 append_stage_1:
    146 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    147 	@${MAKE} -Dbefore-1 -f ${MAKEFILE} append_stage_2 VAR1=value -Dafter-1
    148 
    149 append_stage_2:
    150 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    151 	@${MAKE} -Dbefore-2 -f ${MAKEFILE} append_stage_3 VAR2=value -Dafter-2
    152 
    153 append_stage_3:
    154 	@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    155 
    156 
    157 # Demonstrates the implementation details of 'MAKEFLAGS', in particular that
    158 # it is an environment variable rather than a global variable.
    159 override_stage_0:
    160 	@${MAKE} -f ${MAKEFILE} STAGE=1 VAR=value override_stage_1
    161 
    162 .if make(override_stage_1)
    163 # While parsing the makefiles, 'MAKEFLAGS' is the value of the environment
    164 # variable, in this case provided by stage 0.
    165 .  if ${MAKEFLAGS:M*} != "-r -k"
    166 .    error
    167 .  endif
    168 MAKEFLAGS=	overridden	# temporarily override it
    169 .  if ${MAKEFLAGS} != "overridden"
    170 .    error
    171 .  endif
    172 .undef MAKEFLAGS		# make the environment variable visible again
    173 .  if ${MAKEFLAGS:M*} != "-r -k"
    174 .    error
    175 .  endif
    176 .endif
    177 override_stage_1:
    178 	@echo '$@: run MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
    179 	@${MAKE} -f ${MAKEFILE} STAGE=2 override_stage_2
    180 
    181 override_stage_2:
    182 	@echo '$@: STAGE=<${STAGE}> VAR=<${VAR}>'
    183