Commit graph zephyr/scripts
Author SHA1 Message Date
Alberto Escolar Piedras
b3a11d8025 twister: script harness: Allow providing globs in tests_scripts
Let users provide their own globs.
When they do, let's just use the provided glob as is.

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
2026-08-19 17:11:15 +01:00
Alberto Escolar Piedras
e28b81892a twister: script harness: Also find scripts in subdirectories
When a directory is provided, find scripts in directories and
sub-directories.
This is what users expect.

Note that now we also name the tests not just based on the "basename" of
the file, but on the relative path to the tests.yaml so we ensure we have
unique tests names.

We also sort the globing output.

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
2026-08-19 17:11:15 +01:00
Alberto Escolar Piedras
0dc486b6db twister: script harness: Handle gracefully not finding any script
We may also not find any script at all (say the folder is empty,
or there is no tests_scripts folder).
Let's handle it gracefully too, by printing an appropriate
message instead of pointing at the build log.

This fixes more cases than what was covered by
60643b7b05

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
2026-08-19 17:11:15 +01:00
Muhammad Waleed Badar
0791e4c24e dts: add devicetree support for the dma-ranges property
Zephyr's devicetree tooling parses and generates macros
for the ranges property but has no equivalent support for
dma-ranges, even though both are defined the same way by
the Devicetree Specification (§2.3.9) and edtlib.py already
has the machinery to parse address-translation triplets.

This adds the same pipeline that already exists for ranges.
edtlib.py now parses dma-ranges into Node. dma_ranges using
the same cell-based translation logic as Node via a new
_init_dma_ranges() method.

gen_defines.py emits DT_N_..._DMA_RANGES_* macros for each node
with a dma-ranges property through a new write_dma_ranges() function.

devicetree.h gains the DT_DMA_RANGES_* public API, including HAS_IDX,
CHILD_BUS_ADDRESS_BY_IDX, PARENT_BUS_ADDRESS_BY_IDX, LENGTH_BY_IDX,
NUM_DMA_RANGE, and FOREACH_DMA_RANGE. base.yaml documents the dma-ranges
property per DT spec §2.3.9.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
2026-08-19 17:09:21 +01:00
Tim Pambor
dbd6698fc0 scripts: west: build: retain quotes for SB_CONFIG_ in extra_args
The extra_args parsing only treated arguments starting with "CONFIG_"
as config options whose surrounding quotes must be preserved.
Sysbuild config options prefixed with "SB_CONFIG_" were classified as
non-config candidates, which stripped their quotes and could mangle
values.

Extend the prefix check to also match "SB_CONFIG_" so sysbuild config
options are handled identically to regular config options

Signed-off-by: Tim Pambor <tim.pambor@codewrights.de>
2026-08-19 11:17:53 +02:00
Loek Le Blansch
e417dffd80 scripts/build: allow whitespace between function name and parenthesis
This commit changes the syscall regex to allow whitespace between a
syscall's function name and the opening parenthesis of the argument list.

Signed-off-by: Loek Le Blansch <loek.le-blansch.pv@renesas.com>
2026-08-18 17:20:51 -04:00
Anas Nashif
ac4666dac2 twister: detect faults reported after a test passes
Harness.process_test() failed a run on a kernel fatal error only when
two conditions held: the console line had to be exactly equal to
"ZEPHYR FATAL ERROR", and the fault had to be seen before the test
printed "PROJECT EXECUTION SUCCESSFUL". Neither holds in practice.

z_fatal_error() prints ">>> ZEPHYR FATAL ERROR %d: %s on CPU %d",
normally through LOG_ERR and therefore behind a timestamp and a module
prefix, so no console line ever compares equal to the marker. The
Console harness has always matched it as a substring and worked; the
Test and Ztest harnesses rely on process_test() alone, so for them
fault detection never triggered at all. The existing unit test passed
the bare marker as the whole line, which is why this went unnoticed.

Match the marker as a substring, move the check ahead of the RUN_PASSED
branch, and withdraw a PASS that was recorded earlier in the output.
Tests that fault on purpose are unaffected: they opt out with
ignore_faults, which clears fail_on_fault. Drop the now duplicated
check in Console.handle(), which process_test() covers.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-17 16:30:10 -04:00
Jukka Rissanen
953835d93a net: packet: Add support for multicast membership add/drop
A packet socket can be used to add or drop a multicast group
membership in L2 level. This means that application can ask
the network device to start to listen extra multicast L2 addresses.
This uses PACKET_ADD_MEMBERSHIP and PACKET_DROP_MEMBERSHIP
socket options which can be set using setsockopt() API.

