Commit graph

399 commits

Author SHA1 Message Date
Reto Schneider
db7a3901bd cmake: modules: dts: Restore gen_defines.py warnings
Ever since 059aae7c91 (cmake: modules:
dts: make Device Tree error messages more visible, PR #76472), warnings
generated by gen_defines.py got only printed when the exit code signaled
an error.

Without this patch, the warning gets swallowed and the build continues:

```
$ west build --pristine --board nrf54l15pdk/nrf54l15/cpuapp \
  samples/userspace/hello_world_user
<snip>
-- Found BOARD.dts:
<snip>/boards/nordic/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.dts
-- Generated zephyr.dts: <snip>/build/zephyr/zephyr.dts
<snip>
```

With this patch, the behavior is back to how it was before
059aae7c91:
```
$ west build --pristine --board nrf54l15pdk/nrf54l15/cpuapp \
  samples/userspace/hello_world_user
<snip>
-- Found BOARD.dts: <snip>/nrf54l15pdk/nrf54l15pdk_nrf54l15_cpuapp.dts
unit address and first address in 'reg' (0x5004c000) don't match for
/soc/peripheral@50000000/vpr@4c000/mailbox@1
-- Generated zephyr.dts: <snip>zephyr/build/zephyr/zephyr.dts
<snip>
```

Signed-off-by: Reto Schneider <reto.schneider@husqvarnagroup.com>
2024-09-13 13:42:40 +02:00
Rubin Gerritsen
1a16ace775 unittest: Enable debug info by default
By enabling debugging information it becomes way much simpler
to find the root cause of a failing unit test as we can simply
run it with a debugger.

Signed-off-by: Rubin Gerritsen <rubin.gerritsen@nordicsemi.no>
2024-09-12 13:02:31 -04:00
Anas Nashif
a87eec570a cmake: Add board emulator extension functions
Adds new CMake extension functions that allow setting board-specific
emulator arguments, similar to existing support for setting
board-specific runner arguments.

Originally authored by: Maureen Helm

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-09-12 14:49:21 +02:00
Pieter De Gendt
d2fb07785d cmake: Create git module
Create a CMake git module for a git_describe function.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2024-09-12 10:04:05 +02:00
Tom Burdick
8c4c180575 cmake: Fix finding python in virtualenv
When running cmake directly (without west, as twister does) on nix the
CMake environment paths are set and thus it does not find the
virtualenv'ed python. Fix this by ignoring the cmake environment
variables nix sets.

Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2024-09-11 14:00:44 -04:00
Anas Nashif
82613fba11 doc: fix trivial typo
fix 'be build' and replace with 'be built'.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-09-05 09:49:18 +02:00
Torsten Rasmussen
d63489195f cmake: support PROPERTY argument on zephyr_link_libraries.
To ease the use of linker flag properties and to simplify the use of
generator expression then an optional PROPERTY argument has been added
to the zephyr_link_libraries() function.

This means a call such as:
zephyr_link_libraries($<TARGET_PROPERTY:linker,<property-name>)
can instead be simplified to:
zephyr_link_libraries(PROPERTY <property-name>)

Thus making intention clearer and keeping the complexity and minimizes
the risk of typos when writing generator expressions.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-09-04 21:26:59 +02:00
Torsten Rasmussen
1728e04b8c cmake: fix check_set_linker_property() function
Fix check_set_linker_property() to correctly handle multiple linker
flags passed on function call.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-09-04 21:26:59 +02:00
Torsten Rasmussen
105a4b5eb2 cmake: initial version of a CMake yaml module
Initial CMake yaml module to facilitate reading yaml files into CMake,
update yaml settings and write it back to a file.

The yaml module also supports creation of yaml files from scratch.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-08-23 08:02:11 -04:00
Torsten Rasmussen
9da2766846 cmake: add check_arguments_... macro to facilitate function writing
Add a new zephyr_check_arguments_required_allow_empty() macro for
function argument validation.

Zephyr already has a zephyr_check_arguments_required() for checking
required arguments, like
zephyr_check_arguments_required(foo_func <prefix> FOO BAR)
which ensures that one of FOO or BAR are given in a call like:
foo_func(BAR val)

One limitation however, is that is some cases BAR may be allowed to be
empty, so that it's still possible to know if FOO or BAR were supplied.
In most case, BAR and FOO will have values following the keyword, like:
foo_func(BAR my_bar_val)
foo_func(FOO my_foo_val)

but in cases where `my_bar_val` is a variable which may be empty, like:
set(my_bar_val)
foo_func(BAR ${my_bar_val}) # (expands to: foo_func(BAR)

then BAR was actually supplied.
To support functions where such empty expansion is allowed, then a new
helper macro `zephyr_check_arguments_required_allow_empty()` has been
implemented, as to be able to distinguish `foo_func()` from
`foo_func(BAR)` when parsing arguments.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-08-23 08:02:11 -04:00
Torsten Rasmussen
cdd3e6fa84 cmake: support list mode in Zephyr-sdk module package
Introduce list mode in Zephyr-sdk module package.

The list mode allows to list all Zephyr SDK's found in the system
without loading any of them.

Signature of the list mode is:
> find_package(Zephyr-sdk COMPONENTS LIST)

Will print valid Zephyr SDKs and their path, as well as defining the
following corresponding CMake lists:
- Zephyr-sdk      : List of Zephyr SDKs' version
- Zephyr-sdk_DIRS : List of Directories with a valid Zephyr SDK.
Each entry in Zephyr-sdk corresponds to the same entry index in the
Zephyr-sdk_DIRS list.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-08-20 14:45:09 +02:00
Torsten Rasmussen
32c33aeca8 cmake: minor cleanups of the FindZephyr-sdk.cmake module
Minor cleanup of the FindZephyr-sdk.cmake module.
- Honor the QUIET flag on find_package(Zephyr-sdk QUIET)
  Do not print messages when caller has specified QUIET in the
  'find_package()' call.
- include Zephyr extensions CMake module.
  FindZephyr-sdk.cmake uses zephyr_get() from extensions.cmake, and
  therefore the proper thing to do is to include said module in order
  to have the package re-usable.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-08-20 14:45:09 +02:00
Mathieu Choplain
059aae7c91 cmake: modules: dts: make Device Tree error messages more visible
This commit modifies the DTS cmake module to capture `stderr`
output of the `gen_defines.py` script and `dtc` program during
their execution. The messages can then be printed as CMake
`message`s, which improves QoL when debugging device tree
errors, and reduces the risk of introducing malformed DTS,
as the warning/error messages are made much more visible.

Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
2024-08-05 16:27:17 +02:00
Mathieu Choplain
662b9803fa llext: disable verbose for SLID generation scripts
This commit removes the "-vvv" argument from the SLID generation
scripts' command line when building Zephyr or an extension with
Kconfig CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID enabled. This removes
a lot of noise in the build log (usually ~250 lines) and is fine to
do because the printed information is also saved in build artifacts.

Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
2024-07-09 17:21:18 +02:00
Jamie McCrae
11c1f3de61 cmake: modules: extensions: Fix dts watch file processing
Fixes and simplifies the handling of how the dts watch file is
processed

Signed-off-by: Grzegorz Swiderski <grzegorz.swiderski@nordicsemi.no>
Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-06-25 06:05:52 -04:00
Jamie McCrae
f4cfb8cd96 cmake: modules: extension: Fix dts file watch
Fixes an issue in the code that processes the output file of a
compiler to see which files should be watched, the compiler can
combine multiple files into a single line instead of putting them
each on separate lines if the length of the file paths is short,
therefore account for this and split it up into multiple elements

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-06-25 06:05:52 -04:00
Jordan Yates
e82e358ed4 cmake: version.cmake: cleanup docs
Cleanup the documentation to fix indentation and remove leading zeros.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2024-06-24 08:28:54 -04:00
Jordan Yates
20348d6b71 cmake: version: enforce single byte limits
Enforce the single byte size limits on the numeric fields in `VERSION`.

Signed-off-by: Jordan Yates <jordan@embeint.com>
2024-06-24 08:28:54 -04:00
Jordan Yates
07870934e3 everywhere: replace double words
Treewide search and replace on a range of double word combinations:
    * `the the`
    * `to to`
    * `if if`
    * `that that`
    * `on on`
    * `is is`
    * `from from`

Signed-off-by: Jordan Yates <jordan@embeint.com>
2024-06-22 05:40:22 -04:00
Pierrick Guillaume
3500a6133d cmake: modules: fix FindThreads use of deprecated PTHREAD config
With the update of the Kconfig symbols to new naming scheme,
CONFIG_PTHREAD does not exist anymore.
Use the new CONFIG_POSIX_THREADS instead

Follow-up: #73047
Signed-off-by: Pierrick Guillaume <pierguill@gmail.com>
2024-06-20 17:03:57 -04:00
Pieter De Gendt
99366dd2be linker: Add ROM_SECTIONS location
Currently iterable sections as per the documentation are added with
zephyr_linker_sources(SECTIONS ...) after bss/noinit.
This commit allows putting sections after common-rom.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2024-06-20 12:08:58 -04:00
Luca Burelli
baa3b6a5ba llext: disable LL_EXTENSION_SYMBOL when not building an llext
The LL_EXTENSION_SYMBOL macro is used to export a symbol to the base
image. When CONFIG_LLEXT is not defined, or the file is being compiled
outside of an llext, the macro is not useful and would leave orphan
sections in the final image instead.

This patch adds the LL_EXTENSION_BUILD definition to the llext build
process, and uses it to stub out the symbol-defining macro when not
building an llext.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 19:24:51 +02:00
Torsten Rasmussen
087dd96a34 cmake: use SOC_ROOT for SoCs instead of BOARD_ROOT
kconfig_soc_root was mistakenly set to value of BOARD_ROOT.
Fix this by correctly set kconfig_soc_root to the value of SOC_ROOT.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-06-13 05:33:38 -04:00
Jamie McCrae
0a590e62e5 cmake: kconfig: Treat Kconfig source paths as UTF-8
These may reside on systems that have unicode characters in the
filenames, treat them as such

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-06-13 05:31:50 -04:00
Jamie McCrae
4fcde701ec sysbuild: Use UTF-8 encoding for cache
Fixes an issue whereby strings are placed in UTF-8 format but the
application doesn't read them in when configured using sysbuild
and another issue whereby sysbuild then reads the application's
cache and did not treat them as UTF-8

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-06-13 05:31:50 -04:00
Torsten Rasmussen
0d51cb08c4 cmake: remove dead 'soc_legacy' folder handling
During HWMv2 migration, non-ported SoCs were placed in a 'soc_legacy'
folder and sourced from there instead of 'soc' folder.

Remove the no-longer needed soc_legacy folder.

CMake oot SoCs in old hardware model are sourced from
'<soc-root>/soc/<arch>/<soc-path>' which has always been the case, also
before HWMv2.

Remove the 'osource "soc/soc_legacy/...' generation in Kconfig, because
the source is relative to Zephyr base.
All SoCs in Zephyr repository has been ported to the new hardware model
and therefore there is no need for this line.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-06-12 17:15:28 -05:00
Eve Redero
65154e644b doc: cmake: fix cmake config documentation
In new hardware model, the arch subfolder is no more: updating cmake config
documentation to reflect this change

Signed-off-by: Eve Redero <eve.redero@gmail.com>
2024-06-10 00:59:50 -07:00
Mathieu Choplain
8aa6ae43ce llext: add support for SLID-based linking
This commit introduces support for an alternate linking method in the
LLEXT subsystem, called "SLID" (short for Symbol Link Identifier),
enabled by the CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID Kconfig option.

SLID-based linking uses a unique identifier (integer) to identify
exported symbols, instead of using the symbol name as done currently.
This approach provides several benefits:
 * linking is faster because the comparison operation to determine
   whether we found the correct symbol in the export table is now an
   integer compare, instead of a string compare
 * binary size is reduced as symbol names can be dropped from the binary
 * confidentiality is improved as a side-effect, as symbol names are no
   longer present in the binary

Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
2024-06-03 15:29:34 -04:00
Torsten Rasmussen
24acc7d43d sysbuild: introduce sysbuild_root for root adjustment
Fixes: #73066

Introduce sysbuild_root CMake module similar to the Zephyr root CMake
module. The sysbuild_root CMake module works similar to existing root
module, but with the difference that root paths are adjusted relative to
APP_DIR which is the main image, instead of relative to sysbuild.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-05-30 11:55:01 +01:00
Torsten Rasmussen
8b3d4c6f0d cmake: update zephyr_file to use cmake_path()
Since the introduction of zephyr_file() then the minimum required CMake
version has become 3.20.
Update zephyr_file() to use cmake_path insteasd of set().
This allows us to normalize the path and thereby also remove duplicates
in the list as paths are normalized.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-05-30 11:55:01 +01:00
Torsten Rasmussen
f7d2cc2d43 cmake: use zephyr_get() and zephyr_file() for APPLICATION_CONFIG_DIR
Fixes: #73065

Update APPLICATION_CONFIG_DIR is Zephyr CMake and sysbuild to follow
the common principle in Zephyr for relative paths.

This means that relative paths are taken from the application source
directory when specified on command line, and require local scoped
defined APPLICATION_CONFIG_DIR to be given as absolute, for example by
using CMAKE_CURRENT_LIST_DIR.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-05-30 08:59:25 +02:00
Yong Cong Sin
0dac6c132b build: namespace autoconf.h with zephyr/
Namespace the generated `autoconf.h` file with `zephyr/`.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
2024-05-28 22:03:55 +02:00
Yong Cong Sin
bbe5e1e6eb build: namespace the generated headers with zephyr/
Namespaced the generated headers with `zephyr` to prevent
potential conflict with other headers.

Introduce a temporary Kconfig `LEGACY_GENERATED_INCLUDE_PATH`
that is enabled by default. This allows the developers to
continue the use of the old include paths for the time being
until it is deprecated and eventually removed. The Kconfig will
generate a build-time warning message, similar to the
`CONFIG_TIMER_RANDOM_GENERATOR`.

Updated the includes path of in-tree sources accordingly.

Most of the changes here are scripted, check the PR for more
info.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
2024-05-28 22:03:55 +02:00
Michał Szprejda
7c084b6649 West: Add west robot command
Introduce `robot` command for running Robot Framework test suites.
Initial implementation consists of one runner dedicated for renode-test,
which is a Renode wrapper for running Robot tests.

Signed-off-by: Michał Szprejda <mszprejda@antmicro.com>
2024-05-28 12:54:52 +02:00
Michał Szprejda
80900cbc3b West: Add west simulate command
Introduce `simulate `command for running samples on a simulator of
choice. Initial implementation consists of one runner, dedicated for
Renode.

Signed-off-by: Michał Szprejda <mszprejda@antmicro.com>
2024-05-28 12:54:52 +02:00
Torsten Rasmussen
207da52e8e cmake: find python path adjustment
Fixes: #70258

Specify NO_CMAKE_PATH to prevent CMake find_program from having a
preference for searching CMAKE_PREFIX_PATH.

Some tool like NixOS / Nix package manager sets this variable
to point inside the nix store, like this:
CMAKE_PREFIX_PATH=/nix/store/gpvnsgf8zhqjjgk63dd...-python3-3.11.6-env

thus causing `find_program()` to prefer this over the tool in the
default path.

Support Nix environments by specifying NO_CMAKE_PATH and in addition
support `VIRTUAL_ENV` environment setting for search path when set by
the virtual environment.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
2024-05-24 18:04:28 -04:00
Pieter De Gendt
4cc7753cad cmake: modules: extensions: Check for missing blobs in zephyr_blobs_verify
Add a separate warning/error message if a blob is missing.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
2024-05-23 07:48:42 -04:00
Ederson de Souza
dc8d7ada19 cmake/modules: Extract flags filtering code to a function
This way they can be reused by the LLEXT EDK.

Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
2024-05-17 16:21:48 +01:00
Grzegorz Swiderski
22fd74914a cmake: modules: dts: Expose DTS_INCLUDE_FILES
This was previously used as a variable internal to the module, but it
can be used in other places in the build system, which may want a list
of DT-specific includes. Therefore, document it as an output variable.

Signed-off-by: Grzegorz Swiderski <grzegorz.swiderski@nordicsemi.no>
2024-05-13 10:36:37 +03:00
Ederson de Souza
2b53c83058 cmake/modules/extensions: Fix string list replacement
Changing from `;` to `|` directly doesn't consider for escaped `;`
inside a list. Fix suggested by @pillo79.

Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
2024-05-12 11:05:20 -04:00
Yong Cong Sin
2e072ad017 ztest: include: unittest: relocate cpu.h and include only if unit-test
The `cpu.h` is meant to be a hack around Zephyr's dependencies
for unit-test, relocate it to a folder that's included only by
unit-test.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
2024-05-10 11:50:36 +02:00
Yong Cong Sin
af78efaa4d subsys/testsuite/ztest: create stub headers at CMake configure time
Create unittest stub headers at CMake configure time.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
2024-05-10 11:50:36 +02:00
Jamie McCrae
a0267d2f48 west: runners: Add run once commands and deferred reset
This adds supports for flashing images with sysbuild where there
are multiple images per board to prevent using the same command per
image flash which might cause issues if they are not ran just once
per flash per unique board name. A deferred reset feature is also
introduced that prevents a board (or multiple) from being reset if
multiple images are to be flashed until the final one has been
flashed which prevents issues with e.g. security bits being enabled
that then prevent flashing further images.

These options can be set at a board level (in board.yml) or a SoC
level (in soc.yml), if both are present then the board configuration
will be used instead of the SoC, and regex can be used for matching
of partial names which allows for matching specific SoCs or CPU cores
regardless of the board being used

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-04-29 17:56:19 +01:00
Nicolas Lebedenco
6837ca808b cmake: Revert breaking change to CMAKE_SYSTEM_NAME
This commit reverts a breaking change in CMAKE_SYSTEM_NAME introduced by
"Zephyr" back to "Generic") and removes the file
`cmake/modules/Platform/Zephyr`.

