Skip to content

treewide: reduce usage of shell in Makefiles - #22669

Open
basilfx wants to merge 20 commits into
RIOT-OS:masterfrom
basilfx:feature/remove_makefile_shell
Open

treewide: reduce usage of shell in Makefiles#22669
basilfx wants to merge 20 commits into
RIOT-OS:masterfrom
basilfx:feature/remove_makefile_shell

Conversation

@basilfx

@basilfx basilfx commented Sep 6, 2026

Copy link
Copy Markdown
Member

Contribution description

Using $(shell ..) in Makefiles spawns a subprocess, which is less performant than built-in alternatives. Recalling #13174 from before, I let Claude analyze where this may improve on current master.

An overview:

  • $(shell basename $(CURDIR)) works the same as $(notdir $(CURDIR)) (unless $(CURDIR) equals /)
  • uppercase_and_underscore can be used instead of tr a-z- A-Z_
  • Use memoization for flags re-evaluated multiple times

The impact will be unnoticeable for a single build and will probably be in the noise when actual compilation takes the overhand. But (hopefully) it will be more noticeable for CI builds with warmer caches. I don't expect miracles, and it started as an experiment.

To give an idea of the improvement (I let Claude do the benchmarking) on my server (i5 14600K with 64 GiB of memory):

For make -j1 (rebuild, so warm cache):

App / board base head saving execve base → head
hello-world / nucleo-f767zi 2.30 s 0.66 s −71% 651 → 207 (−68%)
gnrc networking / nucleo-f767zi 3.23 s 1.10 s −66% 807 → 311 (−61%)
hello-world / samr21-xpro 1.19 s 0.65 s −46% 314 → 209 (−33%)
hello-world / native 0.54 s 0.41 s −23% 197 → 174 (−12%)

For make -j8 (rebuild, so warm cache):

App / board base head saving
hello-world / nucleo-f767zi 2.50 s 1.72 s −31%
gnrc networking / nucleo-f767zi 4.83 s 3.68 s −24%
hello-world / samr21-xpro 1.52 s 1.26 s −17%
hello-world / native 0.52 s 0.56 s ~0 (noise)

Testing procedure

This should not impact the builds. The end result should be the same.

To count subprocessed, one can use for example strace -f -qq -e trace=execve -o trace.txt make BOARD=nucleo-f767zi all. Then count the number of execve in the output file.

Issues/PRs references

None

Declaration of AI-Tools / LLMs usage:

AI-Tools / LLMs that were used are:

  • Claude Code Opus 5 for coming up with alternatives (especially strings.mk) and performing benchmarks. I have read an understand every line changed, but I am not a Makefile export, and it can probably be better.

@basilfx basilfx added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Sep 6, 2026
@github-actions github-actions Bot added Platform: native Platform: This PR/issue effects the native platform Platform: ARM Platform: This PR/issue effects ARM-based platforms Area: tests Area: tests and testing framework Area: build system Area: Build system Area: pkg Area: External package ports Area: cpu Area: CPU/MCU ports Area: toolchain Area: toolchains; everything related to compilation, libc, linking, … labels Sep 6, 2026
@basilfx basilfx added the AI: Co-Authored PR/Issue relies on AI. Documentation / Code was partly generated by AI. label Sep 6, 2026
@riot-ci

riot-ci commented Sep 6, 2026

Copy link
Copy Markdown

Murdock results

✔️ PASSED

369bf52 makefiles/toolchain: replace shell commands with functions

Success Failures Total Runtime
172224 0 172224 03h:29m:03s

Artifacts

@basilfx basilfx added CI: full build disable CI build filter CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR CI: full build disable CI build filter labels Sep 7, 2026
Comment thread makefiles/toolchain/gnu.inc.mk Outdated
Comment thread makefiles/toolchain/gnu.inc.mk Outdated
@basilfx basilfx removed the CI: full build disable CI build filter label Sep 7, 2026
@basilfx

basilfx commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

I wasn't expecting miracles, but I hoped for a bit more to be honest.

Full build took 03h 27m 11s. Its ~5 minutes faster, but I guess that is in the noise. Some older builds are equally 'fast' without the optimizations.

@crasbe

crasbe commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

I wasn't expecting miracles, but I hoped for a bit more to be honest.

I know that feeling 😅

@basilfx
basilfx force-pushed the feature/remove_makefile_shell branch from ccc1ea2 to 6fe1bce Compare September 7, 2026 21:19
@basilfx
basilfx requested a review from maribu as a code owner September 7, 2026 21:19
@basilfx
basilfx force-pushed the feature/remove_makefile_shell branch from 2e62b30 to 369bf52 Compare September 8, 2026 18:36
@github-actions github-actions Bot added Area: network Area: Networking Area: doc Area: Documentation Area: BLE Area: Bluetooth Low Energy support Area: boards Area: Board ports Platform: ESP Platform: This PR/issue effects ESP-based platforms Area: CoAP Area: Constrained Application Protocol implementations Area: sys Area: System and removed Area: CI Area: Continuous Integration of RIOT components labels Sep 8, 2026
@basilfx

basilfx commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

I also added a section on $(shell) usage in the documentation.