As the same link layer address can be needed by several users at once,
the Ethernet L2 keeps track of the multicast addresses that an
interface listens to and tells the driver to change its receive filter
only when a group is joined by its first user or left by its last one.
The IP level joins, the packet socket memberships and the filters that
an application sets with net_eth_mac_filter() all share this count.
Previously they were given to the driver separately, so leaving one
group could stop the device from listening to another one that needs
the same link layer address. That happens easily as IPv4 multicast
addresses map 32:1 to link layer addresses.

The membership change is given straight to net_eth_mcast_addr_add() and
net_eth_mcast_addr_rm(), so that setsockopt() can tell the application
when the interface cannot serve the group. There is no interface level
callback list in between, as a callback cannot report back that the
address did not fit.

The addresses can be read back with net_eth_mcast_addr_foreach(), so a
driver may also treat ETHERNET_CONFIG_TYPE_FILTER as a hint that the
set of addresses changed and reprogram its filter from scratch. That
suits devices that filter by a hash of the address.

How many addresses an interface can track is the sum of what the
enabled subsystems ask for with their own
NET_L2_ETHERNET_MCAST_FILTER_ADD_COUNT_ options, summed at build time
the same way as the system heap size is. The new
NET_L2_ETHERNET_MCAST_FILTER_COUNT option raises the result if an
application needs more addresses than the subsystems asked for. A
group that does not fit is not joined at all, as programming it
without tracking it would break the drivers that read the addresses
back and the group would be lost as soon as another user of the same
address left.

A device that cannot filter passes the group up anyway, so the group is
joined and tracked also when the driver has no receive filter. The
address is then ready for a filter that the device programs later, and
setsockopt() does not fail on a device that receives the group without
being told to.

A VLAN interface has no receive filter of its own, so a group joined
on one is programmed to the Ethernet interface it is attached to.

Note that a multicast destination address given to net_eth_mac_filter()
is now counted like any other user of the group, so each such filter
that an application sets must also be unset by it, and unsetting one
that was never set fails with -ENOENT.

Assisted-by: Claude:Opus-5
Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
2026-08-17 16:26:38 -04:00
William Jeffreys
181bd4b54b scripts: runners: probe-rs: Rename 'attach' RTT command to 'rtt'
RTT support was previously exposed via `west attach` (commit 3c7d9732),
but attach is meant for debugging without reflashing, not RTT. This
renames the relevant runner methods so `west rtt` is used instead,
avoiding confusion. Note this breaks the previous (incorrect) `west
attach` invocation for RTT.

Signed-off-by: William Jeffreys <wjeffreys96@gmail.com>
2026-08-17 10:26:03 +02:00
Anas Nashif
f73914b99f ci: annotate coding guideline violations on the changed lines
The job reported every violation as a single annotation attached to
output.txt. That file does not exist in the tree, so GitHub could only
show it as a job level annotation and the actual findings were buried in
the workflow log.

Give guideline_check.py an --annotate option, following the convention
check_compliance.py already uses, that emits one workflow command per
violation with the real path and line. GitHub then renders them on the
changed lines in the pull request. The rule number is lifted out of the
message into the annotation title so the finding is identifiable without
expanding it.

GitHub keeps only the first 10 annotations of a level per step, so cap
them there and summarise the rest in a single warning. output.txt still
lists every violation and remains what fails the job.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-15 08:12:32 -04:00
Anas Nashif
e6b837e656 scripts: coccinelle: check for unnamed function parameters
MISRA C:2012 Rule 8.2 requires every parameter in a function type to be
named, including the parameters of function pointer parameters. Nothing
in CI caught that, so violations kept being introduced.

Add a rule that walks the parameter list of every function declaration
and definition and reports any parameter that carries a type but no
identifier, recursing into the parameter lists of function pointer
parameters. Macro invocations parse as function declarations, so
identifiers without a lower case letter are skipped, as is the text of
the preprocessor directives that a conditionally compiled parameter list
leaves in the parameter tokens.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-15 08:12:32 -04:00
Anas Nashif
54da97077c scripts: ci: match coccinelle violations in any path
The pattern used to parse the coccinelle output only accepted letters,
digits, underscores and slashes in the file name, so a violation
reported against a path containing anything else was silently dropped.
Zephyr has plenty of those: include/zephyr/sys/libc-hooks.h and every
other hyphenated file name never produced a finding.