Both changes in the aforementioned PR were only introduced to ultimately
modify the value of the global CMake property TARGET_SUPPORTS_SHARED_LIBS
for the special case of building for Xtensa with LLEXT.

The modification of CMAKE_SYSTEM_NAME is considered a breaking change
because it has the potential to alter the build of any non-trivial project
that previously checked for the "Generic" system identifier as
corresponding to Zephyr - for example by doing
`if (CMAKE_SYSTEM_NAME STREQUAL "Generic")`. Such builds may now break in
many ways including silently when there is no `else()` clause with a
`message()` to alert the user that a whole configuration block had been
skipped.

In essence, that CMAKE_SYSTEM_NAME modification was only introduced in
order to have CMake to load `cmake/modules/Platform/Zephyr.cmake` which in
turn adjusted the value of TARGET_SUPPORTS_SHARED_LIBS.

But the use of a CMake platform file like this is ineffective for
non-trivial projects where one or more top level CMake `project()` calls
may happen before the first call to `find_package(Zephyr)` because in such
cases CMAKE_MODULE_PATH will not have been modified yet to contain the
path to <Zephyr_ROOT>/cmake/modules and thus no platform file will be
include by CMake.

This patch moves the conditional override of TARGET_SUPPORTS_SHARED_LIBS
needed by some archs (e.g. Xtensa) into the `kernel.cmake` module which
is known to be the first call to `project()` that enables any language and
thus the one that must come before any artifact target can be defined.

Note commit 64e7d85 added a Kconfig to specify the object type of llext
being built, so it's not tied to the arch anymore but to the
CONFIG_LLEXT_TYPE_ELF_SHAREDLIB option.

Signed-off-by: Nicolas Lebedenco <nicolas@lebedenco.net>
2024-04-29 16:17:39 +02:00
Jamie McCrae
6ed5ac7111 cmake: modules: configuration_files: Add support for soc overlays
Adds support for SoC overlay files which go in a ``socs`` folder
in application folders and functions similar to the ``boards``
folder, but works for SoCs instead of boards

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-04-29 15:08:35 +01:00
Jamie McCrae
6f58159a72 cmake: Add support for socs folder and Kconfig fragments
Adds support for a new ``socs`` folder that can be placed in
application folders and functions similar to the ``boards``
folder, but works for SoCs instead of boards

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-04-29 15:08:35 +01:00
Jamie McCrae
43c323a835 cmake: modules: extensions: Fix documentation for zephyr_build_string
Fixes a missed entry and a wrong named variable in the
documentation for this function

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-04-29 15:08:35 +01:00
Patryk Duda
144a08c58c cmake: modules: Introduce FindThreads module
Some third-party modules uses 'find_package(Threads REQUIRED)' to check
if threads implementation is supported.

The original implementation tries to find threads library using various
methods (e.g. checking if pthread library is present or compiling
example program to check if the implementation is provided by libc), but
it's not able to detect pthread implementation provided by Zephyr.

Signed-off-by: Patryk Duda <patrykd@google.com>
2024-04-29 15:59:42 +02:00
Jamie McCrae
23551eb05a cmake: boards: Fix missing board name
Fixes an issue whereby the board name was missing

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
2024-04-24 14:55:18 -04:00
Nicolas Lebedenco
4df926b02d cmake: Make enable_language() clear about what it is actually doing
That call to enable_languages() is passed C CXX ASM which misleads the
reader into thinking that the three languages are enabled in that call but
at that point only ASM is actually because C and CXX were already
implicitly enabled by the call to project() above. The suggested change
removes the misleading C CXX arguments but we could as well make it clear
in the project() call by passing LANGUAGES C CXX.

Signed-off-by: Nicolas Lebedenco <nicolas@lebedenco.net>
2024-04-19 16:40:11 +00:00