From adc42d44162900a586e6e15c876fcc85be30d2c7 Mon Sep 17 00:00:00 2001 From: rillig Date: Sat, 29 Jan 2022 00:52:53 +0000 Subject: tests/make: extend and isolate tests for target-local variables Reusing the target var-scope-local.o for several tests made the test more difficult to understand than necessary. The test names '2' and '3' didn't convey any meaning. Instead, add more test targets that are named after what they test. Add tests for each of the 5 variable assignment operators, to demonstrate an inconsistency between '+=' and '?='. Add tests for the built-in target-local variables as well and explain the general concepts, in particular the exact point where target-local expressions are expanded. The lines in the expected output file are not generated in the same order as they appear in the makefile, so allow the 'expect' lines in non-linear order, in check-expect.lua. --- usr.bin/make/unit-tests/check-expect.lua | 5 +- usr.bin/make/unit-tests/var-scope-local.exp | 25 +++- usr.bin/make/unit-tests/var-scope-local.mk | 192 +++++++++++++++++++++++----- 3 files changed, 184 insertions(+), 38 deletions(-) (limited to 'usr.bin/make') diff --git a/usr.bin/make/unit-tests/check-expect.lua b/usr.bin/make/unit-tests/check-expect.lua index 2aaf31f9a6d..44c867dd321 100644 --- a/usr.bin/make/unit-tests/check-expect.lua +++ b/usr.bin/make/unit-tests/check-expect.lua @@ -1,5 +1,5 @@ #! /usr/bin/lua --- $NetBSD: check-expect.lua,v 1.1 2022/01/15 12:35:18 rillig Exp $ +-- $NetBSD: check-expect.lua,v 1.2 2022/01/29 00:52:53 rillig Exp $ --[[ @@ -82,6 +82,9 @@ local function check_mk(mk_fname) mk_fname, mk_lineno, exp_fname, prev_expect_line + 1, text) end end + if mk_line:match("^#%s*expect%-reset$") then + prev_expect_line = 0 + end ---@param text string for offset, text in mk_line:gmatch("#%s*expect([+%-]%d+):%s*(.*)") do diff --git a/usr.bin/make/unit-tests/var-scope-local.exp b/usr.bin/make/unit-tests/var-scope-local.exp index ec051d0f492..051ede288bc 100644 --- a/usr.bin/make/unit-tests/var-scope-local.exp +++ b/usr.bin/make/unit-tests/var-scope-local.exp @@ -1,10 +1,21 @@ +Global: .ALLTARGETS = one +Global: .ALLTARGETS = one two +Var_Parse: ${.MAKE.TARGET_LOCAL_VARIABLES} (eval) +Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored +Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored +Global: one two = +Global: one two = three +Global: .MAKEFLAGS = -r -k -d v -d +Global: .MAKEFLAGS = -r -k -d v -d 0 : Making var-scope-local.c out of nothing. : Making var-scope-local.o from var-scope-local.c. -: Making basename "var-scope-local.o" in "." from "var-scope-local.c" in "." VAR="local". -: Making var-scope-local2.c out of nothing. -: Making var-scope-local2.o from var-scope-local2.c. -: Making basename "var-scope-local2.o" in "." from "var-scope-local2.c" in "." VAR="local to var-scope-local2.o". -: Making var-scope-local3.c out of nothing. -: var-scope-local3.o uses .USE VAR="global+local" -: all overwritten VAR="global" +: Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".". +: Making var-scope-local-assign.o with VAR="local". +: Making var-scope-local-append.o with VAR="local to var-scope-local-append.o". +: Making var-scope-local-append-global.o with VAR="global+local". +: Making var-scope-local-default.o with VAR="global". +: Making var-scope-local-subst.o with VAR="global+local". +: Making var-scope-local-shell.o with VAR="output". +: var-scope-local-use.o uses .USE VAR="global" +: all overwritten exit status 0 diff --git a/usr.bin/make/unit-tests/var-scope-local.mk b/usr.bin/make/unit-tests/var-scope-local.mk index bd7b75d7000..91a5f525e85 100644 --- a/usr.bin/make/unit-tests/var-scope-local.mk +++ b/usr.bin/make/unit-tests/var-scope-local.mk @@ -1,16 +1,67 @@ -# $NetBSD: var-scope-local.mk,v 1.2 2022/01/27 06:56:27 sjg Exp $ +# $NetBSD: var-scope-local.mk,v 1.3 2022/01/29 00:52:53 rillig Exp $ # -# Tests for target-local variables, such as ${.TARGET} or $@. +# Tests for target-local variables, such as ${.TARGET} or $@. These variables +# are relatively short-lived as they are created just before making the +# target. In contrast, global variables are typically created when the +# makefiles are read in. +# +# The 7 built-in target-local variables are listed in the manual page. They +# are defined just before the target is actually made. Additional +# target-local variables can be defined in dependency lines like +# 'target: VAR=value', one at a time. -# TODO: Implementation +.MAIN: all -# Ensure that the name of the variable is exactly the given one. -# The variable "@" is an alias for ".TARGET", so the implementation might +# The target-local variables can be used in expressions, just like other +# variables. When these expressions are evaluated outside of a target, these +# expressions are not yet expanded, instead their text is preserved, to allow +# these expressions to expand right in time when the target-local variables +# are actually set. +# +# Conditions like the ones below are evaluated in the scope of the command +# line, which means that variables from the command line, from the global +# scope and from the environment are resolved, in this order (but see the +# command line option '-e'). In that phase, expressions involving +# target-local variables need to be preserved, including the exact names of +# the variables. +# +# Each of the built-in target-local variables has two equivalent names, for +# example '@' is equivalent to '.TARGET'. The implementation might # canonicalize these aliases at some point, and that might be surprising. # This aliasing happens for single-character variable names like $@ or $< # (see VarFind, CanonicalVarname), but not for braced or parenthesized # expressions like ${@}, ${.TARGET} ${VAR:Mpattern} (see Var_Parse, # ParseVarname). +# +# In the following condition, make does not expand '$@' but instead changes it +# to the long-format alias '$(.TARGET)'; note that the alias is not written +# with braces, as would be common in BSD makefiles, but with parentheses. +# This alternative form behaves equivalently though. +.if $@ != "\$\(.TARGET)" +. error +.endif +# In the long form of writing a target-local variable, the expression is +# preserved exactly as written, no matter whether with '{' or '('. +.if ${@} != "\$\{@}" +. error +.endif +.if $(@) != "\$\(@)" +. error +.endif +# If the variable expression contains modifiers, the behavior depends on the +# actual modifiers. The modifier ':M' keeps the expression in the state +# 'undefined'. Since the expression is still undefined after evaluating all +# the modifiers, the value of the expression is discarded and the expression +# text is used instead. This preserves the expressions based on target-local +# variables as long as possible. +.if ${@:M*} != "\$\{@:M*}" +. error +.endif +# In the following examples, the expressions are based on target-local +# variables but use the modifier ':L', which turns an undefined expression +# into a defined one. At the end of evaluating the expression, the state of +# the expression is not 'undefined' anymore, and the value of the expression +# is the name of the variable, since that's what the modifier ':L' does. .if ${@:L} != "@" . error .endif @@ -24,45 +75,126 @@ . error .endif -all: + +# Additional target-local variables may be defined in dependency lines. +.MAKEFLAGS: -dv +# In the following line, the ':=' may either be interpreted as an assignment +# operator or as the dependency operator ':', followed by an empty variable +# name and the assignment operator '='. It is the latter since in an +# assignment, the left-hand side must be at most a single word. The empty +# variable name is expanded twice, once for 'one' and once for 'two'. +# expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored +# expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored +one two:=three +# If the two targets to the left are generated by a variable expression, the +# line is parsed as a variable assignment since its left-hand side is a single +# word. +# expect: Global: one two = three +${:Uone two}:=three +.MAKEFLAGS: -d0 + .SUFFIXES: .c .o -var-scope-local.c var-scope-local2.c var-scope-local3.c: - : Making ${.TARGET} out of nothing. +# One of the dynamic target-local variables is '.TARGET'. Since this is not +# a suffix transformation rule, the variable '.IMPSRC' is not defined. +# expect: : Making var-scope-local.c out of nothing. +var-scope-local.c: + : Making ${.TARGET} ${.IMPSRC:Dfrom ${.IMPSRC}:Uout of nothing}. +# This is a suffix transformation rule, so both '.TARGET' and '.IMPSRC' are +# defined. +# expect: : Making var-scope-local.o from var-scope-local.c. +# expect: : Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".". .c.o: : Making ${.TARGET} from ${.IMPSRC}. # The local variables @F, @D,