Accept anything up to the colon that separates the path from the line
number instead, and require at least one digit for that line number.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-15 08:12:32 -04:00
Gustav Holmberg
18e4be1b71 runners: iar: create complete launch.json file + other minor fixes
Generate complete version of debug launch file and use better defaults
(Enable zephyr plugin, use correct vector table symbol and use reset
strategy with bootloader when available. Also add launch file path to
CMakeCache to automatically load the launch file in Embedded Workbench.

Signed-off-by: Gustav Holmberg <gustav.holmberg@qt.io>
2026-08-14 16:11:57 -04:00
Benjamin Cabé
cd24209e5b scripts: zspdx: add software_artifactSize to SBOM
SPDX 3.1 introduced a new field for the size of software artifacts.
Capture file sizes in the SBOM model at scan time and emit them when
serializing SPDX 3.1 output.

Assisted-by: Claude:fable-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-08-12 19:27:00 -04:00
Benjamin Cabé
cce85fd3e2 scripts: zspdx: add SPDX 3.1 support
Spec is still WIP but adding support for it will be useful to work on
adding more features to the SBOM, e.g. requirements or tests.

Assisted-by: Claude:fable-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-08-12 19:27:00 -04:00
Appana Durga Kedareswara rao
ec1d451b7b scripts: coredump: enumerate per-CPU SMP threads
With the target exporting CPU_STRIDE/NUM_CPUS offsets (see the companion
kernel commit), teach the host coredump scripts to enumerate one current
thread per CPU.

elf_parser.py exposes the two new offset-table entries and, instead of
capping get_kernel_thread_info_offset() at a hardcoded ceiling, bounds
it by the count actually read from the target binary so an older build
with fewer entries degrades a newer field to "not present" rather than
reading out of bounds.

gdbstub.py's qfThreadInfo walk now enumerates one current thread per CPU
(cpus[i].current = K_CURR_THREAD + i * CPU_STRIDE) instead of one total.
Targets whose offsets table lacks CPU_STRIDE/NUM_CPUS (older or non-SMP
builds) get None back for those entries and degrade to the original
single-CPU behavior.

Signed-off-by: Appana Durga Kedareswara rao <appana.durga.kedareswara.rao@amd.com>
2026-08-12 19:25:12 -04:00
Chris Friedt
76008e5270 scripts: ci: doxygen_coverage_diff: append warn-paths
Previously, the last --warn-paths argument would replace any previous one
that was specified on the command line. Use action="append" to ensure that
all of the arguments are collected.

Signed-off-by: Chris Friedt <chris@fr4.co>
2026-08-12 19:25:02 -04:00
Daniel DeGrasse
3c459dbd15 scripts: ci: check_compliance: fix checks for board extensions
Board extensions do not require the presence of a "Kconfig.<board_name>"
file in order to function correctly, so we should use "osource" when
sourcing these board Kconfig files. The primary board directory's
Kconfig file is still sourced normally, as this Kconfig file is
required.

Signed-off-by: Daniel DeGrasse <daniel.degrasse@analog.com>
2026-08-12 10:03:33 -04:00
Anas Nashif
33cd388312 twister: handlers: do not set "Unknown Error" reason on passing tests
The QEMU monitor thread's _thread_update_instance_info() stamped the
instance reason with "Unknown Error" whenever the harness provided no
reason, regardless of the resulting status. Passing harnesses supply
no reason, so every passing QEMU test instance silently carried
reason="Unknown Error". The classic console output only prints the
reason for failures, which kept this invisible, but trying to view
status using other means reveals this issue.

Only fall back to "Unknown Error" when the status is actually a
failure (failed/error) and no more specific reason is known. For
non-failure results clear the reason instead of keeping it, so a
stale reason from an earlier retry iteration cannot stick to a
now-passing instance.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-11 17:03:36 -04:00
Appana Durga Kedareswara rao
8f807f76c1 scripts: coredump: gdbstub: add ARM64 thread-walk support
GdbStub_ARM64 never implemented arch_supports_thread_operations(), so
it always inherited the base class's `return False`. In practice this
meant `info threads` in GDB only ever showed the single faulting
thread, even for CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_THREADS dumps that
structurally contain every thread's k_thread struct and stack -- the
data was already there, this script just had no path to expose it.

Add that path by reading each non-current thread's saved context out
of its k_thread.callee_saved struct. On ARM64,
z_arm64_context_switch() (arch/arm64/core/switch.S) stores a
non-running thread's x19-x29, sp_elx, and lr directly into that struct
(unlike Cortex-M, which pushes a hardware exception frame onto the
thread's own stack), and a resumed thread continues via `ret` using
the saved lr, so lr doubles as the thread's resume PC.

The generic thread-info offsets table (subsys/debug/thread_info.c)
only exposes sp_elx individually, as
THREAD_INFO_OFFSET_T_STACK_PTR = offsetof(k_thread, callee_saved.sp_elx).
Derive the base of the callee_saved struct from that single offset
instead of adding new table entries, keeping this a self-contained
script change.

Enabling thread operations makes the base-class qThreadExtraInfo path
reachable, which had an off-by-one: thread_id is 1-based and indexed as
thread_id - 1, but the guard used `len(thread_ptrs) > thread_id`, so the
last enumerated thread got an empty response and lost its name/state in
`info threads`. Use `>=` so the final thread is included.

Validated on versalnet_apu_se9 hardware coredumps: non-SMP THREADS-mode
scenarios now enumerate all threads (e.g. 10 for the coredump_threads
ztest: 7 worker threads, test_crash, idle, main) with correct names
and distinct, semantically valid backtraces, with no change to
MIN/LINKER_RAM or SMP scenarios (which have no thread-list data to
walk in the first place).

Signed-off-by: Appana Durga Kedareswara rao <appana.durga.kedareswara.rao@amd.com>
2026-08-11 17:03:08 -04:00
Paul Wedeck
91ad9073ff scripts: runners: blackmagicprobe: disable pagination during flashing
During flashing, a gdb load command is performed.
This command prints out each segment it writes and ask the user to press
enter or 'c' to continue when it prints more lines that the height of the
terminal. When performing "west flash" in a small terminal, this requires
user interaction during flashing which is both annoying and unnecessary.
This behavior is disabled using "set pagination off".

Signed-off-by: Paul Wedeck <paulwedeck@gmail.com>
2026-08-11 07:45:45 -04:00
Sylvio Alves
3f969c6984 scripts: dts: only warn on a locally declared required default
The required-with-a-default check runs on the property settings
left after includes are merged, so a binding that inherits a
default and deliberately overrides it with required was reported
even though nothing is wrong.

That combination is well defined: the required check runs first
and errors out when the property is absent, so the inherited
default never applies. Keep a copy of the properties declared
locally and warn only when both settings come from the same file.

Included files are merged into the raw contents in place, which
also covers any nested child binding, so the copy is taken before
the merge and handed down to each child binding in turn. A child
binding which is only inherited declares nothing of its own and
so gets an empty copy. Add tests covering the reported and the
exempt cases, up to the grandchild binding level.

Assisted-by: Claude Code:opus-4-8
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
2026-08-11 07:45:33 -04:00
Pieter De Gendt
5911d9006b scripts: style: Add test cases for CMake/Kconfig style checkers
Add pytest unit tests for the CMake and Kconfig style checkers: one
flagged and one clean snippet per rule, asserting the exact set of rules
raised. Snippets are passed as strings, so no fixture files are committed
(which the compliance checks would otherwise scan). Both suites run in
the Scripts tests workflow.

Assisted-by: Claude Code:claude-opus-4.8
Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2026-08-07 07:02:48 -04:00
Pieter De Gendt
eb4ef86614 scripts: kconfig: make blank-line rules continuation-aware
The if-blank and decl-blank checks assumed single-line statements, so a
backslash-continued 'if' condition produced false positives: the blank
required after 'if' was checked at the keyword line (a continuation
line), and the block-opener exemption for declarations tested that
continuation line instead of the opener keyword.

Follow continuations to the statement's start and end in both checks.
Also require the continuation backslash to be the final character, since
a backslash before trailing whitespace escapes it rather than continuing
the line.

Assisted-by: Claude Code:claude-opus-4.8
Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2026-08-07 07:02:48 -04:00
Henrik Brix Andersen
12cb84a54a scripts: requirements: actions: basic: refresh pinned versions
Run the uv command to update the pinned versions in
requirements-actions-basic.txt.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2026-08-06 14:38:43 +02:00
Henrik Brix Andersen
4a38ebbb4c scripts: requirements: actions: refresh pinned versions
Run the uv command to update the pinned versions in
requirements-actions.txt.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2026-08-06 14:38:43 +02:00
Henrik Brix Andersen
500c0b7844 scripts: requirements: west: refresh pinned versions
Run the uv command to update the pinned version in requirements-west.txt.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2026-08-06 14:38:43 +02:00
Anas Nashif
697b323954 ci: sanitizers: report native_sim findings to code scanning
Add a workflow that runs the test suite on native_sim under the
sanitizers and reports what they find to the GitHub code scanning
dashboard, as the dynamic counterpart to the CodeQL and GCC
analyzer scans. Those infer what might go wrong; this records what
actually did, so the findings are proven reachable and uploaded at
error level. Coverage is bounded by what the tests exercise, which
is the opposite trade-off, and neither kind of scan subsumes the
other.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 21:35:49 -04:00
Anas Nashif
b89b283220 ci: gcc: add static analyzer scan with SARIF upload
cmake/sca/gcc has been able to drive the GCC static analyzer for
some time, but nothing in CI uses it. Wire it up and report the
findings to the GitHub code scanning dashboard. Unlike the CodeQL
and Eclair scans this needs no license and no extra tooling:
-fanalyzer ships with the toolchain the tree is already built
with.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 21:35:49 -04:00
Anas Nashif
be88746fbd ci: set_assignees: add --reset to re-staff a pull request
The script only ever adds to a pull request: labels, review requests and
an assignee accumulate across runs.  There is no way to correct one that
was staffed badly, or to re-apply the current MAINTAINERS.yml to a pull
request that was opened before an area changed hands.

Add --reset, which works out the new staffing first and then, just
before applying it, undoes what an earlier run decided: it withdraws the
review requests, removes every assignee and strips the area labels that
MAINTAINERS.yml defines, leaving the pull request labelled, reviewed and
assigned as if it had just been opened.

Doing this late rather than on entry matters twice over.  Every skip
condition -- draft, closed, more than MAX_FILES changed files -- has had
its say by then, so a reset cannot strip a pull request the run goes on
to decline.  And the reviewers about to be requested again are known, so
their existing request is left in place instead of being withdrawn and
re-sent, which would notify them twice.

Four things survive the reset:

  - Reviewers who submitted a review or commented on the pull request or
    one of its review threads.  They are involved by their own action,
    and dropping their request would either lose that or notify them
    again.  This covers approvals and changes-requested reviews
    regardless of the verdict.
  - Team review requests.  The script only ever requests individuals, so
    a team was requested by hand and a reset has no basis to withdraw it.
  - Size labels, which update_size_labels recomputes and prunes on every
    run anyway; removing them here would double-remove.
  - Labels the script does not own, such as 'bug' or backport labels.
    They are not derived from MAINTAINERS.yml, so a reset has no basis
    for second-guessing whoever added them.

People who removed themselves from the review request are not re-added:
_add_reviewers already refuses to request them, and the reset's own
removals are made by the token account, so they do not read as
self-removals either.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 17:58:54 -04:00
Anas Nashif
01b334b5db ci: set_assignees: keep the top labels instead of dropping them all
A pull request matching more than MAX_LABELS (10) area labels had its
label step skipped entirely, on the grounds that labelling a change with
a dozen areas says nothing.  The result was worse: the broadest pull
requests, the ones hardest to route, ended up with no area label at all.

Rank the collected labels by how much of the pull request the areas
carrying them cover, and apply the MAX_LABELS highest-ranked ones
instead, so the same limit now caps how many labels are applied rather
than deciding whether any are.  A label's rank is the sum of the file
weights of every touched area carrying it, falling back to the plain
file count for areas weighted 0.  Those weights are zeroed for assignee
selection -- meta-areas, files that only matched CMakeLists.txt,
repeated matches of one Platform area -- but such an area still
describes what the pull request changes, and without the fallback a
documentation-only pull request would rank 'area: Documentation' last
and drop it first.  Ties break by name to keep the outcome
deterministic.

Size labels take no part in this.  They are computed for the pull
request alone and update_size_labels has already pruned the stale ones,
so they neither count towards the limit -- ten area labels plus a size
label is not an overflow -- nor can be dropped by it.

The limit governs what a run applies; no label is ever taken off the
pull request, whether a human or an earlier run put it there.  --reset
is the way to clear those.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 17:58:54 -04:00
Anas Nashif
f4f52189fa ci: set_assignees: narrow the heuristic reviewer tiers
Changed files that MAINTAINERS.yml cannot staff (files in under-covered
areas, files in no area at all) fall back to two heuristics: GitHub's own
suggestedReviewers, then the recent contributors to those files.  Both
ran whenever such a file was present, however well staffed the rest of
the pull request already was, so a single orphaned file was enough to
append lower-confidence names to a review request that already held the
people responsible for the change.

Skip both heuristics once the touched areas have yielded
MIN_TOTAL_REVIEWERS (3) candidates other than the author, who cannot
review their own pull request.  The count is taken across all areas, so
two thinly staffed areas that together cover the pull request no longer
trigger the fallback either.

Also limit the commit walk to the last HISTORY_MAX_AGE_DAYS (365) days.
A contributor who has not touched a file within a year is unlikely to
still be the right person to ask, and on long-lived files the unbounded
history filled every heuristic slot with people who have moved on.  The
window is applied by GitHub via the 'since' parameter, so it also cuts
the API cost of the walk.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 17:58:54 -04:00
Anas Nashif
3b4681e57f ci: set_assignees: never treat meta-areas as under-covered
An area that names no maintainers, or at most two collaborators, is
considered under-covered: it cannot staff a review on its own, so recent
Git contributors to its files are added as heuristic reviewers.

That test misfires on meta-areas.  They match large parts of the tree by
design and name few people on purpose, so a documentation- or
samples-only pull request would walk the history of every file it
touches and request reviews from people on top of the maintainers and
collaborators who already own the area.

Skip areas carrying 'meta: true' when collecting under-covered areas.
Files matched only by a meta-area no longer feed the heuristic; files
that a thin non-meta area also claims still do, as do orphaned files
that match no area at all.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 17:58:54 -04:00
Anas Nashif
d73563fdbd maintainers: declare meta-areas in MAINTAINERS.yml
Meta-areas, i.e. areas that cut across the whole tree instead of owning
one subsystem, were hardcoded as name lists in two CI scripts:
set_assignees.py (META_AREAS) and sync_maintainer_tests.py
(_META_AREAS).  The two lists had drifted apart and both had gone stale:
they named "Release Notes" and "Boards", neither of which is an area in
MAINTAINERS.yml anymore.

Move the classification into MAINTAINERS.yml itself as an optional
per-area 'meta: true' key, so it lives in one place next to the area it
describes and new meta-areas can be added without touching any script.
get_maintainer.py validates the key as a boolean, exposes it as
Area.meta and prints it alongside the other area fields.

Both scripts now read that key instead of their own list.  As the two
lists are unified, membership changes slightly: Benchmarks is no longer
weighted when picking a pull request assignee, and Documentation and
Release no longer get auto-generated 'tests' entries.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-05 17:58:54 -04:00
Adarsha Regmi
8925ae2806 toolchain: llvm: add ELD (ld.eld) linker support
ELD (“Embedded Linker”) is Qualcomm's open source, LLVM-based,
GNU-compatible linker designed for the needs of embedded systems. It can be
selected as an alternative to LLD when building Zephyr with the LLVM
toolchain.

This change adds a CONFIG_LLVM_USE_ELD Kconfig option and the required
CMake integration to locate ld.eld and use it during linking. A minimum ELD
version is enforced (22.0+) to ensure required linker-script features are
available.

ELD was discussed in several Zephyr Toolchain WG meetings from February
through June 2026. The meeting notes include links to recordings and
presentation slides covering key features such as linker plugins, LTO with
linker scripts, section budgeting, and rich diagnostics for facilitating
debugging.

Meeting notes: https://docs.google.com/document/d/1nFKhdhbxKhECvcVhwHQNytov3TbcN_eDUvPwPXlmXEM/edit#heading=h.8l0u6j5vo01p
Recording: https://zoom.us/rec/share/ztjugOyQ_zZcOf9zrZpomk2zxxE6aWeyvVJIUP2L-enc_wFubVJARkhOGlpzIEV2.nzAOoV97lPNrm_EB
Slides: https://riscv.atlassian.net/wiki/download/attachments/159286264/Invited%20Talk%20-Qualcomm%20Embedded%20Linker%20%E2%80%93%20Open%20sourcing.pdf?api=v2

ELD repository: https://github.com/qualcomm/eld
ELD docs: https://qualcomm.github.io/eld/

Prebuilt ELD binaries can be found on eld's github releases page:
https://github.com/qualcomm/eld/releases

Signed-off-by: Adarsha Regmi <aregmi@qti.qualcomm.com>
2026-08-05 18:36:15 +01:00
Ricardo Cañuelo Navarro
a1bbee39ab runners: openocd: add option to append gdb commands for debug
Add a `--gdb-pre-debug` option to allow appending commands to run before
starting a debugging session, after the gdb `load` command is issued.

This can be used in targets that require a specific setup for the
`debug` command, such as initialization commands to leave the board
ready and in a known state.

Signed-off-by: Ricardo Cañuelo Navarro <rcn@igalia.com>
2026-08-05 13:53:41 +01:00
Anas Nashif
870a471f1a scripts: ci: fix twisterlib import in test plan scripts
Both test plan scripts imported TwisterStatus through the package path
'pylib.twister.twisterlib.statuses'. Modules inside twisterlib import
each other with absolute 'twisterlib.<module>' names, which only resolve
when scripts/pylib/twister is on sys.path - something only the
scripts/twister launcher did. That spelling worked by accident as long
as statuses.py had no intra-package imports; commit fc599d0e3e added
'from twisterlib.error import StatusAttributeError' to it and the import
started raising ModuleNotFoundError.

test_plan.py aborted outright. In test_plan_v2.py the same import sat
inside a bare try/except ImportError that returned 0, so _count_errors()
always reported no errors and the script exited 0 even when test
configurations failed.

Put scripts/pylib/twister on sys.path in both scripts and import
'twisterlib.statuses' directly, matching every other consumer of the
package, then drop the try/except so an unimportable TwisterStatus is a
hard failure rather than a silently miscounted result. Importing via
both spellings would otherwise create two distinct TwisterStatus enum
classes whose members compare unequal under 'is'.

Fixes #114208

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-04 14:10:02 +01:00
Pieter De Gendt
0e9ea868bc scripts: west_commands: runners: intel_cyclonev: Fix ZEPHYR_BASE
Use the ZEPHYR_BASE constant from zephyr_ext_common instead of relying
on the ZEPHYR_BASE environment variable, which may not be set.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2026-08-04 06:54:24 -04:00
Anas Nashif
9fb83c881d twister: include the handler's stderr in the JSON report
BinaryHandler captures the test binary's stderr to its own file,
handler_stderr.log, which no report ever reads. Whatever the
binary wrote there is therefore absent from twister.json and from
everything derived from it.

This is most visible with UndefinedBehaviorSanitizer on
native_sim. It writes its diagnostics to stderr rather than
stdout, so a run it aborts is recorded as a bare "rc=1": the
report says the test failed and nothing at all about why, even
though the reason was captured and sits on disk next to the
build. The same applies to any crash or loader failure that
reports on stderr.

Append the captured stderr to the log already selected for a
failing instance, rather than replacing it, so the stdout
transcript that shows how far the test got is preserved and the
stderr diagnostic explaining the failure follows it. Only failing
instances are affected, and only when stderr is non-empty, so
passing runs and reports for handlers that do not capture stderr
are unchanged.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2026-08-04 06:53:52 -04:00
Benjamin Cabé
a119dbf957 build: bump minimum CMake version to 3.28.0
Raise the minimum required CMake version from 3.20.0 (documented as
3.20.5) to 3.28.0, which is satisfied by the CMake 3.28.3 package
shipped in the Ubuntu 24.04 LTS repositories. Ubuntu 24.04 is the
current Ubuntu LTS release targeted by the Zephyr getting started
guide, and by the time of the next Zephyr release, Ubuntu 22.04 will be
within months of its end of standard support. Users of distributions
shipping an older CMake can use the Kitware APT repository or a
pip-installed CMake, as the documentation already suggests.

Raising the floor to 3.28 unlocks a range of modern CMake features for
the build system, among which the cmake_file_api() command (3.27),
file(COPY_FILE) (3.21), block()/endblock() (3.25), and allows removal
of several version-conditional workarounds.

The tree-wide cmake_minimum_required() occurrences in samples, tests
and boards are updated accordingly, together with the documentation
and the sysbuild CMake presets. The IAR C-STAT integration keeps its
own higher requirement (4.1.0).

Assisted-by: Claude:fable-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-08-03 15:03:35 -04:00
Benjamin Cabé
fa7c9bd867 scripts: zspdx: relate each source package to its dependency package
A module appears twice in the SBOM: as a "-sources" package (its
checked-out source tree, in the zephyr document) and as a "-deps"
package (its upstream identity for vulnerability tracking, in the
modules-deps document). Nothing connected the two, so a consumer could
not tell they describe the same module.

Add a VARIANT_OF relationship from each source package to its
dependency package (rendered as hasVariant in SPDX 3.0), so the checked-
out sources are tied to the upstream dependency they are a variant of.
The same link is added between zephyr-sources and zephyr-deps.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Cursor:opus-4.8
2026-08-03 15:02:24 -04:00
Benjamin Cabé
c772649795 scripts: zspdx: place ExternalDocumentRef in the creation-info section
ExternalDocumentRef was emitted after Created, past the Document
Creation Information section. Strict tag-value parsers reject that
("unknown tag ExternalDocumentRef in CreationInfo section") and fail to
load the document. Emit it right after DocumentNamespace and before
Creator, where the specification places it.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Cursor:opus-4.8
2026-08-03 15:02:24 -04:00
Benjamin Cabé
515db9a1b1 scripts: zspdx: describe source and dependency packages
The role of a module's "-sources" package versus its "-deps" package is
not self-evident, and a "-deps" package is emitted for every module in
the manifest even when its code is not built, which looks surprising.
Attach a package comment to each explaining what it represents and why
it is present.

This also replaces the "Utility target; no files" comment that was
applied to every fileless package: it was left over from the CMake
utility targets (now excluded) and mislabelled the source and
dependency packages.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Cursor:opus-4.8
2026-08-03 15:02:24 -04:00
Benjamin Cabé
1872775fb4 scripts: zspdx: exclude CMake UTILITY targets from the SBOM
CMake UTILITY targets (menuconfig, ram_report, run/flash/debug, code
generation helpers, ...) are build-system conveniences, not software
components. They produced empty, purposeless packages that only added
noise to the build SBOM, so skip them while walking the codemodel.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Cursor:opus-4.8
2026-08-03 15:02:24 -04:00
Benjamin Cabé
6df57abace scripts: zspdx: derive package supplier and purl from module metadata
Components lacking a supplier or a package URL are flagged by SBOM
quality tooling and cannot be matched against vulnerability databases.
Populate both for Zephyr and its modules from the metadata already in
zephyr.meta: the git remote yields a supplier organization and a
revision-pinned purl. Modules recorded under "url" instead of "remote"
are now handled too, and curated purls from a module's security
metadata are left untouched.

In SPDX 3.0 the supplier is an Agent reference rather than a string, so
each package's suppliedBy points at a shared, deduplicated Organization
element.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Cursor:opus-4.8
2026-08-03 15:02:24 -04:00
Benjamin Cabé
db5c91e23f scripts: zspdx: record SBOM author and tool version
An SBOM should declare who authored it and which tool version produced
it; both were missing, so provenance/quality checks scored zero. Add
"The Zephyr Project" as the creating organization and stamp the
generator with the Zephyr version read from the VERSION file.

The values are recorded on the SBOM graph metadata by the walker and
emitted by both serializers: as SPDX 2.x Creator lines, and in SPDX 3.0
as an Organization in CreationInfo.createdBy plus a packageUrl on the
tool (which has no dedicated version field).

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Cursor:opus-4.8
2026-08-03 15:02:24 -04:00
Benjamin Cabé
a6281547d1 scripts: ci: check_compliance: add option to run checks in parallel
The compliance checks currently run strictly one after the other. Most of
the total runtime is spent in the Kconfig-based checks, each of which
parses a full Kconfig tree on its own.

Add a -p/--parallel [N] option that runs the checks in a pool of N worker
processes (one per CPU by default). Each check runs in its own process,
which also isolates the environment variable mutations and module imports
the Kconfig checks perform. The Kconfig-based checks are scheduled first
so the slowest checks are not left running alone at the end.

Enable the new option in the compliance workflow, where the runtime of
the Kconfig checks now roughly amounts to the single slowest check
instead of the sum of all of them.

Assisted-by: Claude:fable-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-08-02 11:43:26 -04:00
Benjamin Cabé
a4c8ddd9a8 scripts: ci: check_compliance: abort the whole run on Ctrl-C
Each compliance check runs inside a try/except that catches BaseException
and turns any error into a failure for that check. This also caught
KeyboardInterrupt, so pressing Ctrl-C only aborted the check that happened
to be running and the loop carried on with the next one instead of
stopping the whole run.

Re-raise KeyboardInterrupt from the per-check handler so it propagates, and
handle it in main() with a clean "Interrupted" exit instead of dumping a
traceback.

Assisted-by: Claude:opus-4.8
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2026-08-02 11:43:26 -04:00
Alberto Escolar Piedras
e201b84b04 twister harness robot: Handle better missing robot executable
Depending on conditions, PermissionError may also be raised if there
is no executable to run.
So let's also handle it in the same way.
This expands on the fix from a18fd195bf

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
2026-07-31 20:09:24 -04:00
Perry Naseck
cd88dea51a scripts: checkpatch: Recognize tagged types from function-like macros
checkpatch reported a false-positive SPACING error for pointer
declarations whose type name comes from a function-like macro, e.g.
"struct GPIO_FAST_DISPATCH_TYPE(NODE) *spec", because the macro's
parentheses were parsed as a call and the '*' as a multiply. Add a
branch to annotate_values() that consumes a struct/union/enum tag plus a
function-like macro as part of the type so the '*' is seen as a pointer.
Requiring the tag avoids misclassifying genuine multiplies like
"u32(5) * 2". Closes #113747.

Assisted-by: Claude:claude-opus-4.8

Signed-off-by: Perry Naseck <pnaseck@media.mit.edu>
2026-07-31 14:53:09 -04:00