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 := � 124731c00bSChris Kay 134731c00bSChris Kaycompat-path = $(subst $(space),$(null),$(1)) 144731c00bSChris Kaydecompat-path = $(subst $(null), ,$(1)) 154731c00bSChris Kay 164731c00bSChris Kayabsolute-path = $(call decompat-path,$(abspath $(call compat-path,$(1)))) 174731c00bSChris Kayreal-path = $(call decompat-path,$(realpath $(call compat-path,$(1)))) 184731c00bSChris Kay 194731c00bSChris Kayfile-name = $(call decompat-path,$(notdir $(call compat-path,$(1)))) 204731c00bSChris Kaydirectory-name = $(call decompat-path,$(dir $(call compat-path,$(1)))) 214731c00bSChris Kay 224731c00bSChris Kayescape-shell = '$(subst ','\'',$(1))' 233af4eb50SChris Kay 243af4eb50SChris Kay# 25a57b94ecSChris Kay# The grouped-target symbol. Grouped targets are not supported on versions of 26a57b94ecSChris Kay# GNU Make <= 4.2, which was most recently packaged with Ubuntu 20.04. 27a57b94ecSChris Kay# 28a57b94ecSChris Kay 29a57b94ecSChris Kay& := $(if $(filter grouped-target,$(.FEATURES)),&) 30a57b94ecSChris Kay 31a57b94ecSChris Kay# 323af4eb50SChris Kay# Upper-case a string value. 333af4eb50SChris Kay# 343af4eb50SChris Kay# Parameters: 353af4eb50SChris Kay# 363af4eb50SChris Kay# - $(1): The string to upper-case. 373af4eb50SChris Kay# 383af4eb50SChris Kay# Example usage: 393af4eb50SChris Kay# 403af4eb50SChris Kay# $(call uppercase,HeLlO wOrLd) # "HELLO WORLD" 413af4eb50SChris Kay# 423af4eb50SChris Kay 433af4eb50SChris Kayuppercase = $(shell echo $(call escape-shell,$(1)) | tr '[:lower:]' '[:upper:]') 443af4eb50SChris Kay 453af4eb50SChris Kay# 463af4eb50SChris Kay# Lower-case a string value. 473af4eb50SChris Kay# 483af4eb50SChris Kay# Parameters: 493af4eb50SChris Kay# 503af4eb50SChris Kay# - $(1): The string to lower-case. 513af4eb50SChris Kay# 523af4eb50SChris Kay# Example usage: 533af4eb50SChris Kay# 543af4eb50SChris Kay# $(call lowercase,HeLlO wOrLd) # "hello world" 553af4eb50SChris Kay# 563af4eb50SChris Kay 573af4eb50SChris Kaylowercase = $(shell echo $(call escape-shell,$(1)) | tr '[:upper:]' '[:lower:]') 580dfa3deaSChris Kay 590dfa3deaSChris Kay# 600dfa3deaSChris Kay# Determine the "truthiness" of a value. 610dfa3deaSChris Kay# 620dfa3deaSChris Kay# Parameters: 630dfa3deaSChris Kay# 640dfa3deaSChris Kay# - $(1): The value to determine the truthiness of. 650dfa3deaSChris Kay# 660dfa3deaSChris Kay# A value is considered to be falsy if it is: 670dfa3deaSChris Kay# 680dfa3deaSChris Kay# - empty, or 690dfa3deaSChris Kay# - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing. 700dfa3deaSChris Kay# 710dfa3deaSChris Kay# If the value is truthy then the value is returned as-is, otherwise no value 720dfa3deaSChris Kay# is returned. 730dfa3deaSChris Kay# 740dfa3deaSChris Kay# Example usage: 750dfa3deaSChris Kay# 760dfa3deaSChris Kay# truthy := y 770dfa3deaSChris Kay# truthy-bool := $(call bool,$(truthy)) # "y" 780dfa3deaSChris Kay# 790dfa3deaSChris Kay# falsy := n 800dfa3deaSChris Kay# falsy-bool := $(call bool,$(falsy)) # <empty> 810dfa3deaSChris Kay# 820dfa3deaSChris Kay 830dfa3deaSChris Kaybool = $(filter-out 0 n no f false,$(call lowercase,$(1))) 840dfa3deaSChris Kay 850dfa3deaSChris Kay# 860dfa3deaSChris Kay# Determine the "truthiness" of a value, returning 0 or 1. 870dfa3deaSChris Kay# 880dfa3deaSChris Kay# Parameters: 890dfa3deaSChris Kay# 900dfa3deaSChris Kay# - $(1): The value to determine the truthiness of. 910dfa3deaSChris Kay# 920dfa3deaSChris Kay# A value is considered to be falsy if it is: 930dfa3deaSChris Kay# 940dfa3deaSChris Kay# - empty, or 950dfa3deaSChris Kay# - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing. 960dfa3deaSChris Kay# 970dfa3deaSChris Kay# If the value is truthy then the value is returned as-is, otherwise no value 980dfa3deaSChris Kay# is returned. 990dfa3deaSChris Kay# 1000dfa3deaSChris Kay# Example usage: 1010dfa3deaSChris Kay# 1020dfa3deaSChris Kay# truthy := y 1030dfa3deaSChris Kay# truthy-bool := $(call bool,$(truthy)) # "1" 1040dfa3deaSChris Kay# 1050dfa3deaSChris Kay# falsy := n 1060dfa3deaSChris Kay# falsy-bool := $(call bool,$(falsy)) # "0" 1070dfa3deaSChris Kay# 1080dfa3deaSChris Kay 1090dfa3deaSChris Kaybool-01 = $(if $(call bool,$(1)),1,0) 110d2867397SChris Kay 111d2867397SChris Kay# 112d2867397SChris Kay# Determine whether a variable is defined or not. 113d2867397SChris Kay# 114d2867397SChris Kay# Parameters: 115d2867397SChris Kay# 116d2867397SChris Kay# - $(1): The variable to check. 117d2867397SChris Kay# 118d2867397SChris Kay# Example usage: 119d2867397SChris Kay# 120d2867397SChris Kay# xyz-defined := $(call defined,xyz) # <empty> 121d2867397SChris Kay# 122d2867397SChris Kay# xyz := 123d2867397SChris Kay# xyz-defined := $(call defined,xyz) # <non-empty> 124d2867397SChris Kay# 125d2867397SChris Kay# xyz := hello 126d2867397SChris Kay# xyz-defined := $(call defined,xyz) # <non-empty> 127d2867397SChris Kay# 128d2867397SChris Kay 129d2867397SChris Kaydefined = $(call bool,$(filter-out undefined,$(origin $(1)))) 130c3273703SChris Kay 131c3273703SChris Kay# 1320fcee05fSHarrison Mutai# Extract include directories from compiler flags and convert them to absolute 1330fcee05fSHarrison Mutai# paths. 1340fcee05fSHarrison Mutai# 1350fcee05fSHarrison Mutai# Parameters: 1360fcee05fSHarrison Mutai# 1370fcee05fSHarrison Mutai# - $(1): A list of C compiler flags. 1380fcee05fSHarrison Mutai# 1390fcee05fSHarrison Mutai# Example: 1400fcee05fSHarrison Mutai# 1410fcee05fSHarrison Mutai# includes := $(call include-dirs, -nostdlib -Iinclude-dir) # /absolute/path/to/include-dir 1420fcee05fSHarrison Mutai# 1430fcee05fSHarrison Mutai 1440fcee05fSHarrison Mutaiinclude-dirs-pattern := $(call escape-shell,-I\s*("[^"]*"|'[^']*'|\S+)) 1450fcee05fSHarrison Mutaiinclude-dirs = $(shell \ 1460fcee05fSHarrison Mutai printf '%s' $(call escape-shell,$1) | \ 1470fcee05fSHarrison Mutai perl -nle 'print $$1 while /'$(include-dirs-pattern)'/g' | \ 1480fcee05fSHarrison Mutai xargs realpath \ 1490fcee05fSHarrison Mutai) 1500fcee05fSHarrison Mutai 1510fcee05fSHarrison Mutai# 152c3273703SChris Kay# Determine the path to a program. 153c3273703SChris Kay# 154c3273703SChris Kay# Parameters: 155c3273703SChris Kay# 156c3273703SChris Kay# - $(1): The program to search for. 157c3273703SChris Kay# 158c3273703SChris Kay# Example usage: 159c3273703SChris Kay# 160c3273703SChris Kay# path-to-gcc := $(call which,gcc) # "/usr/bin/gcc" 161c3273703SChris Kay# 162c3273703SChris Kay 163c3273703SChris Kaywhich = $(shell command -v $(call escape-shell,$(1)) 2>/dev/null) 1646eb35c60SChris Kay 1656eb35c60SChris Kay# 1666eb35c60SChris Kay# Temporarily bind variables while expanding text (scoped "with"). 1676eb35c60SChris Kay# 1686eb35c60SChris Kay# Creates temporary variable bindings, expands a body of text with those 1696eb35c60SChris Kay# bindings in effect, then restores all affected variables to their previous 1706eb35c60SChris Kay# values and flavors (or undefines them if they did not exist). This provides a 1716eb35c60SChris Kay# "let"-style scope for variable assignments during text expansion. 1726eb35c60SChris Kay# 1736eb35c60SChris Kay# This function is modelled on the `let` function introduced in GNU Make 4.4: 1746eb35c60SChris Kay# 1756eb35c60SChris Kay# https://www.gnu.org/software/make/manual/html_node/Let-Function.html 1766eb35c60SChris Kay# 1776eb35c60SChris Kay# Binding specifiers (space-separated in `$(1)`): 1786eb35c60SChris Kay# 1796eb35c60SChris Kay# - l:name Bind from the word list in `$(2)`. Bindings are applied 1806eb35c60SChris Kay# left-to-right; the last `l` binding receives all remaining words 1816eb35c60SChris Kay# (which may be empty). If there are more `l` names than words, the 1826eb35c60SChris Kay# excess names are bound to empty values. 1836eb35c60SChris Kay# 1846eb35c60SChris Kay# - p:name Bind from subsequent call arguments (`$(2)`, `$(3)`, `$(4)`, ...), 1856eb35c60SChris Kay# in left-to-right order. If `l` bindings are present, these 1866eb35c60SChris Kay# arguments instead start from `$(3)`, following the word list. 1876eb35c60SChris Kay# 1886eb35c60SChris Kay# - name Treated as `l:name`. 1896eb35c60SChris Kay# 1906eb35c60SChris Kay# Parameters: 1916eb35c60SChris Kay# 1926eb35c60SChris Kay# - $(1): Space-separated binding specifiers. 1936eb35c60SChris Kay# - $(2): The list value used by `l` bindings, if present. 1946eb35c60SChris Kay# - $(2|3..N-1): Values for `p` bindings, in order (optional). 1956eb35c60SChris Kay# - $(N): The text to expand with the temporary bindings active. 1966eb35c60SChris Kay# 1976eb35c60SChris Kay# Evaluation and restoration: 1986eb35c60SChris Kay# 1996eb35c60SChris Kay# - All function arguments in Make are expanded at the call site. The text 2006eb35c60SChris Kay# must therefore be escaped (write `$$` to produce a literal `$`), or 2016eb35c60SChris Kay# supplied via `$(value ...)` to avoid premature expansion. 2026eb35c60SChris Kay# 2036eb35c60SChris Kay# - Whitespace in `l`-style bindings is processed in terms of Make words; if 2046eb35c60SChris Kay# you need to preserve whitespace then prefer `p` bindings. 2056eb35c60SChris Kay# 2066eb35c60SChris Kay# - Variables are assigned as simple (`:=`) during the text expansion. After 2076eb35c60SChris Kay# the text is expanded, each variable is restored to its previous state with 2086eb35c60SChris Kay# its original flavor (simple or recursive), or undefined if it did not 2096eb35c60SChris Kay# exist. Origins (e.g., command line, environment) are not preserved. 2106eb35c60SChris Kay# 2116eb35c60SChris Kay# Examples: 2126eb35c60SChris Kay# 2136eb35c60SChris Kay# # Basic list destructuring (two names from a list): 2146eb35c60SChris Kay# $(call with,foo bar,10 20,$$(foo) $$(bar)) # "10 20" 2156eb35c60SChris Kay# 2166eb35c60SChris Kay# # Last list binding receives the remainder: 2176eb35c60SChris Kay# $(call with,head tail,1 2 3 4,[$$(head)] [$$(tail)]) # "[1] [2 3 4]" 2186eb35c60SChris Kay# 2196eb35c60SChris Kay# # Extra list names bind to empty values: 2206eb35c60SChris Kay# $(call with,x y,9,x=<$$(x)> y=<$$(y)>) # "x=<9> y=<>" 2216eb35c60SChris Kay# 2226eb35c60SChris Kay# # Parameter-only bindings start in `$(2)`: 2236eb35c60SChris Kay# $(call with,p:x p:y,foo,bar,$$(x)-$$(y)) # "foo-bar" 2246eb35c60SChris Kay# 2256eb35c60SChris Kay# # Parameter bindings start in `$(3)` when list bindings are specified: 2266eb35c60SChris Kay# $(call with,l:lhs p:op l:rhs,10 20,+,$$(lhs) $$(op) $$(rhs)) # "10 + 20" 2276eb35c60SChris Kay# 2286eb35c60SChris Kay# # Variables are restored after expansion, with flavor preserved: 2296eb35c60SChris Kay# 2306eb35c60SChris Kay# x := outer-x 2316eb35c60SChris Kay# y = outer-y 2326eb35c60SChris Kay# 2336eb35c60SChris Kay# $(info $(call with,x y,inner-x inner-y,$$(x) $$(y))) # "inner-x inner-y" 2346eb35c60SChris Kay# 2356eb35c60SChris Kay# $(info $(x) ($(flavor x))) # "outer-x (simple)" 2366eb35c60SChris Kay# $(info $(y) ($(flavor y))) # "outer-y (recursive)" 2376eb35c60SChris Kay# 2386eb35c60SChris Kay# # Passing the text via `$(value ...)` to avoid `$$` escaping: 2396eb35c60SChris Kay# 2406eb35c60SChris Kay# text = [$(head)] [$(tail)] 2416eb35c60SChris Kay# $(call with,head tail,1 2 3 4,$(value text)) # "[1] [2 3 4]" 2426eb35c60SChris Kay# 2436eb35c60SChris Kay# # Nested usage: 2446eb35c60SChris Kay# 2456eb35c60SChris Kay# $(call with,a b,foo bar, \ 2466eb35c60SChris Kay# $$(call with,c d,baz qux,$$$$(a) $$$$(b) $$$$(c) $$$$(d))) 2476eb35c60SChris Kay# # "foo bar baz qux" 2486eb35c60SChris Kay# 2496eb35c60SChris Kay 2506eb35c60SChris Kaywith = $(with.ns.push)$(eval $(value with.core))$(with.ns.pop) 2516eb35c60SChris Kay 2526eb35c60SChris Kaywith.ns = with.ns.$(with.ns.stack.head) 2536eb35c60SChris Kay 2546eb35c60SChris Kaywith.ns.stack := 2556eb35c60SChris Kaywith.ns.stack.head = $(words $(with.ns.stack)) 2566eb35c60SChris Kay 2576eb35c60SChris Kaywith.ns.push = $(eval with.ns.stack += $(with.ns.stack.head)) 2586eb35c60SChris Kaywith.ns.pop = $($(with.ns).result)$(eval $(value with.ns.pop.1)) 2596eb35c60SChris Kay 2606eb35c60SChris Kaydefine with.ns.pop.1 = 2616eb35c60SChris Kay $(foreach variable,$(filter $(with.ns).%,$(.VARIABLES)),$\ 2626eb35c60SChris Kay $(eval undefine $(variable))) 2636eb35c60SChris Kay 2646eb35c60SChris Kay with.ns.stack := $(wordlist 2,$(with.ns.stack.head),$(with.ns.stack)) 2656eb35c60SChris Kayendef 2666eb35c60SChris Kay 2676eb35c60SChris Kaywith.bind.norm = $\ 2686eb35c60SChris Kay $(if $(findstring :,$(1)),$\ 2696eb35c60SChris Kay $(or $(filter l: p:,$(firstword $(subst :,: ,$(1)))),$\ 2706eb35c60SChris Kay $(error invalid binding specifier: $(1)))$\ 2716eb35c60SChris Kay $(or $(filter-out %:,$(word 2,$(subst :,: ,$(1)))),$\ 2726eb35c60SChris Kay $(error invalid binding specifier: $(1))),$\ 2736eb35c60SChris Kay l:$(1)) 2746eb35c60SChris Kay 2756eb35c60SChris Kaywith.bind.kind = $(word 1,$(subst :, ,$(call with.bind.norm,$(1)))) 2766eb35c60SChris Kaywith.bind.name = $(word 2,$(subst :, ,$(call with.bind.norm,$(1)))) 2776eb35c60SChris Kay 2786eb35c60SChris Kaydefine with.core = 2796eb35c60SChris Kay # Parse and record binding list/kinds/names from `$(1)` 2806eb35c60SChris Kay $(with.ns).bind.list := $(foreach b,$(1),$(call with.bind.norm,$(b))) 2816eb35c60SChris Kay $(with.ns).bind.names := $(foreach b,$(1),$(call with.bind.name,$(b))) 2826eb35c60SChris Kay $(with.ns).bind.kinds := $(foreach b,$(1),$(call with.bind.kind,$(b))) 2836eb35c60SChris Kay 2846eb35c60SChris Kay # Create a 1..=(N_bindings) list of binding indices 2856eb35c60SChris Kay $(with.ns).bind.idx := 2866eb35c60SChris Kay $(with.ns).bind.next = $(words 0 $($(with.ns).bind.idx)) 2876eb35c60SChris Kay 2886eb35c60SChris Kay $(foreach bind,$($(with.ns).bind.list),$\ 2896eb35c60SChris Kay $(eval $(with.ns).bind.idx += $($(with.ns).bind.next))) 2906eb35c60SChris Kay 2916eb35c60SChris Kay # Create a 2..=(N_arguments) list pointing to the text argument 2926eb35c60SChris Kay $(with.ns).text.idx := 2936eb35c60SChris Kay $(with.ns).text.next = $(words 1 2 $($(with.ns).text.idx)) 2946eb35c60SChris Kay $(with.ns).text = $($($(with.ns).text.next)) 2956eb35c60SChris Kay 2966eb35c60SChris Kay # Snapshot original flavors/values of all variables to be overwritten 2976eb35c60SChris Kay $(foreach bind.name,$($(with.ns).bind.names),$\ 2986eb35c60SChris Kay $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\ 2996eb35c60SChris Kay $(eval $(bind.name.ns).flavor := $(flavor $(bind.name))$\ 3006eb35c60SChris Kay $(eval $(bind.name.ns).value = $(value $(bind.name)))))) 3016eb35c60SChris Kay 3026eb35c60SChris Kay # Initialize per-kind buckets (e.g., `l`, `p`) 3036eb35c60SChris Kay $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\ 3046eb35c60SChris Kay $(eval $(with.ns).bind.kind[$(bind.kind)] := )) 3056eb35c60SChris Kay 3066eb35c60SChris Kay # Distribute binding indices into kind buckets 3076eb35c60SChris Kay $(foreach bind.i,$($(with.ns).bind.idx),$\ 3086eb35c60SChris Kay $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\ 3096eb35c60SChris Kay $(eval $(with.ns).bind.kind[$(bind.kind)] += $(bind.i)))) 3106eb35c60SChris Kay 3116eb35c60SChris Kay # Per-kind setup (e.g., to set up index vectors before binding) 3126eb35c60SChris Kay $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\ 3136eb35c60SChris Kay $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\ 3146eb35c60SChris Kay $(eval $(value with.core.$(bind.kind))))) 3156eb35c60SChris Kay 3166eb35c60SChris Kay # Perform binding from left to right 3176eb35c60SChris Kay $(foreach bind.i,$($(with.ns).bind.idx),$\ 3186eb35c60SChris Kay $(foreach bind.name,$(word $(bind.i),$($(with.ns).bind.names)),$\ 3196eb35c60SChris Kay $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\ 3206eb35c60SChris Kay $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\ 3216eb35c60SChris Kay $(eval $(value with.core.$(bind.kind).bind)))))) 3226eb35c60SChris Kay 3236eb35c60SChris Kay # Capture the expansion result from the current text pointer 3246eb35c60SChris Kay $(eval $(with.ns).result := $($(with.ns).text)) 3256eb35c60SChris Kay 3266eb35c60SChris Kay # Restore originals (flavor/value) or undefine if previously absent 3276eb35c60SChris Kay $(foreach bind.name,$($(with.ns).bind.names),$\ 3286eb35c60SChris Kay $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\ 3296eb35c60SChris Kay $(eval $(value with.core.restore)))) 3306eb35c60SChris Kayendef 3316eb35c60SChris Kay 3326eb35c60SChris Kaydefine with.core.l = 3336eb35c60SChris Kay # Create a 1..=(N_largs) list capturing the unbound `l` words 3346eb35c60SChris Kay $(bind.kind.ns).words.idx := 3356eb35c60SChris Kay $(bind.kind.ns).words.next = $(words 1 $($(bind.kind.ns).words.idx)) 3366eb35c60SChris Kay $(bind.kind.ns).words = $\ 3376eb35c60SChris Kay $(wordlist $($(bind.kind.ns).words.next),$(words $(2)),$(2)) 3386eb35c60SChris Kay 3396eb35c60SChris Kay # Increment the text pointer 3406eb35c60SChris Kay $(with.ns).text.idx += $($(with.ns).text.next) 3416eb35c60SChris Kayendef 3426eb35c60SChris Kay 3436eb35c60SChris Kaydefine with.core.l.bind = 3446eb35c60SChris Kay # Bind this name to the next unbound word 3456eb35c60SChris Kay $(bind.name) := $(firstword $($(bind.kind.ns).words)) 3466eb35c60SChris Kay 3476eb35c60SChris Kay # If this is the last `l` binding, absorb the remaining words 3486eb35c60SChris Kay ifeq ($($(bind.kind.ns).words.next),$(words $($(bind.kind.ns)))) 3496eb35c60SChris Kay $(bind.name) := $($(bind.kind.ns).words) 3506eb35c60SChris Kay endif 3516eb35c60SChris Kay 3526eb35c60SChris Kay # Nudge the word pointer forward 3536eb35c60SChris Kay $(bind.kind.ns).words.idx += $($(bind.kind.ns).words.next) 3546eb35c60SChris Kayendef 3556eb35c60SChris Kay 3566eb35c60SChris Kaydefine with.core.p = 3576eb35c60SChris Kay # Compute the parameter index that `p` bindings start at 3586eb35c60SChris Kay $(bind.kind.ns).param.offset := 1 2 3596eb35c60SChris Kay 3606eb35c60SChris Kay # When `l` bindings are present, `p` values shift right 3616eb35c60SChris Kay ifneq ($(filter l,$($(with.ns).bind.kinds)),) 3626eb35c60SChris Kay $(bind.kind.ns).param.offset += 3 3636eb35c60SChris Kay endif 3646eb35c60SChris Kay 3656eb35c60SChris Kay # Create an N_poff..=N_pargs list capturing the unbound `p` arguments 3666eb35c60SChris Kay $(bind.kind.ns).param.idx := 3676eb35c60SChris Kay $(bind.kind.ns).param.next = $\ 3686eb35c60SChris Kay $(words $($(bind.kind.ns).param.offset) $\ 3696eb35c60SChris Kay $($(bind.kind.ns).param.idx)) 3706eb35c60SChris Kay $(bind.kind.ns).param = $($(lastword $($(bind.kind.ns).param.idx))) 3716eb35c60SChris Kayendef 3726eb35c60SChris Kay 3736eb35c60SChris Kaydefine with.core.p.bind = 3746eb35c60SChris Kay # Mark the next parameter as bound 3756eb35c60SChris Kay $(bind.kind.ns).param.idx += $($(bind.kind.ns).param.next) 3766eb35c60SChris Kay 3776eb35c60SChris Kay # Bind this name to the next unbound argument 3786eb35c60SChris Kay $(bind.name) := $($(bind.kind.ns).param) 3796eb35c60SChris Kay 3806eb35c60SChris Kay # Increment the text pointer 3816eb35c60SChris Kay $(with.ns).text.idx += $($(with.ns).text.next) 3826eb35c60SChris Kayendef 3836eb35c60SChris Kay 3846eb35c60SChris Kaydefine with.core.restore = 3856eb35c60SChris Kay ifeq ($($(bind.name.ns).flavor),simple) 3866eb35c60SChris Kay $(eval $(bind.name) := $(value $(bind.name.ns).value)) 3876eb35c60SChris Kay else ifeq ($($(bind.name.ns).flavor),recursive) 3886eb35c60SChris Kay $(eval $(bind.name) = $(value $(bind.name.ns).value)) 3896eb35c60SChris Kay else ifeq ($($(bind.name.ns).flavor),undefined) 3906eb35c60SChris Kay undefine $(bind.name) 3916eb35c60SChris Kay endif 3926eb35c60SChris Kayendef 39310cb835fSChris Kay 39410cb835fSChris Kay# 39510cb835fSChris Kay# Quote a string for safe use as a shell word. 39610cb835fSChris Kay# 39710cb835fSChris Kay# Takes the input string `$(1)` and escapes any single quotes it contains so 39810cb835fSChris Kay# that the result can be safely used as a literal shell argument. The output is 39910cb835fSChris Kay# wrapped in single quotes to ensure that whitespace and special characters are 40010cb835fSChris Kay# preserved exactly when passed to the shell. 40110cb835fSChris Kay# 40210cb835fSChris Kay# This function is useful when constructing shell commands dynamically, since it 40310cb835fSChris Kay# guarantees that arbitrary values are quoted correctly and will not be 40410cb835fSChris Kay# misinterpreted by the shell. 40510cb835fSChris Kay# 40610cb835fSChris Kay# Parameters: 40710cb835fSChris Kay# 40810cb835fSChris Kay# - $(1): The string to quote for safe shell usage. 40910cb835fSChris Kay# 41010cb835fSChris Kay# Examples: 41110cb835fSChris Kay# 41210cb835fSChris Kay# $(call shell-quote,foo) # "'foo'" 41310cb835fSChris Kay# $(call shell-quote,bar baz) # "'bar baz'" 41410cb835fSChris Kay# $(call shell-quote,foo 'bar baz' qux) # "'foo '\''bar baz'\'' qux'" 41510cb835fSChris Kay# 41610cb835fSChris Kay 41710cb835fSChris Kayshell-quote = '$(subst ','\'',$(1))' 4185980fa7cSChris Kay 4195980fa7cSChris Kay# 4205980fa7cSChris Kay# Parse a shell fragment and extract the N-th word. 4215980fa7cSChris Kay# 4225980fa7cSChris Kay# Parses the shell fragment given by `$(2)` using the shell's word-splitting and 4235980fa7cSChris Kay# quoting rules, then prints the `$(1)`-th shell word in the result. If the 4245980fa7cSChris Kay# index is out of range then this function evaluates to an empty string. 4255980fa7cSChris Kay# 4265980fa7cSChris Kay# This function is useful when working with lists that may contain whitespace or 4275980fa7cSChris Kay# quoted values, since it relies on the shell to do the parsing rather than 4285980fa7cSChris Kay# Make's own word functions. Whitespace is preserved in the return value. 4295980fa7cSChris Kay# 4305980fa7cSChris Kay# Parameters: 4315980fa7cSChris Kay# 4325980fa7cSChris Kay# - $(1): The 1-based index of the word to extract. 4335980fa7cSChris Kay# - $(2): The shell fragment to parse. 4345980fa7cSChris Kay# 4355980fa7cSChris Kay# Example usage: 4365980fa7cSChris Kay# 4375980fa7cSChris Kay# $(call shell-word,1,foo 'bar baz' qux) # "foo" 4385980fa7cSChris Kay# $(call shell-word,2,foo 'bar baz' qux) # "bar baz" 4395980fa7cSChris Kay# $(call shell-word,3,foo 'bar baz' qux) # "qux" 4405980fa7cSChris Kay# $(call shell-word,4,foo 'bar baz' qux) # <empty> 4415980fa7cSChris Kay# 4425980fa7cSChris Kay 4435980fa7cSChris Kayshell-word = $(shell $(shell-word.sh)) 4445980fa7cSChris Kay 4455980fa7cSChris Kaydefine shell-word.sh = 4465980fa7cSChris Kay set -Cefu -- '' $(2); 4475980fa7cSChris Kay 4485980fa7cSChris Kay n=$(call shell-quote,$(1)); 4495980fa7cSChris Kay 4505980fa7cSChris Kay shift "$${n}"; 4515980fa7cSChris Kay printf '%s' "$${1:-}"; 4525980fa7cSChris Kayendef 4538165d826SChris Kay 4548165d826SChris Kay# 4558165d826SChris Kay# Parse a shell fragment and count the number of shell words. 4568165d826SChris Kay# 4578165d826SChris Kay# Parses the shell fragment given by `$(1)` using the shell's word-splitting and 4588165d826SChris Kay# quoting rules, then prints the total number of words in the result. 4598165d826SChris Kay# 4608165d826SChris Kay# This function is useful when working with lists that may contain whitespace or 4618165d826SChris Kay# quoted values, since it relies on the shell to do the parsing rather than 4628165d826SChris Kay# Make's own word functions. 4638165d826SChris Kay# 4648165d826SChris Kay# Parameters: 4658165d826SChris Kay# 4668165d826SChris Kay# - $(1): The shell fragment to parse. 4678165d826SChris Kay# 4688165d826SChris Kay# Example usage: 4698165d826SChris Kay# 4708165d826SChris Kay# $(call shell-words,) # "0" 4718165d826SChris Kay# $(call shell-words,foo) # "1" 4728165d826SChris Kay# $(call shell-words,foo bar baz) # "3" 4738165d826SChris Kay# $(call shell-words,foo 'bar baz' qux) # "3" 4748165d826SChris Kay# 4758165d826SChris Kay 4768165d826SChris Kayshell-words = $(shell $(shell-words.sh)) 4778165d826SChris Kayshell-words.sh = set -Cefu -- $(1); printf '%s' "$$\#"; 4789a782d40SChris Kay 4799a782d40SChris Kay# 4809a782d40SChris Kay# Parse a shell fragment and extract a sequence of shell words. 4819a782d40SChris Kay# 4829a782d40SChris Kay# Parses the shell fragment given by `$(1)` using the shell's word-splitting and 4839a782d40SChris Kay# quoting rules, then extracts the words from index `$(2)` up to but not 4849a782d40SChris Kay# including index `$(3)`. Each extracted shell word is returned sanitized for 4859a782d40SChris Kay# safe use in the shell. 4869a782d40SChris Kay# 4879a782d40SChris Kay# If `$(3)` is omitted, it defaults to one past the total number of words in the 4889a782d40SChris Kay# string, allowing you to express "all words starting from `$(2)`". 4899a782d40SChris Kay# 4909a782d40SChris Kay# This function is useful for safely selecting and passing subsequences of 4919a782d40SChris Kay# shell-parsed arguments into other shell commands, ensuring correct handling 4929a782d40SChris Kay# of whitespace and special characters. 4939a782d40SChris Kay# 4949a782d40SChris Kay# Parameters: 4959a782d40SChris Kay# 4969a782d40SChris Kay# - $(1): The shell fragment to parse. 4979a782d40SChris Kay# - $(2): The 1-based start index of the slice (default: 1). 4989a782d40SChris Kay# - $(3): The 1-based end index of the slice (exclusive). 4999a782d40SChris Kay# Defaults to all remaining words in the shell fragment. 5009a782d40SChris Kay# 5019a782d40SChris Kay# Example usage: 5029a782d40SChris Kay# 5039a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux) # "'foo' 'bar baz' 'qux'" 5049a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,1,3) # "'foo' 'bar baz'" 5059a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,2) # "'bar baz' 'qux'" 5069a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,2,4) # "'bar baz' 'qux'" 5079a782d40SChris Kay# $(call shell-slice,foo 'bar baz' qux,2,5) # "'bar baz' 'qux'" 5089a782d40SChris Kay# 5099a782d40SChris Kay 5109a782d40SChris Kayshell-slice = $(shell $(shell-slice.sh)) 5119a782d40SChris Kay 5129a782d40SChris Kaydefine shell-slice.sh = 5139a782d40SChris Kay set -Cefu -- $(1); 5149a782d40SChris Kay 5159a782d40SChris Kay n=$(if $(2),$(call shell-quote,$(2)),1); 5169a782d40SChris Kay m=$(if $(3),$(call shell-quote,$(3)),$$#); 5179a782d40SChris Kay 5189a782d40SChris Kay printf '%s\n' "$$@" $\ 5199a782d40SChris Kay | sed -n "$${n},$${m}p" $\ 5209a782d40SChris Kay | sed "s/'/'\\\\''/g; s/^/'/; s/\$$/'/"; 5219a782d40SChris Kayendef 522*a75ab9a7SChris Kay 523*a75ab9a7SChris Kay# 524*a75ab9a7SChris Kay# Join shell words with a custom delimiter. 525*a75ab9a7SChris Kay# 526*a75ab9a7SChris Kay# Parses the shell fragment given by `$(1)` using the shell's word-splitting and 527*a75ab9a7SChris Kay# quoting rules, then joins the resulting words together with the delimiter 528*a75ab9a7SChris Kay# specified by `$(2)`. If no delimiter is provided, no delimiter is used. 529*a75ab9a7SChris Kay# 530*a75ab9a7SChris Kay# This function is useful for safely rejoining a sequence of shell-parsed 531*a75ab9a7SChris Kay# arguments into a single string with controlled separators, ensuring that 532*a75ab9a7SChris Kay# whitespace and quoting are preserved correctly. 533*a75ab9a7SChris Kay# 534*a75ab9a7SChris Kay# Parameters: 535*a75ab9a7SChris Kay# 536*a75ab9a7SChris Kay# - $(1): The shell fragment to parse and join. 537*a75ab9a7SChris Kay# - $(2): The delimiter to insert between words (optional). 538*a75ab9a7SChris Kay# 539*a75ab9a7SChris Kay# Example usage: 540*a75ab9a7SChris Kay# 541*a75ab9a7SChris Kay# $(call shell-join,foo 'bar baz' qux) # "foobar bazqux" 542*a75ab9a7SChris Kay# $(call shell-join,foo 'bar baz' qux,:) # "foo:bar baz:qux" 543*a75ab9a7SChris Kay# $(call shell-join,foo 'bar baz' qux,;) # "foo;bar baz;qux" 544*a75ab9a7SChris Kay# 545*a75ab9a7SChris Kay 546*a75ab9a7SChris Kayshell-join = $(shell $(shell-join.sh)) 547*a75ab9a7SChris Kay 548*a75ab9a7SChris Kaydefine shell-join.sh = 549*a75ab9a7SChris Kay set -Cefu -- $(1); 550*a75ab9a7SChris Kay 551*a75ab9a7SChris Kay delimiter=$(call shell-quote,$(2)); 552*a75ab9a7SChris Kay 553*a75ab9a7SChris Kay printf '%s' "$${1:-}"; 554*a75ab9a7SChris Kay shift 1; 555*a75ab9a7SChris Kay 556*a75ab9a7SChris Kay while [ "$$#" -gt 0 ]; do 557*a75ab9a7SChris Kay printf '%s%s' "$${delimiter}" "$${1}"; 558*a75ab9a7SChris Kay shift 1; 559*a75ab9a7SChris Kay done 560*a75ab9a7SChris Kayendef 561