1# 2# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved. 3# 4# SPDX-License-Identifier: BSD-3-Clause 5# 6 7space := 8space := $(space) $(space) 9comma := , 10 11null := � 12 13compat-path = $(subst $(space),$(null),$(1)) 14decompat-path = $(subst $(null), ,$(1)) 15 16absolute-path = $(call decompat-path,$(abspath $(call compat-path,$(1)))) 17real-path = $(call decompat-path,$(realpath $(call compat-path,$(1)))) 18 19file-name = $(call decompat-path,$(notdir $(call compat-path,$(1)))) 20directory-name = $(call decompat-path,$(dir $(call compat-path,$(1)))) 21 22escape-shell = '$(subst ','\'',$(1))' 23 24# 25# The grouped-target symbol. Grouped targets are not supported on versions of 26# GNU Make <= 4.2, which was most recently packaged with Ubuntu 20.04. 27# 28 29& := $(if $(filter grouped-target,$(.FEATURES)),&) 30 31# 32# Upper-case a string value. 33# 34# Parameters: 35# 36# - $(1): The string to upper-case. 37# 38# Example usage: 39# 40# $(call uppercase,HeLlO wOrLd) # "HELLO WORLD" 41# 42 43uppercase = $(shell echo $(call escape-shell,$(1)) | tr '[:lower:]' '[:upper:]') 44 45# 46# Lower-case a string value. 47# 48# Parameters: 49# 50# - $(1): The string to lower-case. 51# 52# Example usage: 53# 54# $(call lowercase,HeLlO wOrLd) # "hello world" 55# 56 57lowercase = $(shell echo $(call escape-shell,$(1)) | tr '[:upper:]' '[:lower:]') 58 59# 60# Determine the "truthiness" of a value. 61# 62# Parameters: 63# 64# - $(1): The value to determine the truthiness of. 65# 66# A value is considered to be falsy if it is: 67# 68# - empty, or 69# - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing. 70# 71# If the value is truthy then the value is returned as-is, otherwise no value 72# is returned. 73# 74# Example usage: 75# 76# truthy := y 77# truthy-bool := $(call bool,$(truthy)) # "y" 78# 79# falsy := n 80# falsy-bool := $(call bool,$(falsy)) # <empty> 81# 82 83bool = $(filter-out 0 n no f false,$(call lowercase,$(1))) 84 85# 86# Determine the "truthiness" of a value, returning 0 or 1. 87# 88# Parameters: 89# 90# - $(1): The value to determine the truthiness of. 91# 92# A value is considered to be falsy if it is: 93# 94# - empty, or 95# - equal to "0", "N", "NO", "F" or "FALSE" after upper-casing. 96# 97# If the value is truthy then the value is returned as-is, otherwise no value 98# is returned. 99# 100# Example usage: 101# 102# truthy := y 103# truthy-bool := $(call bool,$(truthy)) # "1" 104# 105# falsy := n 106# falsy-bool := $(call bool,$(falsy)) # "0" 107# 108 109bool-01 = $(if $(call bool,$(1)),1,0) 110 111# 112# Determine whether a variable is defined or not. 113# 114# Parameters: 115# 116# - $(1): The variable to check. 117# 118# Example usage: 119# 120# xyz-defined := $(call defined,xyz) # <empty> 121# 122# xyz := 123# xyz-defined := $(call defined,xyz) # <non-empty> 124# 125# xyz := hello 126# xyz-defined := $(call defined,xyz) # <non-empty> 127# 128 129defined = $(call bool,$(filter-out undefined,$(origin $(1)))) 130 131# 132# Extract include directories from compiler flags and convert them to absolute 133# paths. 134# 135# Parameters: 136# 137# - $(1): A list of C compiler flags. 138# 139# Example: 140# 141# includes := $(call include-dirs, -nostdlib -Iinclude-dir) # /absolute/path/to/include-dir 142# 143 144include-dirs-pattern := $(call escape-shell,-I\s*("[^"]*"|'[^']*'|\S+)) 145include-dirs = $(shell \ 146 printf '%s' $(call escape-shell,$1) | \ 147 perl -nle 'print $$1 while /'$(include-dirs-pattern)'/g' | \ 148 xargs realpath \ 149) 150 151# 152# Determine the path to a program. 153# 154# Parameters: 155# 156# - $(1): The program to search for. 157# 158# Example usage: 159# 160# path-to-gcc := $(call which,gcc) # "/usr/bin/gcc" 161# 162 163which = $(shell command -v $(call escape-shell,$(1)) 2>/dev/null) 164 165# 166# Temporarily bind variables while expanding text (scoped "with"). 167# 168# Creates temporary variable bindings, expands a body of text with those 169# bindings in effect, then restores all affected variables to their previous 170# values and flavors (or undefines them if they did not exist). This provides a 171# "let"-style scope for variable assignments during text expansion. 172# 173# This function is modelled on the `let` function introduced in GNU Make 4.4: 174# 175# https://www.gnu.org/software/make/manual/html_node/Let-Function.html 176# 177# Binding specifiers (space-separated in `$(1)`): 178# 179# - l:name Bind from the word list in `$(2)`. Bindings are applied 180# left-to-right; the last `l` binding receives all remaining words 181# (which may be empty). If there are more `l` names than words, the 182# excess names are bound to empty values. 183# 184# - p:name Bind from subsequent call arguments (`$(2)`, `$(3)`, `$(4)`, ...), 185# in left-to-right order. If `l` bindings are present, these 186# arguments instead start from `$(3)`, following the word list. 187# 188# - name Treated as `l:name`. 189# 190# Parameters: 191# 192# - $(1): Space-separated binding specifiers. 193# - $(2): The list value used by `l` bindings, if present. 194# - $(2|3..N-1): Values for `p` bindings, in order (optional). 195# - $(N): The text to expand with the temporary bindings active. 196# 197# Evaluation and restoration: 198# 199# - All function arguments in Make are expanded at the call site. The text 200# must therefore be escaped (write `$$` to produce a literal `$`), or 201# supplied via `$(value ...)` to avoid premature expansion. 202# 203# - Whitespace in `l`-style bindings is processed in terms of Make words; if 204# you need to preserve whitespace then prefer `p` bindings. 205# 206# - Variables are assigned as simple (`:=`) during the text expansion. After 207# the text is expanded, each variable is restored to its previous state with 208# its original flavor (simple or recursive), or undefined if it did not 209# exist. Origins (e.g., command line, environment) are not preserved. 210# 211# Examples: 212# 213# # Basic list destructuring (two names from a list): 214# $(call with,foo bar,10 20,$$(foo) $$(bar)) # "10 20" 215# 216# # Last list binding receives the remainder: 217# $(call with,head tail,1 2 3 4,[$$(head)] [$$(tail)]) # "[1] [2 3 4]" 218# 219# # Extra list names bind to empty values: 220# $(call with,x y,9,x=<$$(x)> y=<$$(y)>) # "x=<9> y=<>" 221# 222# # Parameter-only bindings start in `$(2)`: 223# $(call with,p:x p:y,foo,bar,$$(x)-$$(y)) # "foo-bar" 224# 225# # Parameter bindings start in `$(3)` when list bindings are specified: 226# $(call with,l:lhs p:op l:rhs,10 20,+,$$(lhs) $$(op) $$(rhs)) # "10 + 20" 227# 228# # Variables are restored after expansion, with flavor preserved: 229# 230# x := outer-x 231# y = outer-y 232# 233# $(info $(call with,x y,inner-x inner-y,$$(x) $$(y))) # "inner-x inner-y" 234# 235# $(info $(x) ($(flavor x))) # "outer-x (simple)" 236# $(info $(y) ($(flavor y))) # "outer-y (recursive)" 237# 238# # Passing the text via `$(value ...)` to avoid `$$` escaping: 239# 240# text = [$(head)] [$(tail)] 241# $(call with,head tail,1 2 3 4,$(value text)) # "[1] [2 3 4]" 242# 243# # Nested usage: 244# 245# $(call with,a b,foo bar, \ 246# $$(call with,c d,baz qux,$$$$(a) $$$$(b) $$$$(c) $$$$(d))) 247# # "foo bar baz qux" 248# 249 250with = $(with.ns.push)$(eval $(value with.core))$(with.ns.pop) 251 252with.ns = with.ns.$(with.ns.stack.head) 253 254with.ns.stack := 255with.ns.stack.head = $(words $(with.ns.stack)) 256 257with.ns.push = $(eval with.ns.stack += $(with.ns.stack.head)) 258with.ns.pop = $($(with.ns).result)$(eval $(value with.ns.pop.1)) 259 260define with.ns.pop.1 = 261 $(foreach variable,$(filter $(with.ns).%,$(.VARIABLES)),$\ 262 $(eval undefine $(variable))) 263 264 with.ns.stack := $(wordlist 2,$(with.ns.stack.head),$(with.ns.stack)) 265endef 266 267with.bind.norm = $\ 268 $(if $(findstring :,$(1)),$\ 269 $(or $(filter l: p:,$(firstword $(subst :,: ,$(1)))),$\ 270 $(error invalid binding specifier: $(1)))$\ 271 $(or $(filter-out %:,$(word 2,$(subst :,: ,$(1)))),$\ 272 $(error invalid binding specifier: $(1))),$\ 273 l:$(1)) 274 275with.bind.kind = $(word 1,$(subst :, ,$(call with.bind.norm,$(1)))) 276with.bind.name = $(word 2,$(subst :, ,$(call with.bind.norm,$(1)))) 277 278define with.core = 279 # Parse and record binding list/kinds/names from `$(1)` 280 $(with.ns).bind.list := $(foreach b,$(1),$(call with.bind.norm,$(b))) 281 $(with.ns).bind.names := $(foreach b,$(1),$(call with.bind.name,$(b))) 282 $(with.ns).bind.kinds := $(foreach b,$(1),$(call with.bind.kind,$(b))) 283 284 # Create a 1..=(N_bindings) list of binding indices 285 $(with.ns).bind.idx := 286 $(with.ns).bind.next = $(words 0 $($(with.ns).bind.idx)) 287 288 $(foreach bind,$($(with.ns).bind.list),$\ 289 $(eval $(with.ns).bind.idx += $($(with.ns).bind.next))) 290 291 # Create a 2..=(N_arguments) list pointing to the text argument 292 $(with.ns).text.idx := 293 $(with.ns).text.next = $(words 1 2 $($(with.ns).text.idx)) 294 $(with.ns).text = $($($(with.ns).text.next)) 295 296 # Snapshot original flavors/values of all variables to be overwritten 297 $(foreach bind.name,$($(with.ns).bind.names),$\ 298 $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\ 299 $(eval $(bind.name.ns).flavor := $(flavor $(bind.name))$\ 300 $(eval $(bind.name.ns).value = $(value $(bind.name)))))) 301 302 # Initialize per-kind buckets (e.g., `l`, `p`) 303 $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\ 304 $(eval $(with.ns).bind.kind[$(bind.kind)] := )) 305 306 # Distribute binding indices into kind buckets 307 $(foreach bind.i,$($(with.ns).bind.idx),$\ 308 $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\ 309 $(eval $(with.ns).bind.kind[$(bind.kind)] += $(bind.i)))) 310 311 # Per-kind setup (e.g., to set up index vectors before binding) 312 $(foreach bind.kind,$(sort $($(with.ns).bind.kinds)),$\ 313 $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\ 314 $(eval $(value with.core.$(bind.kind))))) 315 316 # Perform binding from left to right 317 $(foreach bind.i,$($(with.ns).bind.idx),$\ 318 $(foreach bind.name,$(word $(bind.i),$($(with.ns).bind.names)),$\ 319 $(foreach bind.kind,$(word $(bind.i),$($(with.ns).bind.kinds)),$\ 320 $(foreach bind.kind.ns,$(with.ns).bind.kind[$(bind.kind)],$\ 321 $(eval $(value with.core.$(bind.kind).bind)))))) 322 323 # Capture the expansion result from the current text pointer 324 $(eval $(with.ns).result := $($(with.ns).text)) 325 326 # Restore originals (flavor/value) or undefine if previously absent 327 $(foreach bind.name,$($(with.ns).bind.names),$\ 328 $(foreach bind.name.ns,$(with.ns).bind.names[$(bind.name)],$\ 329 $(eval $(value with.core.restore)))) 330endef 331 332define with.core.l = 333 # Create a 1..=(N_largs) list capturing the unbound `l` words 334 $(bind.kind.ns).words.idx := 335 $(bind.kind.ns).words.next = $(words 1 $($(bind.kind.ns).words.idx)) 336 $(bind.kind.ns).words = $\ 337 $(wordlist $($(bind.kind.ns).words.next),$(words $(2)),$(2)) 338 339 # Increment the text pointer 340 $(with.ns).text.idx += $($(with.ns).text.next) 341endef 342 343define with.core.l.bind = 344 # Bind this name to the next unbound word 345 $(bind.name) := $(firstword $($(bind.kind.ns).words)) 346 347 # If this is the last `l` binding, absorb the remaining words 348 ifeq ($($(bind.kind.ns).words.next),$(words $($(bind.kind.ns)))) 349 $(bind.name) := $($(bind.kind.ns).words) 350 endif 351 352 # Nudge the word pointer forward 353 $(bind.kind.ns).words.idx += $($(bind.kind.ns).words.next) 354endef 355 356define with.core.p = 357 # Compute the parameter index that `p` bindings start at 358 $(bind.kind.ns).param.offset := 1 2 359 360 # When `l` bindings are present, `p` values shift right 361 ifneq ($(filter l,$($(with.ns).bind.kinds)),) 362 $(bind.kind.ns).param.offset += 3 363 endif 364 365 # Create an N_poff..=N_pargs list capturing the unbound `p` arguments 366 $(bind.kind.ns).param.idx := 367 $(bind.kind.ns).param.next = $\ 368 $(words $($(bind.kind.ns).param.offset) $\ 369 $($(bind.kind.ns).param.idx)) 370 $(bind.kind.ns).param = $($(lastword $($(bind.kind.ns).param.idx))) 371endef 372 373define with.core.p.bind = 374 # Mark the next parameter as bound 375 $(bind.kind.ns).param.idx += $($(bind.kind.ns).param.next) 376 377 # Bind this name to the next unbound argument 378 $(bind.name) := $($(bind.kind.ns).param) 379 380 # Increment the text pointer 381 $(with.ns).text.idx += $($(with.ns).text.next) 382endef 383 384define with.core.restore = 385 ifeq ($($(bind.name.ns).flavor),simple) 386 $(eval $(bind.name) := $(value $(bind.name.ns).value)) 387 else ifeq ($($(bind.name.ns).flavor),recursive) 388 $(eval $(bind.name) = $(value $(bind.name.ns).value)) 389 else ifeq ($($(bind.name.ns).flavor),undefined) 390 undefine $(bind.name) 391 endif 392endef 393 394# 395# Quote a string for safe use as a shell word. 396# 397# Takes the input string `$(1)` and escapes any single quotes it contains so 398# that the result can be safely used as a literal shell argument. The output is 399# wrapped in single quotes to ensure that whitespace and special characters are 400# preserved exactly when passed to the shell. 401# 402# This function is useful when constructing shell commands dynamically, since it 403# guarantees that arbitrary values are quoted correctly and will not be 404# misinterpreted by the shell. 405# 406# Parameters: 407# 408# - $(1): The string to quote for safe shell usage. 409# 410# Examples: 411# 412# $(call shell-quote,foo) # "'foo'" 413# $(call shell-quote,bar baz) # "'bar baz'" 414# $(call shell-quote,foo 'bar baz' qux) # "'foo '\''bar baz'\'' qux'" 415# 416 417shell-quote = '$(subst ','\'',$(1))' 418