Commit Graph

1409 Commits

Author SHA1 Message Date
Igor Velkov
1b74748622
Extension: ccache-remote — shared compilation cache via Redis/HTTP (#9369)
* add hook to allow customizing before kernel make env creation
* Hook runs in docker_cli_prepare_launch() just before DOCKER_EXTRA_ARGS
is processed, allowing extensions to add Docker arguments with a more
descriptive hook name than add_host_dependencies.
* Extension: ccache-remote

Enables ccache with remote Redis storage for sharing compilation cache across build hosts.

Features:
- Auto-discovery via Avahi/mDNS (ccache.local hostname)
- Explicit Redis server configuration via CCACHE_REMOTE_STORAGE
- Build statistics display at end of build (hit/miss/error rates)
- Support for both Docker and native builds
- Hooks for kernel and u-boot compilation environments

Documentation includes server setup instructions with security warnings,
client mDNS configuration, and cache sharing requirements.


* uboot: fix ccache environment and add extension hook

U-Boot build uses `env -i` which clears all environment variables.
CCACHE_DIR and CCACHE_TEMPDIR were not explicitly passed to make,
unlike kernel build (kernel-make.sh). This caused ccache to use
default directory instead of configured Armbian one, breaking
cache statistics and shared cache functionality.

Changes:
- Add CCACHE_DIR and CCACHE_TEMPDIR to uboot_make_envs
- Add uboot_make_config hook for extensions (similar to kernel_make_config),
  allowing modification of environment variables before compilation

* add long list of allowed ccache-related env vars
* set permissions to ccache files RW for everyone if cache not private
* ccache: add ccache_post_compilation hook for extensions
* ccache-remote: use ccache_post_compilation hook instead of cleanup handler

Show remote ccache stats after each compilation (kernel, uboot) via hook,
instead of once at the end via cleanup handler. Stats now shown even on
build failure.

* ccache: show stats with safe arithmetic
* ccache/uboot: improve code comments per review feedback

- uboot.sh: clarify ARMBIAN=foe workaround for dual-compiler scenario
- ccache-remote.sh: document that CCACHE_REDIS_CONNECT_TIMEOUT must be
  set before extension loads

* ccache-remote: mask storage URLs in logs

Mask CCACHE_REMOTE_STORAGE when emitting Docker env debug logs.

* ccache-remote: extract ccache_inject_envs() helper to deduplicate passthrough loops

Extract ccache_inject_envs() helper to deduplicate identical passthrough
loops in kernel and uboot make config hooks.

ccache-remote: rename functions to follow project naming conventions

Rename get_redis_stats and mask_storage_url to ccache_get_redis_stats
and ccache_mask_storage_url to follow project naming conventions.

ccache-remote: mask credentials in debug log output for passthrough loops

Mask CCACHE_REMOTE_STORAGE value through ccache_mask_storage_url() before
logging in both Docker env and make env passthrough loops to avoid leaking
credentials into build logs.

* ccache-remote: add HTTP/WebDAV backend and DNS discovery
* ccache-remote: move extension script into directory layout
* ccache-remote: add server setup docs and config files
* ccache-remote: validate Redis credentials in URLs
* ccache-remote: document Redis auth options and safe passwords

Add separate insecure config example for trusted networks.

Recommend URL-safe hex passwords and update setup docs.

* ccache-remote: improve Docker loopback handling and IPv6 host parsing
2026-03-01 01:18:35 +01:00
Igor Velkov
986f77495b drop deprecated KERNEL_UPGRADE_FREEZE feature
Was only used once (orangepi5pro.csc) and has been deprecated.
Remove the implementation, the board config, and the README entry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 01:15:10 +01:00
Igor Velkov
ac9d08cc97 (#9400 P3c) armbian-bsp-cli-deb: safe array assignment from word splitting
Replace unquoted array assignment `arr=(${var})` with
`IFS=' ' read -ra arr <<< "${var}"` to prevent glob expansion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:15:10 +01:00
Igor Velkov
cb3bedf527 (#9400 P3b) patching: add missing -r flag to read
Other read calls in the same file already use -r.
Without -r, backslashes in user input are interpreted as escape characters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:15:10 +01:00
Igor Velkov
a0123f5d7a fix(kernel-headers): preserve build-time autoconf.h across postinst olddefconfig (#9425)
При упаковке linux-headers скомпилированные бинарники из scripts/ удаляются,
так как они собраны под хост сборки, а не под целевую машину (типичный случай
кросс-сборки). Поэтому postinst при установке пакета пересобирает их нативно,
предварительно запустив `make olddefconfig`.

Однако olddefconfig не только подготавливает окружение — он заново вычисляет
конфигурацию ядра, проверяя тулчейн, доступный на целевом хосте при установке.
Если инструменты, использовавшиеся при сборке ядра, на целевой машине отсутствуют
или имеют другую версию, olddefconfig молча отключает соответствующие CONFIG_*
опции (например, CONFIG_CC_IS_CLANG, CONFIG_LTO_CLANG, CONFIG_DEBUG_INFO_BTF).

В результате установленный пакет заголовков описывает не то ядро, которое
реально собрано и работает, а то, которое можно было бы собрать на данном хосте.

Это затрагивает:
- include/generated/autoconf.h (используется препроцессором C)
- include/config/auto.conf + маркер-файлы include/config/ (используются
  make-правилами kbuild)
- include/generated/rustc_cfg (используется Rust-сборками)

Все эти файлы — артефакты сборки и должны описывать скомпилированное ядро,
а не возможности хоста установки.

Исправление: при упаковке сохраняем сайдкар-тарбол с build-time версиями
include/config/ и include/generated/{autoconf.h,rustc_cfg}; восстанавливаем
его в postinst в самом конце, после всех make-шагов.

Fixes: https://github.com/armbian/build/issues/9425

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 22:29:08 +01:00
SuperKali
a8977dcd7d kernel: centralize netfilter legacy xtables config for all families
Add version-gated NETFILTER_XTABLES_LEGACY and BRIDGE_NF_EBTABLES_LEGACY
support in armbian-kernel.sh for kernels >= 6.18. Also add missing
ebtables table modules (BRIDGE_EBT_BROUTE, BRIDGE_EBT_T_FILTER,
BRIDGE_EBT_T_NAT) unconditionally to the nftables config function.

This ensures all hardware families automatically get legacy xtables
support when building kernels 6.18+, fixing Docker and Proxmox
firewall breakage without requiring per-family config changes.
2026-02-24 04:46:50 +01:00
Timothy Parys
aaad48ef6b Properly handle git submodules when GIT_FIXED_WORKDIR is set 2026-02-23 00:51:03 +01:00
Aurimas Niekis
e832bb3129 feat(drivers): add RTL8812EU/RTL8822EU wireless driver for EXTRA_WIFI
Integrate the libc0607/rtl88x2eu-20230815 out-of-tree driver into the build
system under EXTRA_WIFI for kernels >= 3.14 and < 6.19.

- Fetch pinned upstream commit ccb31f4ee346d5c2dd45475d276171b2f8de8350
- Install sources under drivers/net/wireless/rtl8822eu
- Enable AP and P2P modes in driver Makefile
- Hook into kernel Kconfig and Makefile via CONFIG_RTL8822EU

Tested working on `6.12.74-current-sunxi` and `6.6.75-legacy-sunxi`.
2026-02-22 16:59:49 +01:00
Sven-Ola Tuecke
e527a1783f OrangePi-RV2: add support for RISCV64 compile-to-binaries.
Required to compile BCM bluetooth firmware hacking tool.

Signed-off-by: Sven-Ola Tuecke <sven-ola@gmx.de>
2026-02-19 22:10:34 -05:00
tabris
d8e24d7619 framework run_host_x86_binary_logged - unset QEMU_CPU 2026-02-18 15:03:08 -05:00
Igor Velkov
ed371f5f5a
(#9400 P3a) Replace useless cat with input redirection (#9404)
* (#9400 P3a) trap-logging: replace useless cat with direct file arguments

- gzip < file → gzip -c file (direct argument, -c for stdout)
- cat file | ansi2txt → ansi2txt < file (ansi2txt has no file argument)
- Remove now-unnecessary shellcheck disable=SC2002 comments

* (#9400 P3a) logging: replace useless cat with direct file argument

- cat file | grep | sed → grep file | sed (grep accepts filename directly)
- Remove now-unnecessary shellcheck disable=SC2002 comment

* (#9400 P3a) initrd: replace useless cat with direct file argument

- cat file | md5sum → md5sum file (md5sum accepts filename directly)

* (#9400 P3a) write-device: replace useless cat with direct file argument

- cat file | awk → awk file (awk accepts filename directly)
- Remove now-unnecessary shellcheck disable=SC2002 comment

* (#9400 P3a) export-logs: replace useless cat with direct file argument

- cat file | sed → sed file (sed accepts filename directly)
- Remove now-unnecessary shellcheck disable=SC2002 comment

* (#9400 P3a) python-tools: replace cat subshell with $(<file) syntax

- $(cat file) → $(< file) (bash builtin, no subprocess)

* (#9400 P3a) artifact-armbian-base-files: replace useless cat with direct file argument

- cat file | grep → grep file (grep accepts filename directly)
2026-02-18 09:28:14 +01:00
Igor Velkov
9e251e885f extension: kernel-version-toolchain for compiler in artifact version
Add opt-in extension that includes gcc/clang major.minor version in the
kernel artifact version string for cache invalidation when the toolchain
changes. Enable with ENABLE_EXTENSIONS="kernel-version-toolchain".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 14:21:28 -05:00
Igor Velkov
baa0fdb2dc artifact/kernel: add hook for customizing version parts
Replace single-line version suffix assembly with an extensible two-array
approach: artifact_version_parts (associative, key=value) and
artifact_version_part_order (indexed, "NNNN-KEY" for sortable insertion).

Extensions can add, modify, or remove parts via the
artifact_kernel_version_parts hook. Keys starting with "_" are
internal-only and not prefixed in the output.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 14:21:28 -05:00
Igor Velkov
2f834c2508 artifact/kernel: deduplicate config hash inputs
Reduce kernel_config_modifying_hashes to last assignment per key before
hashing, so that overridden config options do not cause unnecessary
cache invalidation. Uses tac|sort to implement last-value-wins
deduplication.

Co-Authored-By: tabrisnet <tabrisnet@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 14:21:28 -05:00
Rosen Penev
65d823f343
board configs: disable unprivelaged BPF (#9082)
Fixes wrong CPU vulnerability output:

/sys/devices/system/cpu/vulnerabilities/spectre_v2:Mitigation:Vulnerable: Unprivileged eBPF enabled

It's enabled but CONFIG_BPF_UNPRIV_DEFAULT_OFF being unset causes the warning.

This warning happens on ARM32 and ARM64 devices.

Edited with:
find -name "*.config" -exec sed -i 's/# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set/CONFIG_BPF_UNPRIV_DEFAULT_OFF=y/g' '{}' ;

CONFIG_BPF_UNPRIV_DEFAULT_OFF is a Linux kernel build-time hardening option that disables unprivileged use of the bpf() syscall (and thus unprivileged eBPF loading) by default by setting kernel.unprivileged_bpf_disabled=2 at boot. With this default, only privileged processes (e.g., with CAP_SYS_ADMIN / CAP_BPF, depending on kernel) can load eBPF unless an administrator explicitly relaxes it. [1], [2]
Operational behavior you should know

kernel.unprivileged_bpf_disabled semantics (as documented in the kernel sysctl docs/patch):

    0: unprivileged bpf() allowed
    1: unprivileged bpf() blocked and cannot be re-enabled until reboot (no transition back to 0 while running)
    2: unprivileged bpf() blocked but admin can later switch to 0 or 1 if needed
    If CONFIG_BPF_UNPRIV_DEFAULT_OFF=y, the default becomes 2 instead of 0. [2]

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2026-02-08 14:33:35 -05:00
Igor Pecovnik
4c963e2930 docker: improve auto-pull cronjob with opt-in flag and cleanup
- Add ARMBIAN_DOCKER_AUTO_PULL environment variable (opt-in, must be explicitly set to "yes")
- Move auto-pull cronjob setup from requirements to docker CLI
- Add automatic cleanup of cronjob files when flag is disabled/removed
- Remove verbose "unchanged" messages for cleaner output
- Simplify control flow in docker_ensure_auto_pull_cronjob()
2026-02-01 00:22:54 +01:00
Igor Pecovnik
882d7e3dfd docker: add automatic image pull cronjob and cleanup system
- Add docker_cleanup_old_images() to remove dangling images and keep only 2 most recent per tag
- Add docker_pull_with_marker() to pull images and update marker files tracking last pull time
- Add docker_setup_auto_pull_cronjob() to create/update system cronjob and wrapper script via hash-based detection
- Add docker_ensure_auto_pull_cronjob() to ensure cronjob is installed and up-to-date
- Create self-contained wrapper script at /usr/local/bin/armbian-docker-pull for cron execution
- Store configuration hash in /var/lib/armbian/docker-pull.hash for smart update detection
- Install cronjob at /etc/cron.d/armbian-docker-pull to pull images every 12 hours
- Move cronjob setup from docker_cli_prepare() to requirements command
- Cronjob is now only installed when users explicitly run ./compile.sh requirements
- Prevents "12 hours since last pull, pulling again" delay during builds

Signed-off-by: Igor Pecovnik <igor@armbian.com>
2026-02-01 00:22:54 +01:00
Igor Velkov
b7bc3a770d clang: enable colored diagnostic output for kernel compilation
When building kernels with KERNEL_COMPILER=clang, compiler warnings
were displayed without color despite -fdiagnostics-color=always being
set in KCFLAGS. This GCC-native flag is not reliably honored by clang
when invoked through ccache and the kernel build system with LLVM=1.

Add -fcolor-diagnostics (clang's native flag) to the clang-specific
extra_warnings to ensure colored warning output.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 17:12:25 +01:00
Igor Velkov
e9f1902134
uwe5622: fix compilation with clang on Linux 6.19 (#9314)
In Linux 6.19, net_device->dev_addr is const unsigned char *.
Clang with -Werror,-Wincompatible-pointer-types-discards-qualifiers
rejects passing dev_addr to non-const parameters and memcpy into it.

Fix by:
- Replacing memcpy(dev->dev_addr, ...) with dev_addr_set()
- Using local buffer + ether_addr_copy for sprdwl_set_mac_addr call
  that needs mutable addr (the function modifies it in-place)
- Changing u8 *mac pointer to u8 mac[ETH_ALEN] array in cfg80211.c
  where dev_addr was assigned to a non-const pointer

Relates to #9049
2026-01-31 13:51:07 +01:00
Ricardo Pardini
82a8f85644 cli: kernel-dtb: check dtc for version 1.7.2 before producing normalized dts
- 1.7.2 does not resolve phandles in dts<->dts mode, which is much more useful
- I learned about this from https://lore.kernel.org/u-boot/20251219024102.145220-1-marek.vasut+renesas@mailbox.org/
- also add `-s` (sorted) flag, which further enhances comparability
- hint: Debian Trixie has 1.7.2; Ubuntu Noble only 1.7.0
2026-01-25 11:36:34 +01:00
Igor Velkov
a661744d1d kernel: add custom_kernel_make_params extension hook
Add a new extension hook point in run_kernel_make_internal() that allows
extensions to modify kernel make parameters before compilation.

Extensions can now modify:
- common_make_params_quoted - parameters passed to make
- common_make_envs - environment variables for make

This enables features like CROSS_COMPILE_COMPAT for 32-bit compat vDSO
on arm64 builds without modifying core build scripts.

Refs: https://github.com/armbian/build/issues/9216

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:36:20 +01:00
Igor Pecovnik
97f91102c1 rootfs: enable loong64 in qemu binfmt registration
Add loong64 to the list of architectures prepared by prepare_host_binfmt_qemu_cross().
This allows automatic registration and use of qemu-user emulation for LoongArch64
guests, enabling rootfs bootstrap and CI workflows targeting loong64.

This aligns Armbian with Debian’s upcoming native loong64 support (Forky) and allows
testing already via debian-ports and qemu-system-loongarch64.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
2026-01-22 14:32:05 +01:00
Igor Velkov
e9885c71af Fix "modpost not foud" error since error in rust coreutils uutils/coreutils#8924 2026-01-22 12:25:08 +01:00
Igor Velkov
ccfe604902 memoize: add user feedback and configurable timeout for flock
When the memoize cache lock is held by another process (e.g., a stale
Docker container from a previous interrupted build), the build would
hang indefinitely without any feedback to the user.

This change:
- First tries non-blocking flock, acquiring immediately if available
- If lock is busy, informs user and waits with periodic status messages
- Adds MEMOIZE_FLOCK_WAIT_INTERVAL (default 10s) for message frequency
- Adds MEMOIZE_FLOCK_MAX_WAIT (default 0=infinite) for optional timeout
- Allows user to interrupt with Ctrl+C
- Suggests checking for stale containers: docker ps -a | grep armbian

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 01:40:21 +01:00
Ricardo Pardini
3b25162398 change-tracking: also track UBOOT_COMPILER & KERNEL_COMPILER 2026-01-21 01:39:50 +01:00
Igor Velkov
40e8c03730 Framework: Add "Repeat Build Options" string at the end in case of error or break 2026-01-21 01:39:23 +01:00
Igor Velkov
0a52e654ad Disable APA for sid too
(https://github.com/armbian/build/pull/9164#issuecomment-3756552792)
2026-01-16 08:10:03 -05:00
Igor Velkov
976b7ae524 Revert "lib / main-config.sh: enable APA extension for questing and resolute builds. Closes: #8966"
This reverts commit ca73176bd9.
2026-01-16 08:10:03 -05:00
Ricardo Pardini
947d349385 change-tracking: track most ATF related vars 2026-01-16 08:13:01 +01:00
Ricardo Pardini
edc3dc124d artifact-uboot: hash ATFSOURCE
- if/when we change `ATFSOURCE`, we want u-boot artifacts to be rebuilt
2026-01-15 20:17:43 +01:00
Ricardo Pardini
cb36a6b10b lib: drop unused functions/general/downloads.sh (get_urls())
- dead code for a very long time
2026-01-14 20:08:21 +01:00
Ricardo Pardini
acfd9c8dcb "get completely rid of dead code toolchain stuff", pt2
- this stuff has been laying around, unused, for years
2026-01-14 20:08:21 +01:00
Ricardo Pardini
84a7e45f29 u-boot: fix and unify CROSS_COMPILE and PATH after predatory maintenance
- also avoid spurious space in `CROSS_COMPILE` when `CCACHE` is not set
2026-01-14 20:08:21 +01:00
Ricardo Pardini
c51b973217 drop UBOOT_USE_GCC, KERNEL_USE_GCC, ATF_USE_GCC completely
- also `CRUST_USE_GCC`
- those don't serve any purpose and cause confusion
2026-01-14 20:08:21 +01:00
Ricardo Pardini
6889c8c0a4 drop find_toolchains, SKIP_EXTERNAL_TOOLCHAINS and all $toolchain PATH injections
- we've had SKIP_EXTERNAL_TOOLCHAINS=yes for ~5 years now
- drop all usages, mostly through `find_toolchains()`
- drop all manual PATH env injections (we've centralized if ever needed)
2026-01-14 20:08:21 +01:00
Ricardo Pardini
001c65df07 u-boot: run binwalk on all the produced u-boot bins (always)
- optionally, if UBOOT_BINS_TO_OUTPUT=yes, copy them out to output/
- this might reveal differences in binwalk itself more than u-boot
- but better than nothing
2026-01-12 23:37:03 +01:00
Ricardo Pardini
6e7d2798e3 u-boot: allow custom LOGLEVEL with UBOOT_LOGLEVEL (default to 6) 2026-01-09 00:40:11 +01:00
Ricardo Pardini
7213d8e8c6 u-boot: better CONFIG_LOG/LOGLEVEL/LOG_MAX_LEVEL (=6) 2026-01-09 00:40:11 +01:00
Ricardo Pardini
287931ac6e armbian-kernel: more eBPF-oriented options for userspace tooling 2026-01-08 19:40:54 +01:00
Ricardo Pardini
574abb9cad host-release: allow to build on resolute 2026-01-08 19:28:26 +01:00
Igor Velkov
9922402de8 !fixup cleanup 2026-01-08 12:24:18 +01:00
Igor Velkov
e92c53a03f Include DEST_LANG in rootfs cache hash calculation
The `DEST_LANG` variable affects rootfs cache content (locale is generated via
`locale-gen "${DEST_LANG}"` before cache is packaged), but it was not included in the
cache hash calculation.

This meant that changing `DEST_LANG` would not invalidate the existing cache,
potentially resulting in images with incorrect locale.

Include `DEST_LANG` in the `hash_hooks` calculation in `calculate_rootfs_cache_id()`.

Changes
- `lib/functions/rootfs/create-cache.sh`: Add `LANG=${DEST_LANG}` to the hash input

Result
Changing `DEST_LANG` now properly invalidates rootfs cache, ensuring the correct locale
is generated.
2026-01-08 12:24:18 +01:00
Igor Velkov
3e71438048 Fix locale warnings during chroot operations
Build process generated numerous locale warnings like:
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
perl: warning: Setting locale failed

This happened because the Docker container and host environment were
configured to use `en_US.UTF-8`, but the rootfs cache may not contain
this locale (only `C.utf8` and whatever `DEST_LANG` specifies,
e.g. `en_GB.utf8`).

When `chroot_sdcard` runs commands inside the rootfs, environment variables
are inherited from the host/Docker, causing locale lookup failures.

Then use `C.UTF-8` locale for the build environment instead of `en_US.UTF-8`.
This locale is always available in rootfs immediately after mmdebstrap,
requiring no generation.

Changes
`lib/functions/host/docker.sh`: Remove `en_US.UTF-8` locale generation,
set `LANG=C.UTF-8` in container environment
`lib/functions/host/prepare-host.sh`: Change locale exports
from `en_US.UTF-8` to `C.UTF-8`
2026-01-08 12:24:18 +01:00
Ricardo Pardini
0562e3a79f atf: once again no-warn-rwx-segment woes
- turns out everybody was wrong, including me
- some (older?) ATF sources won't work, ever; thus
  - introduce ATF_SKIP_LDFLAGS=yes to skip it completely
  - introduce ATF_SKIP_LDFLAGS_WL=yes to only skip the `-Wl,` prefix
    - this is for ATF's that pass flag directly to linker, not gcc
- artifact-uboot: hash atf-building code into artifact version
2026-01-08 12:20:14 +01:00
tabris
4cc12701e7 framework - update comments around armbian_kernel_config__enable_various_filesystems to use extension_hook_opt_out 2026-01-08 12:07:56 +01:00
tabris
fc9c989904 framework - extension_hook_opt_out 2026-01-08 12:07:56 +01:00
Igor Velkov
74e8171074 Remove -Wno-error=unknown-warning-option from clang KCFLAGS.
This flag was breaking kernel's cc-option detection, causing GCC-specific
warnings (-Wpacked-not-aligned, -Wstringop-truncation, -Wmaybe-uninitialized)
to be incorrectly added to btrfs/drm/coresight builds when using clang.
2026-01-08 12:04:39 +01:00
Paolo Sabatino
288b14defa apply rtl8723cs bluetooth only with kernels >= 6.1 2026-01-08 11:56:44 +01:00
Ricardo Pardini
d61b644ef5 framework & kernel options - simplify armbian_kernel_config_apply_opts_from_arrays, no more ambiguity opts_m vs opts_y (part 2) 2026-01-07 11:14:30 +01:00
tabris
0c21be1f67 framework & kernel options - simplify armbian_kernel_config_apply_opts_from_arrays, no more ambiguity opts_m vs opts_y 2026-01-07 11:14:30 +01:00