@basilfx basilfx added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR CI: full build disable CI build filter and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Sep 8, 2026
Comment thread cpu/stm32/stm32_info.mk
$(error Too short to be a valid STM32 CPU_MODEL: '$(CPU_MODEL)')
endif

# 'MP' is the only type that is spelled with two characters

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not true, there are also WB and WL.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't captured by the original regex. I'll look into it.

Comment on lines +47 to +50
$(info +++ FIXIT: Makefile: Add USEMODULE += unicoap_driver_dtls for CoAP over DTLS driver)
$(info +++ FIXIT: Makefile: Add USEMODULE += unicoap_driver_udp for CoAP over UDP driver)
$(info +++ FIXIT: Makefile: Add USEMODULE += unicoap_driver_rfc7252_pdu for CoAP over UDP/DTLS PDU parser only)
$(info +++ FIXIT: Makefile: Add USEMODULE += unicoap_driver_slipmux for CoAP over Slipmux driver)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a valid change, echoing to stderr is intentional here since some scripts of the build system interpret the output on stdout.

Ideally this should use $(call echoinfo,("+++ FIXIT...")), see https://doc.riot-os.org/build-system/build_system_basics/#printing-infos-warnings-and-error-messages

These functions do use a shell call, but printing to stderr is not supported with $(info) and printing colors with $(info) is not necessarily defined, although some code does that.

Comment thread Makefile.include
Comment on lines -340 to -343
# Check whether `which` is installed
ifeq ($(shell command -v which 2>/dev/null),)
$(error 'which' is required but not found in PATH.)
endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is there a big performance penalty for keeping the check? Perhaps @AnnsAnns can elaborate why he added the check?

@AnnsAnns

AnnsAnns commented Sep 9, 2026

Copy link
Copy Markdown
Member

Is the github PR review broken again, I cant directly comment for some reason?

Anyways, RE which check, if I remember correctly this check exists because we use which to check for stuff but when which is not installed it broke those checks in UB ways that caused the build system to create incorrect and misleading errors

Before using a `$(shell ...)` call, check whether one of the following
alternatives already covers the case:

- Use `$(notdir ...)` instead of `$(shell basename ...)` to strip the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Use `$(notdir ...)` instead of `$(shell basename ...)` to strip the
- Use `$(basename $(notdir ...))` instead of `$(shell basename ...)` to strip the

$(basename) strips the suffix as shell basename does

split_chars = $(strip $(subst 0, 0,$(subst 1, 1,$(subst 2, 2,$(subst 3, 3,$(subst 4, 4,$(subst 5, 5,$(subst 6, 6,$(subst 7, 7,$(subst 8, 8,$(subst 9, 9,$(subst a, a,$(subst b, b,$(subst c, c,$(subst d, d,$(subst e, e,$(subst f, f,$(subst g, g,$(subst h, h,$(subst i, i,$(subst j, j,$(subst k, k,$(subst l, l,$(subst m, m,$(subst n, n,$(subst o, o,$(subst p, p,$(subst q, q,$(subst r, r,$(subst s, s,$(subst t, t,$(subst u, u,$(subst v, v,$(subst w, w,$(subst x, x,$(subst y, y,$(subst z, z,$(subst A, A,$(subst B, B,$(subst C, C,$(subst D, D,$(subst E, E,$(subst F, F,$(subst G, G,$(subst H, H,$(subst I, I,$(subst J, J,$(subst K, K,$(subst L, L,$(subst M, M,$(subst N, N,$(subst O, O,$(subst P, P,$(subst Q, Q,$(subst R, R,$(subst S, S,$(subst T, T,$(subst U, U,$(subst V, V,$(subst W, W,$(subst X, X,$(subst Y, Y,$(subst Z, Z,$(subst _, _,$(subst -, -,$1)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

# Returns the first $1 characters of $2, like 'cut -c -$1' does.
first_chars = $(subst $(space),,$(wordlist 1,$1,$(call split_chars,$2)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chars_upto instead of first_chars

might fir better with chars_from

Suggested change
first_chars = $(subst $(space),,$(wordlist 1,$1,$(call split_chars,$2)))
chars_upto = $(subst $(space),,$(wordlist 1,$1,$(call split_chars,$2)))

@kfessel kfessel Sep 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or first_chars and last_chars

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Co-Authored PR/Issue relies on AI. Documentation / Code was partly generated by AI. Area: BLE Area: Bluetooth Low Energy support Area: boards Area: Board ports Area: build system Area: Build system Area: CoAP Area: Constrained Application Protocol implementations Area: cpu Area: CPU/MCU ports Area: doc Area: Documentation Area: drivers Area: Device drivers Area: network Area: Networking Area: pkg Area: External package ports Area: sys Area: System Area: tests Area: tests and testing framework Area: toolchain Area: toolchains; everything related to compilation, libc, linking, … Area: tools Area: Supplementary tools CI: full build disable CI build filter CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms Platform: ESP Platform: This PR/issue effects ESP-based platforms Platform: native Platform: This PR/issue effects the native platform Platform: RISC-V Platform: This PR/issue effects RISC-V-based platforms Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants