14731c00bSChris Kay# 2c3273703SChris Kay# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved. 34731c00bSChris Kay# 44731c00bSChris Kay# SPDX-License-Identifier: BSD-3-Clause 54731c00bSChris Kay# 64731c00bSChris Kay 74731c00bSChris Kayspace := 84731c00bSChris Kayspace := $(space) $(space) 94731c00bSChris Kaycomma := , 104731c00bSChris Kay 114731c00bSChris Kaynull := � 1246a898f9SChris Kay 1346a898f9SChris Kaylparen := ( 1437cd6184SChris Kayrparen := ) 154731c00bSChris Kay 164731c00bSChris Kaycompat-path = $(subst $(space),$(null),$(1)) 174731c00bSChris Kaydecompat-path = $(subst $(null), ,$(1)) 184731c00bSChris Kay 194731c00bSChris Kayabsolute-path = $(call decompat-path,$(abspath $(call compat-path,$(1)))) 204731c00bSChris Kayreal-path = $(call decompat-path,$(realpath $(call compat-path,$(1)))) 214731c00bSChris Kay 224731c00bSChris Kayfile-name = $(call decompat-path,$(notdir $(call compat-path,$(1)))) 234731c00bSChris Kaydirectory-name = $(call decompat-path,$(dir $(call compat-path,$(1)))) 244731c00bSChris Kay 254731c00bSChris Kayescape-shell = '$(subst ','\'',$(1))' 263af4eb50SChris Kay 273af4eb50SChris Kay# 28a57b94ecSChris Kay# The grouped-target symbol. Grouped targets are not supported on versions of 29a57b94ecSChris Kay# GNU Make <= 4.2, which was most recently packaged with Ubuntu 20.04. 30a57b94ecSChris Kay# 31a57b94ecSChris Kay 32a57b94ecSChris Kay& := $(if $(filter grouped-target,$(.FEATURES)),&) 33a57b94ecSChris Kay 34a57b94ecSChris Kay# 353af4eb50SChris Kay# Upper-case a string value. 363af4eb50SChris Kay# 373af4eb50SChris Kay# Parameters: 383af4eb50SChris Kay# 393af4eb50SChris Kay# - $(1): The string to upper-case. 403af4eb50SChris Kay# 413af4eb50SChris Kay# Example usage: 423af4eb50SChris Kay# 433af4eb50SChris Kay# $(call uppercase,HeLlO wOrLd) # "HELLO WORLD" 443af4eb50SChris Kay# 453af4eb50SChris Kay 463af4eb50SChris Kayuppercase = $(shell echo $(call escape-shell,$(1)) | tr '[:lower:]' '[:upper:]') 473af4eb50SChris Kay 483af4eb50SChris Kay# 493af4eb50SChris Kay# Lower-case a string value. 503af4eb50SChris Kay# 513af4eb50SChris Kay# Parameters: 523af4eb50SChris Kay# 533af4eb50SChris Kay# - $(1): The string to lower-case. 543af4eb50SChris Kay# 553af4eb50SChris Kay# Example usage: 563af4eb50SChris Kay# 573af4eb50SChris Kay# $(call lowercase,HeLlO wOrLd) # "hello world" 583af4eb50SChris Kay# 593af4eb50SChris Kay 603af4eb50SChris Kaylowercase = $(shell echo $(call escape-shell,$(1)) | tr '[:upper:]' '[:lower:]') 610dfa3deaSChris Kay 620dfa3deaSChris Kay# 630dfa3deaSChris Kay# Determine the "truthiness" of a value. 640dfa3deaSChris Kay# 650dfa3deaSChris Kay# Parameters: 660dfa3deaSChris Kay# 670dfa3deaSChris Kay# - $(1): The value to determine the truthiness of. 680dfa3deaSChris Kay# 690dfa3deaSChris Kay# A value is considered to be falsy if it is: 700dfa3deaSChris Kay# 710dfa3deaSChris Kay# - empty, or 720dfa3deaSChris Kay# - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing. 730dfa3deaSChris Kay# 740dfa3deaSChris Kay# If the value is truthy then the value is returned as-is, otherwise no value 750dfa3deaSChris Kay# is returned. 760dfa3deaSChris Kay# 770dfa3deaSChris Kay# Example usage: 780dfa3deaSChris Kay# 790dfa3deaSChris Kay# truthy := y 800dfa3deaSChris Kay# truthy-bool := $(call bool,$(truthy)) # "y" 810dfa3deaSChris Kay# 820dfa3deaSChris Kay# falsy := n 830dfa3deaSChris Kay# falsy-bool := $(call bool,$(falsy)) # <empty> 840dfa3deaSChris Kay# 850dfa3deaSChris Kay 860dfa3deaSChris Kaybool = $(filter-out 0 n no f false,$(call lowercase,$(1))) 870dfa3deaSChris Kay 880dfa3deaSChris Kay# 890dfa3deaSChris Kay# Determine the "truthiness" of a value, returning 0 or 1. 900dfa3deaSChris Kay# 910dfa3deaSChris Kay# Parameters: 920dfa3deaSChris Kay# 930dfa3deaSChris Kay# - $(1): The value to determine the truthiness of. 940dfa3deaSChris Kay# 950dfa3deaSChris Kay# A value is considered to be falsy if it is: 960dfa3deaSChris Kay# 970dfa3deaSChris Kay# - empty, or 980dfa3deaSChris Kay# - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing. 990dfa3deaSChris Kay# 1000dfa3deaSChris Kay# If the value is truthy then the value is returned as-is, otherwise no value 1010dfa3deaSChris Kay# is returned. 1020dfa3deaSChris Kay# 1030dfa3deaSChris Kay# Example usage: 1040dfa3deaSChris Kay# 1050dfa3deaSChris Kay# truthy := y 1060dfa3deaSChris Kay# truthy-bool := $(call bool,$(truthy)) # "1" 1070dfa3deaSChris Kay# 1080dfa3deaSChris Kay# falsy := n 1090dfa3deaSChris Kay# falsy-bool := $(call bool,$(falsy)) # "0" 1100dfa3deaSChris Kay# 1110dfa3deaSChris Kay 1120dfa3deaSChris Kaybool-01 = $(if $(call bool,$(1)),1,0) 113d2867397SChris Kay 114d2867397SChris Kay# 115d2867397SChris Kay# Determine whether a variable is defined or not. 116d2867397SChris Kay# 117d2867397SChris Kay# Parameters: 118d2867397SChris Kay# 119d2867397SChris Kay# - $(1): The variable to check. 120d2867397SChris Kay# 121d2867397SChris Kay# Example usage: 122d2867397SChris Kay# 123d2867397SChris Kay# xyz-defined := $(call defined,xyz) # <empty> 124d2867397SChris Kay# 125d2867397SChris Kay# xyz := 126d2867397SChris Kay# xyz-defined := $(call defined,xyz) # <non-empty> 127d2867397SChris Kay# 128d2867397SChris Kay# xyz := hello 129d2867397SChris Kay# xyz-defined := $(call defined,xyz) # <non-empty> 130d2867397SChris Kay# 131d2867397SChris Kay 132d2867397SChris Kaydefined = $(call bool,$(filter-out undefined,$(origin $(1)))) 133c3273703SChris Kay 134c3273703SChris Kay# 1350fcee05fSHarrison Mutai# Extract include directories from compiler flags and convert them to absolute 1360fcee05fSHarrison Mutai# paths. 1370fcee05fSHarrison Mutai# 1380fcee05fSHarrison Mutai# Parameters: 1390fcee05fSHarrison Mutai# 1400fcee05fSHarrison Mutai# - $(1): A list of C compiler flags. 1410fcee05fSHarrison Mutai# 1420fcee05fSHarrison Mutai# Example: 1430fcee05fSHarrison Mutai# 1440fcee05fSHarrison Mutai# includes := $(call include-dirs, -nostdlib -Iinclude-dir) # /absolute/path/to/include-dir 1450fcee05fSHarrison Mutai# 1460fcee05fSHarrison Mutai 1470fcee05fSHarrison Mutaiinclude-dirs-pattern := $(call escape-shell,-I\s*("[^"]*"|'[^']*'|\S+)) 1480fcee05fSHarrison Mutaiinclude-dirs = $(shell \ 1490fcee05fSHarrison Mutai printf '%s' $(call escape-shell,$1) | \ 1500fcee05fSHarrison Mutai perl -nle 'print $$1 while /'$(include-dirs-pattern)'/g' | \ 1510fcee05fSHarrison Mutai xargs realpath \ 1520fcee05fSHarrison Mutai) 1530fcee05fSHarrison Mutai 1540fcee05fSHarrison Mutai# 155c3273703SChris Kay# Determine the path to a program. 156c3273703SChris Kay# 157c3273703SChris Kay# Parameters: 158c3273703SChris Kay# 159c3273703SChris Kay# - $(1): The program to search for. 160c3273703SChris Kay# 161c3273703SChris Kay# Example usage: 162c3273703SChris Kay# 163c3273703SChris Kay# path-to-gcc := $(call which,gcc) # "/usr/bin/gcc" 164c3273703SChris Kay# 165c3273703SChris Kay 166c3273703SChris Kaywhich = $(shell command -v $(call escape-shell,$(1)) 2>/dev/null) 1676eb35c60SChris Kay 1686eb35c60SChris Kay# 1696eb35c60SChris Kay# Temporarily bind variables while expanding text (scoped "with"). 1706eb35c60SChris Kay# 1716eb35c60SChris Kay# Creates temporary variable bindings, expands a body of text with those 1726eb35c60SChris Kay# bindings in effect, then restores all affected variables to their previous 1736eb35c60SChris Kay# values and flavors (or undefines them if they did not exist). This provides a 1746eb35c60SChris Kay# "let"-style scope for variable assignments during text expansion. 1756eb35c60SChris Kay# 1766eb35c60SChris Kay# This function is modelled on the `let` function introduced in GNU Make 4.4: 1776eb35c60SChris Kay# 1786eb35c60SChris Kay# https://www.gnu.org/software/make/manual/html_node/Let-Function.html 1796eb35c60SChris Kay# 1806eb35c60SChris Kay# Binding specifiers (space-separated in `$(1)`): 1816eb35c60SChris Kay# 1826eb35c60SChris Kay# - l:name Bind from the word list in `$(2)`. Bindings are applied 1836eb35c60SChris Kay# left-to-right; the last `l` binding receives all remaining words 1846eb35c60SChris Kay# (which may be empty). If there are more `l` names than words, the 1856eb35c60SChris Kay# excess names are bound to empty values. 1866eb35c60SChris Kay# 1876eb35c60SChris Kay# - p:name Bind from subsequent call arguments (`$(2)`, `$(3)`, `$(4)`, ...), 1886eb35c60SChris Kay# in left-to-right order. If `l` bindings are present, these 1896eb35c60SChris Kay# arguments instead start from `$(3)`, following the word list. 1906eb35c60SChris Kay# 1916eb35c60SChris Kay# - name Treated as `l:name`. 1926eb35c60SChris Kay# 1936eb35c60SChris Kay# Parameters: 1946eb35c60SChris Kay# 1956eb35c60SChris Kay# - $(1): Space-separated binding specifiers. 1966eb35c60SChris Kay# - $(2): The list value used by `l` bindings, if present. 1976eb35c60SChris Kay# - $(2|3..N-1): Values for `p` bindings, in order (optional). 1986eb35c60SChris Kay# - $(N): The text to expand with the temporary bindings active. 1996eb35c60SChris Kay# 2006eb35c60SChris Kay# Evaluation and restoration: 2016eb35c60SChris Kay# 2026eb35c60SChris Kay# - All function arguments in Make are expanded at the call site. The text 2036eb35c60SChris Kay# must therefore be escaped (write `$$` to produce a literal `$`), or 2046eb35c60SChris Kay# supplied via `$(value ...)` to avoid premature expansion. 2056eb35c60SChris Kay# 2066eb35c60SChris Kay# - Whitespace in `l`-style bindings is processed in terms of Make words; if 2076eb35c60SChris Kay# you need to preserve whitespace then prefer `p` bindings. 2086eb35c60SChris Kay# 2096eb35c60SChris Kay# - Variables are assigned as simple (`:=`) during the text expansion. After 2106eb35c60SChris Kay# the text is expanded, each variable is restored to its previous state with 2116eb35c60SChris Kay# its original flavor (simple or recursive), or undefined if it did not 2126eb35c60SChris Kay# exist. Origins (e.g., command line, environment) are not preserved. 2136eb35c60SChris Kay# 2146eb35c60SChris Kay# Examples: 2156eb35c60SChris Kay# 2166eb35c60SChris Kay# # Basic list destructuring (two names from a list): 2176eb35c60SChris Kay# $(call with,foo bar,10 20,$$(foo) $$(bar)) # "10 20" 2186eb35c60SChris Kay# 2196eb35c60SChris Kay# # Last list binding receives the remainder: 2206eb35c60SChris Kay# $(call with,head tail,1 2 3 4,[$$(head)] [$$(tail)]) # "[1] [2 3 4]" 2216eb35c60SChris Kay# 2226eb35c60SChris Kay# # Extra list names bind to empty values: 2236eb35c60SChris Kay# $(call with,x y,9,x=<$$(x)> y=<$$(y)>) # "x=<9> y=<>" 2246eb35c60SChris Kay# 2256eb35c60SChris Kay# # Parameter-only bindings start in `$(2)`: 2266eb35c60SChris Kay# $(call with,p:x p:y,foo,bar,$$(x)-$$(y)) # "foo-bar" 2276eb35c60SChris Kay# 2286eb35c60SChris Kay# # Parameter bindings start in `$(3)` when list bindings are specified: 2296eb35c60SChris Kay# $(call with,l:lhs p:op l:rhs,10 20,+,$$(lhs) $$(op) $$(rhs)) # "10 + 20" 2306eb35c60SChris Kay# 2316eb35c60SChris Kay# # Variables are restored after expansion, with flavor preserved: 2326eb35c60SChris Kay# 2336eb35c60SChris Kay# x := outer-x 2346eb35c60SChris Kay# y = outer-y 2356eb35c60SChris Kay# 2366eb35c60SChris Kay# $(info $(call with,x y,inner-x inner-y,$$(x) $$(y))) # "inner-x inner-y" 2376eb35c60SChris Kay# 2386eb35c60SChris Kay# $(info $(x) ($(flavor x))) # "outer-x (simple)" 2396eb35c60SChris Kay# $(info $(y) ($(flavor y))) # "outer-y (recursive)" 2406eb35c60SChris Kay# 2416eb35c60SChris Kay# # Passing the text via `$(value ...)` to avoid `$$` escaping: 2426eb35c60SChris Kay# 2436eb35c60SChris Kay# text = [$(head)] [$(tail)] 2446eb35c60SChris Kay# $(call with,head tail,1 2 3 4,$(value text)) # "[1] [2 3 4]" 2456eb35c60SChris Kay# 2466eb35c60SChris Kay# # Nested usage: 2476eb35c60SChris Kay# 2486eb35c60SChris Kay# $(call with,a b,foo bar, \ 2496eb35c60SChris Kay# $$(call with,c d,baz qux,$$$$(a) $$$$(b) $$$$(c) $$$$(d))) 2506eb35c60SChris Kay# # "foo bar baz qux" 2516eb35c60SChris Kay# 2526eb35c60SChris Kay 2536eb35c60SChris Kaywith = $(with.ns.push)$(eval $(value with.core))$(with.ns.pop) 2546eb35c60SChris Kay 2556eb35c60SChris Kaywith.ns = with.ns.$(with.ns.stack.head) 2566eb35c60SChris Kay 2576eb35c60SChris Kaywith.ns.stack := 2586eb35c60SChris Kaywith.ns.stack.head = $(words $(with.ns.stack)) 2596eb35c60SChris Kay 2606eb35c60SChris Kaywith.ns.push = $(eval with.ns.stack += $(with.ns.stack.head)) 2616eb35c60SChris Kaywith.ns.pop = $($(with.ns).result)$(eval $(value with.ns.pop.1)) 2626eb35c60SChris Kay 2636eb35c60SChris Kaydefine with.ns.pop.1 = 2646eb35c60SChris Kay $(foreach variable,$(filter $(with.ns).%,$(.VARIABLES)),$\ 2656eb35c60SChris Kay $(eval undefine $(variable))) 2666eb35c60SChris Kay 2676eb35c60SChris Kay with.ns.stack := $(wordlist 2,$(with.ns.stack.head),$(with.ns.stack)) 2686eb35c60SChris Kayendef 2696eb35c60SChris Kay 2706eb35c60SChris Kaywith.bind.norm = $\ 2716eb35c60SChris Kay $(if $(findstring :,$(1)),$\ 2726eb35c60SChris Kay $(or $(filter l: p:,$(firstword $(subst :,: ,$(1)))),$\ 2736eb35c60SChris Kay $(error invalid binding specifier: $(1)))$\ 2746eb35c60SChris Kay $(or $(filter-out %:,$(word 2,$(subst :,: ,$(1)))),$\ 2756eb35c60SChris Kay $(error invalid binding specifier: $(1))),$\ 2766eb35c60SChris Kay l:$(1)) 2776eb35c60SChris Kay 2786eb35c60SChris Kaywith.bind.kind = $(word 1,$(subst :, ,$(call with.bind.norm,$(1)))) 2796eb35c60SChris Kaywith.bind.name = $(word 2,$(subst :, ,$(call with.bind.norm,$(1)))) 2806eb35c60SChris Kay 2816eb35c60SChris Kaydefine with.core = 2826eb35c60SChris Kay # Parse and record binding list/kinds/names from `$(1)` 2836eb35c60SChris Kay $(with.ns).bind.list := $(foreach b,$(1),$(call with.bind.norm,$(b))) 2846eb35c60SChris Kay $(with.ns).bind.names := $(foreach b,$(1),$(call with.bind.name,$(b))) 2856eb35c60SChris Kay $(with.ns).bind.kinds := $(foreach b,$(1),$(call with.bind.kind,$(b))) 2866eb35c60SChris Kay 2876eb35c60SChris Kay # Create a 1..=(N_bindings) list of binding indices 2886eb35c60SChris Kay $(with.ns).bind.idx := 2896eb35c60SChris Kay $(with.ns).bind.next = $(words 0 $($(with.ns).bind.idx)) 2906eb35c60SChris Kay 2916eb35c60SChris Kay $(foreach bind,$($(with.ns).bind.list),$\ 2926eb35c60SChris Kay $(eval $(with.ns).bind.idx += $($(with.ns).bind.next))) 2936eb35c60SChris Kay 2946eb35c60SChris Kay # Create a 2..=(N_arguments) list pointing to the text argument 2956eb35c60SChris Kay $(with.ns).text.idx := 2966eb35c60SChris Kay $(with.ns).text.next = $(words 1 2 $($(with.ns).text.idx)) 2976eb35c60SChris Kay $(with.ns).text = $($($(with.ns).text.next)) 2986eb35c60SChris Kay 2996eb35c60SChris Kay # Snapshot original flavors/values of all variables to be overwritten 3006eb35c60SChris Kay $(foreach bind.name,$($(with.ns).bind.names),$\ 3016eb35c60SChris Kay $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\ 3026eb35c60SChris Kay $(eval $(bind.name.ns).flavor := $(flavor $(bind.name))$\ 3036eb35c60SChris Kay $(eval $(bind.name.ns).value = $(value $(bind.name)))))) 3046eb35c60SChris Kay 3056eb35c60SChris Kay # Initialize per-kind buckets (e.g., `l`, `p`) 3066eb35c60SChris Kay $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\ 3076eb35c60SChris Kay $(eval $(with.ns).bind.kind[$(bind.kind)] := )) 3086eb35c60SChris Kay 3096eb35c60SChris Kay # Distribute binding indices into kind buckets 3106eb35c60SChris Kay $(foreach bind.i,$($(with.ns).bind.idx),$\ 3116eb35c60SChris Kay $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\ 3126eb35c60SChris Kay $(eval $(with.ns).bind.kind[$(bind.kind)] += $(bind.i)))) 3136eb35c60SChris Kay 3146eb35c60SChris Kay # Per-kind setup (e.g., to set up index vectors before binding) 3156eb35c60SChris Kay $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\ 3166eb35c60SChris Kay $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\ 3176eb35c60SChris Kay $(eval $(value with.core.$(bind.kind))))) 3186eb35c60SChris Kay 3196eb35c60SChris Kay # Perform binding from left to right 3206eb35c60SChris Kay $(foreach bind.i,$($(with.ns).bind.idx),$\ 3216eb35c60SChris Kay $(foreach bind.name,$(word $(bind.i),$($(with.ns).bind.names)),$\ 3226eb35c60SChris Kay $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\ 3236eb35c60SChris Kay $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\ 3246eb35c60SChris Kay $(eval $(value with.core.$(bind.kind).bind)))))) 3256eb35c60SChris Kay 3266eb35c60SChris Kay # Capture the expansion result from the current text pointer 3276eb35c60SChris Kay $(eval $(with.ns).result := $($(with.ns).text)) 3286eb35c60SChris Kay 3296eb35c60SChris Kay # Restore originals (flavor/value) or undefine if previously absent 3306eb35c60SChris Kay $(foreach bind.name,$($(with.ns).bind.names),$\ 3316eb35c60SChris Kay $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\ 3326eb35c60SChris Kay $(eval $(value with.core.restore)))) 3336eb35c60SChris Kayendef 3346eb35c60SChris Kay 3356eb35c60SChris Kaydefine with.core.l = 3366eb35c60SChris Kay # Create a 1..=(N_largs) list capturing the unbound `l` words 3376eb35c60SChris Kay $(bind.kind.ns).words.idx := 3386eb35c60SChris Kay $(bind.kind.ns).words.next = $(words 1 $($(bind.kind.ns).words.idx)) 3396eb35c60SChris Kay $(bind.kind.ns).words = $\ 3406eb35c60SChris Kay $(wordlist $($(bind.kind.ns).words.next),$(words $(2)),$(2)) 3416eb35c60SChris Kay 3426eb35c60SChris Kay # Increment the text pointer 3436eb35c60SChris Kay $(with.ns).text.idx += $($(with.ns).text.next) 3446eb35c60SChris Kayendef 3456eb35c60SChris Kay 3466eb35c60SChris Kaydefine with.core.l.bind = 3476eb35c60SChris Kay # Bind this name to the next unbound word 3486eb35c60SChris Kay $(bind.name) := $(firstword $($(bind.kind.ns).words)) 3496eb35c60SChris Kay 3506eb35c60SChris Kay # If this is the last `l` binding, absorb the remaining words 3516eb35c60SChris Kay ifeq ($($(bind.kind.ns).words.next),$(words $($(bind.kind.ns)))) 3526eb35c60SChris Kay $(bind.name) := $($(bind.kind.ns).words) 3536eb35c60SChris Kay endif 3546eb35c60SChris Kay 3556eb35c60SChris Kay # Nudge the word pointer forward 3566eb35c60SChris Kay $(bind.kind.ns).words.idx += $($(bind.kind.ns).words.next) 3576eb35c60SChris Kayendef 3586eb35c60SChris Kay 3596eb35c60SChris Kaydefine with.core.p = 3606eb35c60SChris Kay # Compute the parameter index that `p` bindings start at 3616eb35c60SChris Kay $(bind.kind.ns).param.offset := 1 2 3626eb35c60SChris Kay 3636eb35c60SChris Kay # When `l` bindings are present, `p` values shift right 3646eb35c60SChris Kay ifneq ($(filter l,$($(with.ns).bind.kinds)),) 3656eb35c60SChris Kay $(bind.kind.ns).param.offset += 3 3666eb35c60SChris Kay endif 3676eb35c60SChris Kay 3686eb35c60SChris Kay # Create an N_poff..=N_pargs list capturing the unbound `p` arguments 3696eb35c60SChris Kay $(bind.kind.ns).param.idx := 3706eb35c60SChris Kay $(bind.kind.ns).param.next = $\ 3716eb35c60SChris Kay $(words $($(bind.kind.ns).param.offset) $\ 3726eb35c60SChris Kay $($(bind.kind.ns).param.idx)) 3736eb35c60SChris Kay $(bind.kind.ns).param = $($(lastword $($(bind.kind.ns).param.idx))) 3746eb35c60SChris Kayendef 3756eb35c60SChris Kay 3766eb35c60SChris Kaydefine with.core.p.bind = 3776eb35c60SChris Kay # Mark the next parameter as bound 3786eb35c60SChris Kay $(bind.kind.ns).param.idx += $($(bind.kind.ns).param.next) 3796eb35c60SChris Kay 3806eb35c60SChris Kay # Bind this name to the next unbound argument 3816eb35c60SChris Kay $(bind.name) := $($(bind.kind.ns).param) 3826eb35c60SChris Kay 3836eb35c60SChris Kay # Increment the text pointer 3846eb35c60SChris Kay $(with.ns).text.idx += $($(with.ns).text.next) 3856eb35c60SChris Kayendef 3866eb35c60SChris Kay 3876eb35c60SChris Kaydefine with.core.restore = 3886eb35c60SChris Kay ifeq ($($(bind.name.ns).flavor),simple) 3896eb35c60SChris Kay $(eval $(bind.name) := $(value $(bind.name.ns).value)) 3906eb35c60SChris Kay else ifeq ($($(bind.name.ns).flavor),recursive) 3916eb35c60SChris Kay $(eval $(bind.name) = $(value $(bind.name.ns).value)) 3926eb35c60SChris Kay else ifeq ($($(bind.name.ns).flavor),undefined) 3936eb35c60SChris Kay undefine $(bind.name) 3946eb35c60SChris Kay endif 3956eb35c60SChris Kayendef 39610cb835fSChris Kay 39710cb835fSChris Kay# 39810cb835fSChris Kay# Quote a string for safe use as a shell word. 39910cb835fSChris Kay# 40010cb835fSChris Kay# Takes the input string `$(1)` and escapes any single quotes it contains so 40110cb835fSChris Kay# that the result can be safely used as a literal shell argument. The output is 40210cb835fSChris Kay# wrapped in single quotes to ensure that whitespace and special characters are 40310cb835fSChris Kay# preserved exactly when passed to the shell. 40410cb835fSChris Kay# 40510cb835fSChris Kay# This function is useful when constructing shell commands dynamically, since it 40610cb835fSChris Kay# guarantees that arbitrary values are quoted correctly and will not be 40710cb835fSChris Kay# misinterpreted by the shell. 40810cb835fSChris Kay# 40910cb835fSChris Kay# Parameters: 41010cb835fSChris Kay# 41110cb835fSChris Kay# - $(1): The string to quote for safe shell usage. 41210cb835fSChris Kay# 41310cb835fSChris Kay# Examples: 41410cb835fSChris Kay# 41510cb835fSChris Kay# $(call shell-quote,foo) # "'foo'" 41610cb835fSChris Kay# $(call shell-quote,bar baz) # "'bar baz'" 41710cb835fSChris Kay# $(call shell-quote,foo 'bar baz' qux) # "'foo '\''bar baz'\'' qux'" 41810cb835fSChris Kay# 41910cb835fSChris Kay 42010cb835fSChris Kayshell-quote = '$(subst ','\'',$(1))' 4215980fa7cSChris Kay 4225980fa7cSChris Kay# 4235980fa7cSChris Kay# Parse a shell fragment and extract the N-th word. 4245980fa7cSChris Kay# 4255980fa7cSChris Kay# Parses the shell fragment given by `$(2)` using the shell's word-splitting and 4265980fa7cSChris Kay# quoting rules, then prints the `$(1)`-th shell word in the result. If the 4275980fa7cSChris Kay# index is out of range then this function evaluates to an empty string. 4285980fa7cSChris Kay# 4295980fa7cSChris Kay# This function is useful when working with lists that may contain whitespace or 4305980fa7cSChris Kay# quoted values, since it relies on the shell to do the parsing rather than 4315980fa7cSChris Kay# Make's own word functions. Whitespace is preserved in the return value. 4325980fa7cSChris Kay# 4335980fa7cSChris Kay# Parameters: 4345980fa7cSChris Kay# 4355980fa7cSChris Kay# - $(1): The 1-based index of the word to extract. 4365980fa7cSChris Kay# - $(2): The shell fragment to parse. 4375980fa7cSChris Kay# 4385980fa7cSChris Kay# Example usage: 4395980fa7cSChris Kay# 4405980fa7cSChris Kay# $(call shell-word,1,foo 'bar baz' qux) # "foo" 4415980fa7cSChris Kay# $(call shell-word,2,foo 'bar baz' qux) # "bar baz" 4425980fa7cSChris Kay# $(call shell-word,3,foo 'bar baz' qux) # "qux" 4435980fa7cSChris Kay# $(call shell-word,4,foo 'bar baz' qux) # <empty> 4445980fa7cSChris Kay# 4455980fa7cSChris Kay 4465980fa7cSChris Kayshell-word = $(shell $(shell-word.sh)) 4475980fa7cSChris Kay 4485980fa7cSChris Kaydefine shell-word.sh = 4495980fa7cSChris Kay set -Cefu -- '' $(2); 4505980fa7cSChris Kay 4515980fa7cSChris Kay n=$(call shell-quote,$(1)); 4525980fa7cSChris Kay 4535980fa7cSChris Kay shift "$${n}"; 4545980fa7cSChris Kay printf '%s' "$${1:-}"; 4555980fa7cSChris Kayendef 4568165d826SChris Kay 4578165d826SChris Kay# 4588165d826SChris Kay# Parse a shell fragment and count the number of shell words. 4598165d826SChris Kay# 4608165d826SChris Kay# Parses the shell fragment given by `$(1)` using the shell's word-splitting and 4618165d826SChris Kay# quoting rules, then prints the total number of words in the result. 4628165d826SChris Kay# 4638165d826SChris Kay# This function is useful when working with lists that may contain whitespace or 4648165d826SChris Kay# quoted values, since it relies on the shell to do the parsing rather than 4658165d826SChris Kay# Make's own word functions. 4668165d826SChris Kay# 4678165d826SChris Kay# Parameters: 4688165d826SChris Kay# 4698165d826SChris Kay# - $(1): The shell fragment to parse. 4708165d826SChris Kay# 4718165d826SChris Kay# Example usage: 4728165d826SChris Kay# 4738165d826SChris Kay# $(call shell-words,) # "0" 4748165d826SChris Kay# $(call shell-words,foo) # "1" 4758165d826SChris Kay# $(call shell-words,foo bar baz) # "3" 4768165d826SChris Kay# $(call shell-words,foo 'bar baz' qux) # "3" 4778165d826SChris Kay# 4788165d826SChris Kay 4798165d826SChris Kayshell-words = $(shell $(shell-words.sh)) 4808165d826SChris Kayshell-words.sh = set -Cefu -- $(1); printf '%s' "$$\#"; 4819a782d40SChris Kay 4829a782d40SChris Kay# 4839a782d40SChris Kay# Parse a shell fragment and extract a sequence of shell words. 4849a782d40SChris Kay# 4859a782d40SChris Kay# Parses the shell fragment given by `$(1)` using the shell's word-splitting and 4869a782d40SChris Kay# quoting rules, then extracts the words from index `$(2)` up to but not 4879a782d40SChris Kay# including index `$(3)`. Each extracted shell word is returned sanitized for 4889a782d40SChris Kay# safe use in the shell. 4899a782d40SChris Kay# 4909a782d40SChris Kay# If `$(3)` is omitted, it defaults to one past the total number of words in the 4919a782d40SChris Kay# string, allowing you to express "all words starting from `$(2)`". 4929a782d40SChris Kay# 4939a782d40SChris Kay# This function is useful for safely selecting and passing subsequences of 4949a782d40SChris Kay# shell-parsed arguments into other shell commands, ensuring correct handling 4959a782d40SChris Kay# of whitespace and special characters. 4969a782d40SChris Kay# 4979a782d40SChris Kay# Parameters: 4989a782d40SChris Kay# 4999a782d40SChris Kay# - $(1): The shell fragment to parse. 5009a782d40SChris Kay# - $(2): The 1-based start index of the slice (default: 1). 5013dc69bcbSChris Kay# - $(3): The 1-based end index of the slice (exclusive, optional). 5029a782d40SChris Kay# 5039a782d40SChris Kay# Example usage: 5049a782d40SChris Kay# 5059a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux) # "'foo' 'bar baz' 'qux'" 5069a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,1,3) # "'foo' 'bar baz'" 5079a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,2) # "'bar baz' 'qux'" 5089a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,2,4) # "'bar baz' 'qux'" 5099a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,2,5) # "'bar baz' 'qux'" 5109a782d40SChris Kay# 5119a782d40SChris Kay 5129a782d40SChris Kayshell-slice = $(shell $(shell-slice.sh)) 5139a782d40SChris Kay 5149a782d40SChris Kaydefine shell-slice.sh = 5159a782d40SChris Kay set -Cefu -- $(1); 5169a782d40SChris Kay 5179a782d40SChris Kay n=$(if $(2),$(call shell-quote,$(2)),1); 5183dc69bcbSChris Kay m=$(if $(3),$(call shell-quote,$(3)),$$(($$# + 1))); 5199a782d40SChris Kay 5209a782d40SChris Kay printf '%s\n' "$$@" $\ 5213dc69bcbSChris Kay | sed -n "$${n},$${m}{ $${m}!p }; $${m}q" $\ 5229a782d40SChris Kay | sed "s/'/'\\\\''/g; s/^/'/; s/\$$/'/"; 5239a782d40SChris Kayendef 524a75ab9a7SChris Kay 525a75ab9a7SChris Kay# 526a75ab9a7SChris Kay# Join shell words with a custom delimiter. 527a75ab9a7SChris Kay# 528a75ab9a7SChris Kay# Parses the shell fragment given by `$(1)` using the shell's word-splitting and 529a75ab9a7SChris Kay# quoting rules, then joins the resulting words together with the delimiter 530a75ab9a7SChris Kay# specified by `$(2)`. If no delimiter is provided, no delimiter is used. 531a75ab9a7SChris Kay# 532a75ab9a7SChris Kay# This function is useful for safely rejoining a sequence of shell-parsed 533a75ab9a7SChris Kay# arguments into a single string with controlled separators, ensuring that 534a75ab9a7SChris Kay# whitespace and quoting are preserved correctly. 535a75ab9a7SChris Kay# 536a75ab9a7SChris Kay# Parameters: 537a75ab9a7SChris Kay# 538a75ab9a7SChris Kay# - $(1): The shell fragment to parse and join. 539a75ab9a7SChris Kay# - $(2): The delimiter to insert between words (optional). 540a75ab9a7SChris Kay# 541a75ab9a7SChris Kay# Example usage: 542a75ab9a7SChris Kay# 543a75ab9a7SChris Kay# $(call shell-join,foo 'bar baz' qux) # "foobar bazqux" 544a75ab9a7SChris Kay# $(call shell-join,foo 'bar baz' qux,:) # "foo:bar baz:qux" 545a75ab9a7SChris Kay# $(call shell-join,foo 'bar baz' qux,;) # "foo;bar baz;qux" 546a75ab9a7SChris Kay# 547a75ab9a7SChris Kay 548a75ab9a7SChris Kayshell-join = $(shell $(shell-join.sh)) 549a75ab9a7SChris Kay 550a75ab9a7SChris Kaydefine shell-join.sh = 551a75ab9a7SChris Kay set -Cefu -- $(1); 552a75ab9a7SChris Kay 553a75ab9a7SChris Kay delimiter=$(call shell-quote,$(2)); 554a75ab9a7SChris Kay 555a75ab9a7SChris Kay printf '%s' "$${1:-}"; 556a75ab9a7SChris Kay shift 1; 557a75ab9a7SChris Kay 558a75ab9a7SChris Kay while [ "$$#" -gt 0 ]; do 559a75ab9a7SChris Kay printf '%s%s' "$${delimiter}" "$${1}"; 560a75ab9a7SChris Kay shift 1; 561a75ab9a7SChris Kay done 562a75ab9a7SChris Kayendef 56337cd6184SChris Kay 56437cd6184SChris Kay# 56537cd6184SChris Kay# Apply a function to each shell word in a fragment. 56637cd6184SChris Kay# 56737cd6184SChris Kay# Parses the shell fragment given by `$(2)` into words using the shell's 56837cd6184SChris Kay# word-splitting and quoting rules. For each word, the function `$(1)` is 5691d5ae1e5SChris Kay# invoked with the word as its first argument and the 1-based index of the word 5701d5ae1e5SChris Kay# as its second argument. The results are concatenated and returned, separated 5711d5ae1e5SChris Kay# by whitespace. 57237cd6184SChris Kay# 57337cd6184SChris Kay# This function is useful when you want to process each shell word from a 57437cd6184SChris Kay# fragment through another function, while preserving correct handling of 57537cd6184SChris Kay# whitespace and quoting. 57637cd6184SChris Kay# 57737cd6184SChris Kay# Parameters: 57837cd6184SChris Kay# 57937cd6184SChris Kay# - $(1): The function to apply to each word. 58037cd6184SChris Kay# - $(2): The shell fragment to parse into words. 58137cd6184SChris Kay# 58237cd6184SChris Kay# Example usage: 58337cd6184SChris Kay# 58437cd6184SChris Kay# $(call shell-map,words,foo 'bar baz' qux) # "1 2 1" 58537cd6184SChris Kay# $(call shell-map,uppercase,foo 'bar baz' qux) # "FOO BAR BAZ QUX" 58637cd6184SChris Kay# 58737cd6184SChris Kay# shout = $(1)! 58837cd6184SChris Kay# $(call shell-map,shout,foo 'bar baz' qux) # "foo! bar baz! qux!" 58937cd6184SChris Kay# 59037cd6184SChris Kay# make-binary = /bin/$(1) 59137cd6184SChris Kay# $(call shell-map,make-binary,cp "ls" 'sh') # "/bin/cp /bin/ls /bin/sh" 59237cd6184SChris Kay# 5931d5ae1e5SChris Kay# index-label = $(1):$(2) 5941d5ae1e5SChris Kay# $(call shell-map,index-label,foo 'bar baz') # "foo:1 bar baz:2" 5951d5ae1e5SChris Kay# 59637cd6184SChris Kay 59737cd6184SChris Kayshell-map = $(call with,,$(shell $(shell-map.sh))) 59837cd6184SChris Kay 59937cd6184SChris Kaydefine shell-map.sh = 60037cd6184SChris Kay set -Cefu -- $(2); 60137cd6184SChris Kay 60237cd6184SChris Kay function=$(call shell-quote,$(1)); 6031d5ae1e5SChris Kay index=1; 60437cd6184SChris Kay 60537cd6184SChris Kay for argument in "$$@"; do 60637cd6184SChris Kay sanitized=$$(printf '%s' "$${argument}" $\ 607*cfc2d766SChris Kay | sed -e 's/[$$]/$$$$/g; s/,/$${comma}/g' $\ 608*cfc2d766SChris Kay -e 's/(/$${lparen}/g; s/)/$${rparen}/g'); 60937cd6184SChris Kay 6101d5ae1e5SChris Kay printf '$$(call %s,%s,%s)\n' $\ 6111d5ae1e5SChris Kay "$${function}" "$${sanitized}" "$${index}"; 6121d5ae1e5SChris Kay 6131d5ae1e5SChris Kay index=$$((index + 1)); 61437cd6184SChris Kay done 61537cd6184SChris Kayendef 616a72154ceSChris Kay 617a72154ceSChris Kay# 618a72154ceSChris Kay# Resolve a program name or shell fragment to a safely quoted shell command. 619a72154ceSChris Kay# 620a72154ceSChris Kay# Attempts to locate the program given by `$(1)` on the system `PATH`. If the 621a72154ceSChris Kay# program is found, its name is returned wrapped in single quotes so it can be 622a72154ceSChris Kay# used safely in a shell command. If the program cannot be found, then the 623a72154ceSChris Kay# argument is instead parsed as a shell fragment and returned as a sanitized 624a72154ceSChris Kay# sequence of words, ensuring whitespace and quoting are preserved correctly. 625a72154ceSChris Kay# 626a72154ceSChris Kay# This function is useful when dynamically constructing shell command lines 627a72154ceSChris Kay# that may include either well-known executables or arbitrary user-supplied 628a72154ceSChris Kay# fragments. It guarantees that the result is safe to embed in shell commands, 629a72154ceSChris Kay# regardless of whether it resolves to a `PATH` entry or a literal fragment. 630a72154ceSChris Kay# 631a72154ceSChris Kay# Parameters: 632a72154ceSChris Kay# 633a72154ceSChris Kay# - $(1): The program name or shell fragment to resolve. 634a72154ceSChris Kay# 635a72154ceSChris Kay# Example usage: 636a72154ceSChris Kay# 637a72154ceSChris Kay# $(call shell-program,sh) # "'sh'" 638a72154ceSChris Kay# $(call shell-program,sh -c) # "'sh' '-c'" 639a72154ceSChris Kay# 640a72154ceSChris Kay# # If the program exists and is executable: 641a72154ceSChris Kay# 642a72154ceSChris Kay# $(call shell-program,/foo bar/sh) # "'/foo bar/sh'" 643a72154ceSChris Kay# $(call shell-program,"/foo bar/sh" -c) # "'/foo bar/sh' '-c'" 644a72154ceSChris Kay# 645a72154ceSChris Kay# # If the program does not exist or is not executable: 646a72154ceSChris Kay# 647a72154ceSChris Kay# $(call shell-program,/foo bar/sh) # "'/foo' 'bar/sh'" 648a72154ceSChris Kay# $(call shell-program,/foo bar/sh -c) # "'/foo' 'bar/sh' '-c'" 649a72154ceSChris Kay# 650a72154ceSChris Kay 651a72154ceSChris Kayshell-program = $\ 652a72154ceSChris Kay $(if $(call which,$(1)),$\ 653a72154ceSChris Kay $(call shell-quote,$(1)),$\ 654a72154ceSChris Kay $(call shell-slice,$(1))) 655