unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* A different way to build GCC to overcome issues, especially with C++ for embedded systems
@ 2023-10-02 18:55 Stefan
  2023-12-21 13:32 ` Attila Lendvai
  0 siblings, 1 reply; 13+ messages in thread
From: Stefan @ 2023-10-02 18:55 UTC (permalink / raw)
  To: guix-devel

[-- Attachment #1: Type: text/plain, Size: 4365 bytes --]

Hi!

As some of you probably know, there are issues using GCC to compile C++ 
code, especially for embedded systems.¹²³⁴⁵

Another problem I encountered is that there is only one libstdc++ 
version, which may not match the GCC version one might wish to use.

I stumbled into these problems while trying to compile some embedded C++ 
stuff for an Arm mirco-controller. So I thought to build GCC from 
scratch including libstdc++ and getting the include paths right, and 
then use that to build the needed cross GCC as well.

Finally I got c-toolchain lists for use with package-with-c-toolchain 
and complete GCC toolchains for installation. Each basically consists 
just of (the union of) GCC and Binutils.

I figured out that for GCC 12 only a single patch seems to be necessary: 
gcc-12-strmov-store-file-names.patch.

In the end it worked nicely for my embedded C++ stuff and I also managed 
to compile a custom keyboard firmware based on ZMK using Zephyr, 
although that is just C code.

The newly build GCC contains these default include paths:

$ /gnu/store/…-gcc12-12.2.0/bin/g++ -v -x c++ -E - < /dev/null
…
#include <...> search starts here:
  /gnu/store/…-gcc12-12.2.0/include-c++
  /gnu/store/…-gcc12-12.2.0/include-c++/x86_64-unknown-linux-gnu
  /gnu/store/…-gcc12-12.2.0/include-c++/backward
 
/gnu/store/…-gcc12-12.2.0-lib/lib/gcc/x86_64-unknown-linux-gnu/12.2.0/include
  /gnu/store/…-gcc12-12.2.0-lib/include
 
/gnu/store/…-gcc12-12.2.0-lib/lib/gcc/x86_64-unknown-linux-gnu/12.2.0/include-fixed
  /gnu/store/…-glibc-2.33/include
  /gnu/store/…-linux-libre-headers-5.10.35/include
End of search list.
…

This is very similar to the paths found in FHS systems. The path 
/gnu/store/…-gcc12-12.2.0-lib/include is empty and replaces 
/usr/local/include. It is impossible to omit a path at this place.

Similarly the newly build cross GCC with newlib contains these default 
include paths:

$ 
/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-toolchain-12.2.0/bin/arm-none-eabi-g++ 
-v -x c++ -E - < /dev/null
…
#include <...> search starts here:
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/include-c++
 
/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/include-c++/arm-none-eabi
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/include-c++/backward
 
/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/include
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/include
 
/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/include-fixed
  /gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/include
End of search list.
…

You may note the missing include path to kernel headers, which do not 
exist for bare-metal builds using newlib. So this is by intention.

None of these paths will show up in C_INCLUDE_PATH or CPLUS_INCLUDE_PATH 
when installing a toolchain, which I think was basically the root of all 
the pain.

Of course this makes use of the already existing gnu-build-system and 
the gcc-toolchain. To get this going gcc-phase-fix-environment is used 
to overcome some troubles with the existing gcc-toolchain.

In the end I think it could make sense to change the way how the tower 
of GCC versions is build. I also think that glibc should reference the 
libgcc_s.so from some gcc-stage1:lib output, which has to be build 
without any libc. Then the modification of the specs to pre-load that 
library via -lgcc_s may become obsolete.

Except for other compilers like clang, this makes a libstdc++ package 
obsolete. I did not care about using clang with lbstdc++ yet, but I 
might do so in the future. I also did not try to use the same functions 
on older GCC versions nor GCC 13, which was not existing in Guix when I 
started this endeavor.

I hope this message triggers some interest and helps solving some 
existing troubles.


Bye

Stefan


P.S. If someone likes to play with the attached files, please note the 
needed file structure:
…/embedded.scm
…/zephyr.scm
…/zephyr/modules.scm
…/zephyr/apps.scm
…/zephyr/zmk.scm


¹ https://lists.gnu.org/archive/html/help-guix/2023-09/msg00025.html
² https://lists.gnu.org/archive/html/guix-devel/2020-06/msg00096.html
³ https://issues.guix.gnu.org/37801https://issues.guix.gnu.org/43579https://issues.guix.gnu.org/49935

[-- Attachment #2: embedded.scm --]
[-- Type: text/x-scheme, Size: 29323 bytes --]

;;; GNU Guix --- Functional package management for GNU
;;;
;;; Copyright © 2023 Stefan <stefan-guix@vodafonemail.de>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (embedded)
  #:use-module (guix build-system)
  #:use-module (guix build-system gnu)
  #:use-module (guix build-system trivial)
  #:use-module (guix build gnu-build-system)
  #:use-module ((guix build utils) #:select (alist-replace
                                             modify-phases))
  #:use-module (guix download)
  #:use-module (guix gexp)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (guix utils)
  #:use-module (gnu packages)
  #:use-module (gnu packages autotools)
  #:use-module (gnu packages base)
  #:use-module ((gnu packages bootstrap) #:select (glibc-dynamic-linker))
  #:use-module (gnu packages commencement)
  #:use-module (gnu packages compression)
  #:use-module (gnu packages cross-base)
  #:use-module (gnu packages flex)
  #:use-module (gnu packages gcc)
  #:use-module (gnu packages gdb)
  #:use-module (gnu packages multiprecision)
  #:use-module (gnu packages pkg-config)
  #:use-module (gnu packages texinfo)
  #:use-module (ice-9 optargs)
  #:use-module (srfi srfi-1))

(define-public (gcc-phase-fix-environment)
  "Give a build-phase for the GCC compilation to fix environment variables."
  #~(lambda* (#:key inputs #:allow-other-keys)
      (use-modules (srfi srfi-1))
      (setenv
       "LD_LIBRARY_PATH"
       ;; The built gcc will have a workaround to ensure that glibc will always
       ;; find libgcc_s.so.  Unfortunately during the configuration of libatomic
       ;; and other libraries, the libgcc_s.so is not yet available in its final
       ;; installation directory and this workaround causes trouble to the
       ;; configure script during "checking whether we are cross compiling".  As
       ;; a mitigation we set LD_LIBRARY_PATH to the location of the not yet
       ;; installed libgcc_s.so. This would not be necessary, if glibc had a
       ;; reference to the gcc used to build it.
       (string-append (getcwd) "/build/gcc"))
      (format #t "environment variable `LD_LIBRARY_PATH' set to `~a'~%"
              (getenv "LD_LIBRARY_PATH"))
      (when (getenv "CPLUS_INCLUDE_PATH")
        (let* ((libc (assoc-ref inputs "libc"))
               (gcc (assoc-ref inputs "gcc")) ; This is different to #$gcc!
               (paths-to-delete
                (map (lambda (package) (string-append package "/include"))
                     (filter-map identity (list libc gcc)))))
          (setenv
           "CPLUS_INCLUDE_PATH"
           ;; The gcc package used by the gnu-build-system to build this gcc
           ;; puts the include paths to the C++ headers and to the libc headers
           ;; into CPLUS_INCLUDE_PATH.  This causes trouble in the gcc build
           ;; process when -nostdinc++ is used.  As a mitigation we remove them.
           ;; This would not be necessary, when using this built gcc instead.
           (string-join
            (remove (lambda (path) (member path paths-to-delete))
                    (string-split (getenv "CPLUS_INCLUDE_PATH") #\:))
            ":"))
          (format #t "environment variable `CPLUS_INCLUDE_PATH' set to `~a'~%"
                     (getenv "CPLUS_INCLUDE_PATH"))))))

(define*-public (gcc-phase-pre-configure
                 #:key
                 (libc glibc)
                 (dynamic-linker (glibc-dynamic-linker))
                 (startfile-dir "/lib/"))
  "Give a build-phase for the GCC compilation to modify the source-code.  Use
the LIBC package for embedded search-paths.  The path DYNAMIC-LINKER is appended
to LIBC to form the absolute path to the dynamic-linker.  The STRTFILE-DIR is a
suffix for LIBC to form the path to startfiles like crt0.o from newlib.  All
default values match for glibc.  For newlib omit DYNAMIC-LINKER and set
STARTFILE-DIR to (string-append \"/\" target \"/lib/\")."
  #~(lambda _
      (substitute* "Makefile.in"
        ;; Don't store configure arguments, to avoid retaining references to
        ;; build-time dependencies like "--with-…=/gnu/store/…".
        (("@TOPLEVEL_CONFIGURE_ARGUMENTS@") ""))
      (substitute* (find-files "gcc/config")
        ;; Enforce any /lib64 directory to just be /lib.
        (("/lib64") "/lib"))
      (when #$dynamic-linker
        (substitute* (find-files "gcc/config" "^.+\\.h$" #:directories? #t)
          ;; Enforce anything looking like some /lib/ld.so.2 to be the linker.
          (("[^ :;\"{]+/ld.*[_.]so(\\.[0-9]+)?")
           (string-append #$libc #$dynamic-linker))))
      (substitute* "gcc/configure"
        ;; Prevent auto-host.h in output:lib to create a cyclic dependency
        ;; referencing output:out.
        (("PREFIX_INCLUDE_DIR \"\\$prefix/include\"")
         "PREFIX_INCLUDE_DIR \"$libdir/include\""))
      (substitute* "gcc/genmultilib"
        ;; Enforce proper invokations of sh.
        (("#!/bin/sh") (string-append "#!" (which "sh"))))
      (substitute* "gcc/gcc.cc"
        ;; The STARTFILE_PREFIX_SPEC defines where to find crt1.o and other
        ;; start files of libc.  Replace it with a proper path to the libc.
        ;; Note: This path is relative to the sysroot which therefore must be /.
        (("startfile_prefix_spec = STARTFILE_PREFIX_SPEC;")
         (string-append "startfile_prefix_spec = \""
                        #$libc #$startfile-dir "\";")))
      (substitute* "libstdc++-v3/python/Makefile.in"
        ;; Change pythondir from #$output:out to #$output:lib to prevent
        ;; #$output:lib/lib/libstdc++.so.*-gdb.py to create a cyclic dependency
        ;; to #$output:out/share/…/python.  This moves all python files to
        ;; #$output:lib.  The option --with-python-dir is still usable.
        (("pythondir = \\$\\(datadir\\)") "pythondir = $(libdir)/share")
        (("pythondir = \\$\\(prefix\\)")  "pythondir = $(libdir)"))
      #!(substitute* "libsanitizer/asan/asan_linux.cpp"
        ;; Ensure PATH_MAX is defined by including the proper header file.
        ;; https://gcc.gnu.org/bugzilla//show_bug.cgi?id=99476
        ;; https://gcc.gnu.org/bugzilla//show_bug.cgi?id=106998
        ;; The gcc package used by the gnu-build-system is to blame here.  This
        ;; patch is unnecessary when not using --disable-bootstrap.
        (("#include <limits\\.h>")
         #$(string-join (list "#include <limits.h>"
                              "#if SANITIZER_LINUX"
                              "#include <linux/limits.h>"
                              "#endif")
                        "\n")))!#))

(define*-public (gcc-configure-flags
                 #:key
                 (libc glibc)
                 (kernel-headers
                  (car (assoc-ref (package-propagated-inputs glibc)
                                  "kernel-headers"))))
  "Give the configure-flags for the GCC compilation referring to the LIBC and
KERNEL-HEADERS packages.  The defaults refer to glibc and the kernel-headers
used to build glibc."
  #~(list
      ;; The first set of include paths consinsts of #$gcc/include-c++/… and
      ;; #$gcc:lib/…/include.  Second is usually /usr/local, which we replace
      ;; with the empty #$output:lib/include path.
      (string-append "--with-local-prefix=" #$output:lib)
      ;; Third is #$gcc:lib/…/include-fixed, which expects #$libc/include and
      ;; #$kernel-headers/include to follow in this order.
      ;; Fourth and usually the last include path is /usr/include containing all
      ;; system headers.  It is only possible to specify one path for this.  Set
      ;; the #$libc/include path and prevent the use of /usr/include.
      (string-append "--with-native-system-header-dir=" #$libc "/include")
      ;; The final include path has to be #$kernel-headers/include, which has to
      ;; be after #$libc/include.  There is only -idirafter left to achieve
      ;; this.  Add #$output:lib/lib as a built-in link-time search path.
      ;; Add #$libc/lib and #$libc/static as built-in link-time search paths.
      ;; Add a runtime search path to #$libc/lib, if not linked statically.
      ;; This search path to #$libc/lib may not be technically necessary because
      ;; of the dynamic linker in there, but better use a complete list.
      ;; Actually libc needs a DT_RUNPATH entry to the libgcc_s.so of the GCC
      ;; used to build it.  This is missing and may requires a fix.  As a
      ;; workaround one can force any program built by this GCC and not linked
      ;; statically to load libgcc_s.so by embedding the -lgcc_s option and
      ;; adding a runtime search path to libgcc_s.so as well.
      (string-append
       "--with-specs="
       ;; Embed the path to the kernel-headers.
       "-idirafter " #$kernel-headers "/include "
       ;; Embed the link-time search path to libgcc_s.so, libstdc++.so, etc.
       "%x{-L" #$output:lib "/lib} "
       ;; Embed the link-time search paths to #$libc/lib and #$libc:static/lib.
       "%x{-L" #$libc "/lib} %x{-L" #$libc:static "/lib} "
       ;; Embed the runtime search path to #$libc/lib, if not staticlally
       ;; linked.
       "%{nolibc|nostdlib|static:; :%x{-rpath=" #$libc "/lib}} "
       ;; This is a workaround to ensure a pre-loaded libgcc_s.so for libc if
       ;; not statically linking.  The libstdc++.so and other shared libraries
       ;; are statically linked but use the option -lgcc_s.  Unfortunately it
       ;; seems to be impossible to check for the presence of -lgcc_s.  Adding
       ;; the -rpath option conditionally, if not linking statically, has the
       ;; risk to not add it although needed.  Adding it unconditionally may add
       ;; it needlessly, which prevents building the dynamic linker of libc,
       ;; but makes the make-flags #~(list "LDFLAGS=-Wl,-rpath=$(libdir)/lib")
       ;; obsolete.  As a GCC referencing the dynamic linker cannot be used to
       ;; build it, the -rpath is added unconditionally here.
       "%{nodefaultlibs|nostdlib|static|static-libgcc|static-pie:; "
       ":%x{-lgcc_s}} %x{-rpath=" #$output:lib "/lib}")
      ;; Prevent the C++ headers in #$output:lib, put them in #$output:out
      ;; instead.  Use an unconventional path to prevent it from being added to
      ;; the environment variables C_INCLUDE_PATH and CPLUS_INCLUDE_PATH.
      "--with-gxx-include-dir=$(prefix)/include-c++"
      ;; As libc is limited, gcc will not be usable for 32 and 64 bit builds.
      "--disable-multilib"
      ;; Disable all language frontends except for C and C++.
      "--enable-languages=c,c++"
      ;; Save space by disabling pre-compiled libstdc++ headers.
      "--disable-libstdcxx-pch"
      ;; Use the zlib package instead of the zlib bundled with gcc.
      "--with-system-zlib"
      ;; Avoid parallel linking to not crash on systems with limited memory.
      "--enable-link-serialization"
      ;; Prevent the built gcc to build itself again to save time.
      #!"--disable-bootstrap"!#))

(define-public (make-gcc12 phase-pre-configure configure-flags)
  "Make a GCC package using the PHASE-PRE-CONFIGURE and the CONFIGURE-FLAGS in
the build-process."
  (package
    (name "gcc12")
    (version "12.2.0")
    (source (origin
              (method url-fetch)
              (uri (string-append "mirror://gnu/gcc/gcc-"
                                  version "/gcc-" version ".tar.xz"))
              (sha256
               (base32 "1zrhca90c7hqnjz3jgr1vl675q3h5lrd92b5ggi00jjryffcyjg5"))
              (patches
               (search-patches "gcc-12-strmov-store-file-names.patch"))))
    (build-system gnu-build-system)
    (outputs '("out" "lib" "debug"))
    (inputs (list gmp mpfr mpc isl zstd zlib))
    (arguments
      (list #:tests? #f
            #:out-of-source? #t
            #:configure-flags configure-flags
            #:phases
            #~(modify-phases %standard-phases
                (add-after 'set-paths 'fix-environment
                  #$(gcc-phase-fix-environment))
                (add-before 'configure 'pre-configure
                  #$phase-pre-configure))))
    (native-search-paths
     (list (search-path-specification (variable "CPLUS_INCLUDE_PATH")
                                      (files (list "include")))
           (search-path-specification (variable "C_INCLUDE_PATH")
                                      (files (list "include")))
           (search-path-specification (variable "LIBRARY_PATH")
                                      (files (list "lib")))))
    (synopsis "GNU Compiler Collection")
    (description
      "GCC is the GNU Compiler Collection.  It provides compiler front-ends for
several languages, including C, C++, Objective-C, Fortran, Java, Ada, and
Go.  It also includes runtime support libraries for these languages.")
    (home-page "https://gcc.gnu.org/")
    (license license:gpl3+)))

(define-public gcc12
  (make-gcc12 (gcc-phase-pre-configure) (gcc-configure-flags)))

(define-public guix-locpath
  (package
    (name "guix-locpath")
    (version "1.0")
    (source #f)
    (build-system trivial-build-system)
    (arguments (list #:builder #~(mkdir #$output)))
    (native-search-paths
     (list (search-path-specification (variable "GUIX_LOCPATH")
                                      (files '("lib/locale")))))
    (home-page #f)
    (synopsis "Access for glibc to locales")
    (description "The guix-locpath package sets the environment variable
GUIX_LOCPATH to make all locale related functions of glibc usable without
propagating glibc itself.  This is usefull to prevent glibc include paths to be
exposed via C_INCLUDE_PATH and similar environment variables, to keep a defined
include order with embedded paths in GCC to glibc.")
    (license (package-license glibc-utf8-locales))))

(define*-public (make-c-toolchain gcc binutils #:optional ld-wrapper)
  "Make a C-toolchain consisting of GCC, BINUTILS, guix-locpath and
optionally LD-WRAPPER packages.  The result can be used by the transformation
function 'package-with-c-toolchain' and to build a GCC-toolchain package with
'make-gcc-toolchain-package'.

The guix-locpath package is used instead of the glibc package to prevent glibc
and the kernel-headers from appearing in the C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
and similar environment variables.  The GCC package is expected to have the
necessary paths build-in to preserve a necessary include-order."
  (let ((build-inputs (list (list "guix-locpath" guix-locpath)
                            (list "gcc" gcc)
                            (list "binutils" binutils))))
    (if ld-wrapper
        ;; The ld-wrapper has to be in front of binutils.
        (cons (list "ld-wrapper" ld-wrapper) build-inputs)
        build-inputs)))

(define*-public (make-gcc-toolchain-package c-toolchain)
  "Make a GCC-toolchain package from C-TOOLCHAIN.  The C-TOOLCHAIN argument must
be a list of inputs (label/package tuples) providing equivalent functionality as
the 'gcc-toolchain' package as passed to 'package-with-c-toolchain'."
  (let ((gcc (car (assoc-ref c-toolchain "gcc"))))
    (package
      (name (string-append (package-name gcc) "-toolchain"))
      (version (package-version gcc))
      (source #f)
      (build-system trivial-build-system)
      (arguments
        (list
         #:modules '((guix build union))
         #:builder
         #~(begin
             (use-modules ((guix build union)))
             (union-build #$output (quote #$(map second c-toolchain))))))
      (synopsis "Complete GCC toolchain for C/C++ development")
      (description "This package provides a complete GCC toolchain for C/C++
development to be installed in user profiles.  This includes GCC and Binutils.
GCC is the GNU Compiler Collection.")
      (home-page "https://gcc.gnu.org/")
      (license license:gpl3+))))

(define-public gcc12-c-toolchain
  (make-c-toolchain gcc12 binutils ld-wrapper))

(define-public gcc12-toolchain
  (make-gcc-toolchain-package gcc12-c-toolchain))

(define*-public (make-newlib-4.3 target
                                 #:key
                                 (configure-flags
                                  '("--disable-newlib-supplied-syscalls"
                                    "--enable-newlib-io-long-long"
                                    "--enable-newlib-io-c99-formats"
                                    "--enable-newlib-mb"
                                    "--enable-newlib-reent-check-verify"
                                    "--enable-newlib-register-fini"
                                    "--enable-newlib-retargetable-locking"
                                    "--disable-dependency-tracking"))
                                 (cross-gcc (cross-gcc target))
                                 (cross-binutils (cross-binutils target)))
  "Make a newlib package for TARGET with the given CONFIGURE-FLAGS, CROSS-GCC
and CROSS-BINUTLIS packages for building."
  (package
    (name (string-append "newlib-" target))
    (version "4.3.0")
    (source
      (origin
        (method url-fetch)
        (uri "ftp://sourceware.org/pub/newlib/newlib-4.3.0.20230120.tar.gz")
        (sha256
          (base32 "0l2iycz12m9r8czc08isykzh1mr4xs9d13n5n2wqxqsrmycjm9l3"))))
    (build-system gnu-build-system)
    (arguments
     (list #:out-of-source? #t
           ;; The configure-flags are taken from newlib_configure found in:
           ;; https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/12.2.mpacbti-bet1/manifest/arm-gnu-toolchain-arm-none-eabi-abe-manifest.txt
           ;; Got that link in section "Linaro ABE example manifest files for
           ;; Linux hosted cross toolchains" form:
           ;; https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
           #:configure-flags
           #~(quote #$(cons (string-append "--target=" target)
                            configure-flags))
           #:phases
           #~(modify-phases %standard-phases
               ;; TODO: Remove nano related files after installation.
               (add-after 'unpack 'fix-references-to-/bin/sh
                 (lambda _
                   (substitute* (find-files "libgloss" "^Makefile\\.in$")
                     ;; There are plenty Makefile.in below libgloss which
                     ;; reference /bin/sh. These must be fixed.
                     (("/bin/sh") (which "sh"))))))))
    (native-inputs (list cross-gcc cross-binutils texinfo))
    (home-page "https://www.sourceware.org/newlib/")
    (synopsis "C library for use on embedded systems")
    (description "Newlib is a C library intended for use on embedded
systems.  It is a conglomeration of several library parts that are easily
usable on embedded products.")
    (license (license:non-copyleft
              "https://www.sourceware.org/newlib/COPYING.NEWLIB"))))

(define*-public (make-newlib-nano-4.3 target
                                      #:key
                                      (cross-gcc (cross-gcc target))
                                      (cross-binutils (cross-binutils target)))
  "Make a newlib-nano package for TARGET with the given CROSS-GCC and
CROSS-BINUTLIS packages for building."
  (package
    (inherit (make-newlib-4.3 target
              #:configure-flags
              '("--disable-newlib-fseek-optimization"
                "--disable-newlib-fvwrite-in-streamio"
                "--disable-newlib-supplied-syscalls"
                "--disable-newlib-unbuf-stream-opt"
                "--disable-newlib-wide-orient"
                "--enable-lite-exit"
                "--enable-newlib-global-atexit"
                "--enable-newlib-nano-formatted-io"
                "--enable-newlib-nano-malloc"
                "--enable-newlib-reent-check-verify"
                "--enable-newlib-reent-small"
                "--enable-newlib-retargetable-locking"
                "--disable-dependency-tracking")
                #:cross-gcc cross-gcc
                #:cross-binutils cross-binutils))
    (name (string-append "newlib-nano-" target))
    ;; TODO: Add nano suffix to installed files, keep nano related files.
    (synopsis "C library for use on embedded systems with limited memory")))

(define-public newlib-arm-none-eabi-4.3
  (make-newlib-4.3 "arm-none-eabi"))

(define-public newlib-nano-arm-none-eabi-4.3
  (make-newlib-nano-4.3 "arm-none-eabi"))

(define-public (gcc-cross-newlib-arm-configure-flags target libc)
  "Modify configure-flags to build a GCC cross-compiler for the Arm target
TARGET using newlib as LIBC."
  #~(list
      (string-append "--target=" #$target)
      ;; All paths to --with-… options are relative to the sysroot.  As store
      ;; pathes are absolute, the sysroot needs to be set to /.
      "--with-sysroot=/"
      ;; The first set of include paths consinsts of #$gcc/include-c++/… and
      ;; #$gcc:lib/…/include.  Second is usually /usr/local, which we replace
      ;; with the empty #$output:lib/include path.
      (string-append "--with-local-prefix=" #$output:lib)
      ;; Third is #$gcc:lib/…/include-fixed, which expects #$libc/include and
      ;; #$kernel-headers/include to follow in this order.
      ;; Fourth and usually the last include path is /usr/include containing all
      ;; system headers.  It is only possible to specify one path for this.  Set
      ;; the #$libc/include path and prevent the use of /usr/include.
      ;; Using newlib as libc for bare-metal does not require kernel-headers.
      (string-append
       "--with-native-system-header-dir=" #$libc "/" #$target "/include")
      ;; Add #$output/#$target/lib and #$libc/#$target/lib as a built-in
      ;; link-time search path.
      (string-append
       "--with-specs="
       ;; Embed the link-time search path to libgcc, libstdc++, etc.
       "%x{-L" #$output "/" #$target "/lib} "
       ;; Embed the link-time search paths to libc.
       "%x{-L" #$libc "/" #$target "/lib}")
      ;; Prevent the C++ headers in #$output:lib, put them in #$output:out
      ;; instead.  Use an unconventional path to prevent it from being added to
      ;; the environment variables C_INCLUDE_PATH and CPLUS_INCLUDE_PATH.
      "--with-gxx-include-dir=$(prefix)/include-c++"
      ;; Ensure GCC is build for newlib.
      "--with-newlib"
      ;; As newlib has multiple target libraries, enable their support.
      "--enable-multilib"
      "--with-multilib-list=aprofile,rmprofile"
      ;; As newlib does not have a dynamik-linker, disable shared builds.
      "--disable-shared"
      ;; Disable all language frontends except for C and C++.
      "--enable-languages=c,c++"
      ;; Save space by disabling pre-compiled libstdc++ headers.
      "--disable-libstdcxx-pch"
      ;; Use the zlib package instead of the zlib bundled with gcc.
      "--with-system-zlib"
      ;; Avoid parallel linking to not crash on systems with limited memory.
      "--enable-link-serialization"))

(define*-public (make-cross-gcc gcc cross-libc cross-binutils)
  "Make a GCC cross-compiler package based on a still native but modified GCC
package using the CROSS-LIBC and CROSS-BINUTILS packages."
  (package
    (inherit gcc)
    (name (string-append (package-name gcc)
                         "-cross-"
                         (package-name cross-libc)))
    (inputs '())
    (native-inputs (append (list (list "cross-binutils" cross-binutils))
                           (package-inputs gcc)))))

(define*-public (make-cross-c-toolchain target cross-gcc cross-binutils
                                        #:optional cross-ld-wrapper)
  "Make a cross-C-toolchain targeting TARGET of the CROSS-GCC, CROSS-BINUTILS,
guix-locpath and optionally CROSS-LD-WRAPPER packages.  The result can be used
by the transformation function 'package-with-c-toolchain' and to build a
GCC-toolchain package with 'make-gcc-toolchain-package'.

The guix-locpath package is used instead of the glibc package to prevent glibc
and the kernel-headers from appearing in the C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
and similar environment variables.  The GCC package is expected to have the
necessary paths build-in to preserve a necessary include-order."
  (append (make-c-toolchain cross-gcc cross-binutils cross-ld-wrapper)
          ;; GCC looks for as and other tools from cross-binutils in PATH.
          ;; However, the cross-binutils package contains only executables
          ;; pefixed with the target name in its bin directory.  The ones
          ;; not prefixed reside in its target/bin directory.  We create a
          ;; new package, which links that #$target/bin directory as bin.
          ;; Note: The linker is invoked by collect2, which has different lookup
          ;; rules as GCC and finds a prefixed target-ld.
          (list
           (list "binutils-for-toolchain"
                 (package
                   (inherit cross-binutils)
                   (name (string-append (package-name cross-binutils)
                                        "-for-toolchain"))
                   (version (package-version cross-binutils))
                   (source #f)
                   (build-system trivial-build-system)
                   (arguments
                     (list
                      #:builder
                      #~(begin
                          (mkdir #$output)
                          (symlink
                           #$(file-append cross-binutils "/" target "/bin")
                           (string-append #$output "/bin"))))))))))

(define*-public (make-cross-arm-none-eabi-c-toolchain
                 gcc
                 make-gcc
                 make-cross-newlib)
  "Make a C-toolchain targeting arm-none-eabi consisting of a cross-compiler,
cross-compiled Binutils, and a newlib C-library.  The cross-compiler will be
build with another toolchain using the given host GCC and Binutils.  The
function MAKE-GCC is used to create a GCC cross-compiler package using the
newlib C-library package created with MAKE-CROSS-NEWLIB.  The result can be used
by the transformation function 'package-with-c-toolchain' and to build a
GCC-toolchain package with 'make-gcc-toolchain-package'."
  (let* ((target "arm-none-eabi")
         (c-toolchain (make-c-toolchain gcc binutils ld-wrapper))
         (cross-binutils (cross-binutils target))
         (cross-newlib (make-cross-newlib target))
         (cross-gcc
          (package-with-c-toolchain
           (make-cross-gcc
            (make-gcc (gcc-phase-pre-configure
                       #:libc cross-newlib
                       #:startfile-dir (string-append "/" target "/lib/"))
                      (gcc-cross-newlib-arm-configure-flags target
                                                            cross-newlib))
            cross-newlib
            cross-binutils)
           c-toolchain)))
    (make-cross-c-toolchain target cross-gcc cross-binutils)))

(define-public gcc12-cross-newlib-arm-none-eabi-c-toolchain
  (make-cross-arm-none-eabi-c-toolchain gcc12 make-gcc12 make-newlib-4.3))

(define-public gcc12-cross-newlib-nano-arm-none-eabi-c-toolchain
  (make-cross-arm-none-eabi-c-toolchain gcc12 make-gcc12 make-newlib-nano-4.3))

(define-public gcc12-cross-newlib-arm-none-eabi-toolchain
  (package
    (inherit (make-gcc-toolchain-package
              gcc12-cross-newlib-arm-none-eabi-c-toolchain))
    (synopsis
     "Complete GCC toolchain for C/C++ cross development on ARM Cortex-A and
Cortex-M micro-controllers with newlib")
    (description "This package provides a complete GCC toolchain for C/C++ cross
development on ARM Cortex-A and Cortex-M micro-controllers to be installed in
user profiles.  This includes GCC, newlib and Binutils.  GCC is the GNU
Compiler Collection.")))

(define-public gcc12-cross-newlib-nano-arm-none-eabi-toolchain
  (package
    (inherit (make-gcc-toolchain-package
              gcc12-cross-newlib-nano-arm-none-eabi-c-toolchain))
    (synopsis
     "Complete GCC toolchain for C/C++ cross development on ARM Cortex-A and
Cortex-M micro-controllers with newlib-nano")
    (description "This package provides a complete GCC toolchain for C/C++ cross
development on ARM Cortex-A and Cortex-M micro-controllers to be installed in
user profiles.  This includes GCC, newlib-nano and Binutils.  GCC is the GNU
Compiler Collection.")))

(define-public gcc12-cross-newlib-arm-none-eabi
  (car (assoc-ref gcc12-cross-newlib-arm-none-eabi-c-toolchain "gcc")))

(define-public gcc12-cross-newlib-nano-arm-none-eabi
  (car (assoc-ref gcc12-cross-newlib-nano-arm-none-eabi-c-toolchain "gcc")))

(define-public binutils-cross-arm-none-eabi
  (car (assoc-ref gcc12-cross-newlib-nano-arm-none-eabi-c-toolchain "binutils")))


[-- Attachment #3: zephyr.scm --]
[-- Type: text/x-scheme, Size: 5442 bytes --]

;;; GNU Guix --- Functional package management for GNU
;;;
;;; Copyright © 2023 Stefan <stefan-guix@vodafonemail.de>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (zephyr)
  #:use-module (embedded)
  #:use-module (gnu packages bootloaders)
  #:use-module (gnu packages python)
  #:use-module (gnu packages python-xyz)
  #:use-module (guix build-system copy)
  #:use-module (guix build-system trivial)
  #:use-module (guix gexp)
  #:use-module (guix git-download)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages))

;; This is the common directory name for zephyr-modules to look for search-paths
;; to collect in the ZEPHYR_MODULES environment variable.  The build-system of
;; Zephyr searches for a file zephyr/module.yml in all paths listed in the
;; environment variable ZEPHYR_MODULES.  If that file is missing a name
;; property, then the parent directory name is used as the module name. Having
;; two modules with the same name is treated as an error.  As Guix needs a
;; common directory name for search-path-specification, we need this
;; intermediate directory as a pattern to find unique module names.
;; Unfortunately search-path-specification is not powerful enough, so
;; complete-zephyr-application needs the correct-ZEPHYR_MODULES build-phase.
(define-public %zephyr-module "zephyr-module")

(define-public zephyr
  (let ((version "3.4.0"))
    (package
      (name "zephyr")
      (version version)
      (source
        (origin
          (method git-fetch)
          (uri (git-reference
                (url "https://github.com/zephyrproject-rtos/zephyr")
                (commit (string-append "zephyr-v" version))))
          (file-name (git-file-name name version))
          (sha256 (base32
                   "1gcry9fxv88js5nymi9akgrkghkwavggj3wqdgg2cz6brr5wg284"))))
      (build-system copy-build-system)
      (arguments
        (list
         #:install-plan
         #~(list (list "." "zephyr-base"))
         #:phases
         #~(modify-phases %standard-phases
             (add-after 'unpack 'set-USER_CACHE_DIR-and-BUILD_VERSION
               (lambda _
                ;; Avoid fetching the BUILD_VERSION from the git repository.
                (substitute* "CMakeLists.txt"
	  	          (("if *\\(DEFINED BUILD_VERSION\\)")
                   (string-append
                    "if (NOT DEFINED BUILD_VERSION)\n"
                    "  set(BUILD_VERSION " #$version ")\n"
                    "elseif (DEFINED BUILD_VERSION)")))
                ;; Avoid USER_CACHE_DIR to point to XDG_CACHE_HOME, HOME, or to
                ;; ZEPHYR_BASE inside the store. Instead use the build dir.
                (with-output-to-file
                 "cmake/modules/user_cache.cmake"
                 (lambda ()
                   (display
                    "set(USER_CACHE_DIR ${CMAKE_BINARY_DIR}/cache)\n"))))))))
      (native-search-paths
       (list (search-path-specification
              (variable "ZEPHYR_BASE")
              (files '("zephyr-base"))
              (separator #f))
             (search-path-specification
              (variable "ZEPHYR_MODULES")
              (files (list %zephyr-module)))))
      (home-page "https://zephyrproject.org")
      (synopsis "Zephyr Project RTOS")
      (description "The Zephyr Project is a scalable real-time operating system
(RTOS) supporting multiple hardware architectures, optimized for resource
constrained devices, and built with security in mind.")
      (license license:apsl2))))

(define-public zephyr-3.2+zmk-fixes
  (let ((revision "1")
        (commit "0a586db7b58269fb08248b081bdc3b43452da5f4"))
    (package/inherit zephyr
      (name "zephyr+zmk-fixes")
      (version (git-version "3.2.0" revision commit))
      (source
        (origin
          (method git-fetch)
          (uri (git-reference
                (url "https://github.com/zmkfirmware/zephyr")
                (commit commit)))
          (file-name (git-file-name name version))
          (sha256 (base32
                   "04mqgzhgjb43ybryvpwrbq2g9i0gk7wd7s2ds3fsrakl4hxqss78"))))
      (home-page "https://github.com/zmkfirmware/zephyr"))))

(define-public zephyr-build-tools
  (package
    (name "zephyr-build-tools")
    (version "1.0.0")
    (source #f)
    (build-system trivial-build-system)
    (arguments (list #:builder #~(mkdir #$output)))
    (propagated-inputs (list dtc
                             python
                             python-pyelftools
                             python-pykwalify
                             python-pyyaml
                             python-packaging))
    (home-page "https://zephyrproject.org")
    (synopsis "Zephyr build tools")
    (description "Required build tools to build the Zephyr RTOS.")
    (license license:apsl2)))


[-- Attachment #4: modules.scm --]
[-- Type: text/x-scheme, Size: 11166 bytes --]

;;; GNU Guix --- Functional package management for GNU
;;;
;;; Copyright © 2023 Stefan <stefan-guix@vodafonemail.de>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (zephyr modules)
  #:use-module (guix gexp)
  #:use-module (guix build-system copy)
  #:use-module (guix git-download)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (ice-9 regex)
  #:use-module (zephyr))

(define-public (zephyr-module-installation-target zephyr-module)
  "Return the target directory for the install-plan of the copy-build-system for
the ZEPHYR-MODULE package.  It needs to match a certain pattern to collect
search-paths for zephyr-modules in the ZEPHYR_MOUDULES environment variable."
  (string-append
   ;; Add the needed prefix to the module name.
   "/" %zephyr-module "/"
   ;; Get the module name from the usually prefixed package name.
   (regexp-substitute #f (string-match "^(zephyr-module-|)"
                                       (package-name zephyr-module))
                         "" 'post)))

(define-public zephyr-module-template
  "Return a template package to inherit zephyr module packages from.  It
provides the build-system and proper arguments."
  (package
    (name "zephyr-module-template")
    (version "0")
    (source #f)
    (build-system copy-build-system)
    (arguments
      (list #:install-plan
            #~(list
               (list "." #$(zephyr-module-installation-target this-package)))))
    (home-page #f)
    (synopsis #f)
    (description #f)
    (license #f)))

(define-public zephyr-module-cmsis
  (let ((revision "1")
        (commit "74981bf893e8b10931464b9945e2143d99a3f0a3"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-cmsis")
      (version (git-version "5.8.0" revision commit))
      (source (origin
                (method git-fetch)
                (uri (git-reference
                      (url "https://github.com/zephyrproject-rtos/cmsis")
                      (commit commit)))
                      (file-name (git-file-name name version))
                (sha256
                 (base32
                  "11wwcdwzi5ac8k881616p69v7cz356cwvbqsmmfw3w3v63b9dsmy"))))
    (home-page "https://github.com/zephyrproject-rtos/cmsis")
    (synopsis "Zephyr module for CMSIS")
    (description "Zephyr module providing the Common Microcontroller
Software Interface Standard.")
      (license license:apsl2))))

(define-public zephyr-module-hal-nordic
  (let ((revision "1")
        (commit "cf6e9fc5f7c2c98df26f2a4227a95df9a50823e7"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-hal-nordic")
      (version (git-version "3.1.0" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/hal_nordic")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "1zbnhf7r9sg67xjhbdh6fn4gvccc71pxqcmbfnsi6a75bhfv9y55"))))
      (home-page "https://github.com/zephyrproject-rtos/hal_nordic")
	  (synopsis "Zephyr module for Nordic Semiconductor's SoCs and SiPs")
	  (description "Zephyr module providing the Hardware Abstraction Layer for
Nordic Semiconductor's SoCs and SiPs.

Supported SoCs and SiPs:
@itemize
@item nRF51 Series
@item nRF52805
@item nRF52810
@item nRF52811
@item nRF52820
@item nRF52832
@item nRF52833
@item nRF52840
@item nRF5340
@item nRF9131
@item nRF9160
@item nRF9161
@end itemize
")
	(license license:bsd-3))))

(define-public zephyr-module-hal-nordic-2.11
  (let ((revision "0")
        (commit "5644a13252e5d12e3e841105d106cfdeb40e59f9"))
    (package/inherit zephyr-module-hal-nordic
      (name "zephyr-module-hal-nordic")
      (version (git-version "2.11.0" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/hal_nordic")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "0lj7wlbfp9pb5pv819h9kbddmlzfbdnbmxhpm1i4xmf89z9v14sm")))))))

(define-public zephyr-module-hal-stm32
  (let ((revision "1")
        (commit "d466dc8421ee0c6592bb5682aa93a671bc948107"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-hal-stm32")
      ;; Using highest version number listed in:
      ;; https://github.com/zephyrproject-rtos/hal_stm32/blob/main/stm32cube/common_ll/README.rst
      (version (git-version "1.27.1" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/hal_stm32")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "0q0ckial6a3lvlag44zm65dklbbdnqpzr1vbh85dhwx7acpjd5ni"))))
      (home-page "https://github.com/zephyrproject-rtos/hal_stm32")
	  (synopsis "Zephyr module for STM32 microcontrollers")
	  (description "Zephyr module providing the required STM32cube packages,
dtsi files and libraries needed to build a Zephyr application running on STM32
silicon.")
	(license license:bsd-3))))

(define-public zephyr-module-lvgl-8.2.0
  (let ((revision "1")
        (commit "70a7849726be8375e3d941153dc417823ea7f355"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-lvgl")
      (version (git-version "8.2.0" revision commit)) ; Taken from lvgl.h.
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zmkfirmware/lvgl")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "147mykkb72nwbjhrw4z7h0kkxw4p7kvy0w001s44rgplxhqqsg98"))))
      (home-page "https://github.com/zmkfirmware/lvgl")
	  (synopsis "Zephyr module for LVGL")
	  (description "Zephyr module providing LVGL, the Light and Versatile
Graphics Library for an embedded GUI with graphical elements, visual effects
and a low memory footprint.")
	  (license license:apsl2))))

(define-public zephyr-module-lvgl
  (let ((revision "2")
        (commit "5da257f782a8f9c6e265bdc60ebc2a93fdee24de"))
    (package/inherit zephyr-module-lvgl-8.2.0
      (name "zephyr-module-lvgl")
      (version (git-version "8.3.7" revision commit)) ; Taken from lvgl.h.
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/lvgl")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "14isczxi36dasks1w4hwdlbzpvja4wal458i0km0hi92bbxayg0a")))))))

(define-public zephyr-module-mbedtls
  (let ((revision "1")
        (commit "c38dc78d9a8dcbe43b898cc1171ab33ba3e6fc26"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-mbedtls")
      (version (git-version "3.4.0" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/mbedtls")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "0661myy0wjz38nypbyfw51x10mzg57syb5c28irblgjm2w25wbi7"))))
      (home-page "https://github.com/zephyrproject-rtos/mbedtls")
	  (synopsis "Zephyr module for Mbed TLS")
	  (description "Zephyr module providing Mbed TLS, a C library that
implements cryptographic primitives, X.509 certificate manipulation and the
SSL/TLS and DTLS protocols.  Its small code footprint makes it suitable for
embedded systems.")
	  (license license:apsl2))))

(define-public zephyr-module-mcuboot
  (let ((revision "1")
        (commit "76d19b3b8885ea7ae25a6f4f5d8501f7ec646447"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-mcuboot")
      (version (git-version "1.11.0-dev" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/mcuboot")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "1frm9330bir1cz7h87qq26r74igy3pvrz3iqpvc7r6l7silj0fxf"))))
      (home-page "https://github.com/zephyrproject-rtos/mcuboot")
	  (synopsis "Zephyr module for MCUboot")
	  (description "Zephyr module providing the secure bootloader MCUboot for
32-bit microcontrollers.  It defines a common infrastructure for the bootloader
and the system flash layout on microcontroller systems, and provides a secure
bootloader that enables easy software upgrade.")
	  (license license:apsl2))))

(define-public zephyr-module-tinycrypt
  (let ((revision "1")
        (commit "3e9a49d2672ec01435ffbf0d788db6d95ef28de0"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-tinycrypt")
      (version (git-version "0.2.8" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/tinycrypt")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "19d2q9y23yzz9i383q3cldjl3k5mryx9762cab23zy3ijdnmj2z6"))))
      (home-page "https://github.com/zephyrproject-rtos/tinycrypt")
	  (synopsis "Zephyr module for the TinyCrypt library")
	  (description "Zephyr module providing the TinyCrypt library.")
	  (license (license:non-copyleft "file://README.zephyr")))))

(define-public zephyr-module-zcbor
  (let ((revision "1")
        (commit "67fd8bb88d3136738661fa8bb5f9989103f4599e"))
    (package/inherit zephyr-module-template
      (name "zephyr-module-zcbor")
      (version (git-version "0.7.0" revision commit))
      (source (origin
		        (method git-fetch)
		        (uri (git-reference
			          (url "https://github.com/zephyrproject-rtos/zcbor")
			          (commit commit)))
		        (file-name (git-file-name name version))
		        (sha256
		         (base32
		          "16138k7xlahf63dfvplm8c2m0kxs1g17gcx1fa31y4gcfbi3b0k7"))))
      (home-page "https://github.com/zephyrproject-rtos/zcbor")
	  (synopsis "Zephyr module for the zcbor library")
	  (description "Zephyr module providing the zcbor low footprint CBOR
(Concise Binary Object Representation) library in the C language, tailored for
use in microcontrollers.")
	  (license license:apsl2))))


[-- Attachment #5: apps.scm --]
[-- Type: text/x-scheme, Size: 12588 bytes --]

;;; GNU Guix --- Functional package management for GNU
;;;
;;; Copyright © 2023 Stefan <stefan-guix@vodafonemail.de>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (zephyr apps)
  #:use-module (embedded)
  #:use-module (gnu packages)
  #:use-module (gnu packages python-crypto)
  #:use-module (gnu packages python-xyz)
  #:use-module (gnu packages python-web)
  #:use-module (gnu packages tls)
  #:use-module (guix build-system cmake)
  #:use-module (guix build-system python)
  #:use-module (guix build-system trivial)
  #:use-module (guix gexp)
  #:use-module (guix git-download)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (guix utils)
  #:use-module (ice-9 optargs)
  #:use-module ((srfi srfi-1) #:select (delete-duplicates second))
  #:use-module (zephyr)
  #:use-module (zephyr modules))

(define-public (complete-zephyr-application zephyr-application
                                            zephyr
                                            zephyr-build-tools
                                            target
                                            toolchain
                                            c-toolchain
                                            directory-to-install-from
                                            source-prefix
                                            target-prefix)
  "Complete an incomplete ZEPHYR-APPLICATION package with target specific Zephyr
boilerplate."
  (let ((extended-inputs (modify-inputs
                          (package-inputs zephyr-application)
                          (prepend zephyr zephyr-build-tools)))
        (cross-compile-prefix (file-append toolchain "/bin/" target "-")))
    (package-with-c-toolchain
     (package
       (inherit zephyr-application)
       (build-system cmake-build-system)
       (arguments
         (append
          (substitute-keyword-arguments (package-arguments zephyr-application)
           ((#:configure-flags configure-flags #~(list))
             #~(append #$configure-flags
                (list
                 "-DZEPHYR_TOOLCHAIN_VARIANT=cross-compile"
                 (string-append "-DCROSS_COMPILE=" #$cross-compile-prefix)))))
          (list
           #:tests? #f
           #:phases
           #~(modify-phases %standard-phases
             (add-after 'set-paths 'correct-ZEPHYR_MODULES
               ;; The search-path-specification is not powerful enough. Zephyr
               ;; modules contain a zephyr-module/<name>/zephyr directory
               ;; without a common pattern for <name> and the ZEPHYR_MODULES
               ;; environment variable needs to list the zephyr-module/<name>
               ;; directories separated by semicolons.
               (lambda _
                 (use-modules (ice-9 regex))
                 (let ((zephyr-modules (getenv "ZEPHYR_MODULES")))
                   (when zephyr-modules
                     (setenv "ZEPHYR_MODULES"
                             (string-join
                              (map
                               (lambda (module)
                                 (dirname
                                  (car
                                   (let ((length (string-length module)))
                                     (find-files module
                                                 (lambda (name stat)
                                                   (string-match
                                                    "^/[^/]+/zephyr$"
                                                    (string-drop name length)))
                                                 #:directories? #t)))))
                               (string-split zephyr-modules #\:))
                              ";"))
                     (format
                      #t
                      "environment variable `ZEPHYR_MODULES' set to `~a'~%"
                      (getenv "ZEPHYR_MODULES"))))))
               (replace 'install
                 (lambda _
                   (let* ((source-prefix
                           #$(string-append directory-to-install-from "/"
                                            source-prefix))
                          (target-prefix
                           #$(string-append directory-to-install-from "/"
                                            target-prefix))
                          (source-prefix-length (string-length source-prefix))
                          (primary-files-to-install
                           (list (string-append source-prefix ".uf2")))
                          (files-to-install
                           (map (lambda (suffix)
                                  (string-append source-prefix suffix))
                                '(".bin" ".dts" ".elf" ".hex" ".map" ".stat")))
                          (source-files
                           (find-files #$directory-to-install-from
                                       (lambda (file stat)
                                         (member file primary-files-to-install))
                                       #:directories? #f))
                          (source-files
                           (if (null? source-files)
                               (find-files #$directory-to-install-from
                                           (lambda (file stat)
                                             (member file files-to-install))
                                           #:directories? #f)
                               source-files))
                          (target-files
                           (map (lambda (file)
                                  (string-replace
                                   file target-prefix 0 source-prefix-length))
                                 source-files)))
                     (for-each rename-file source-files target-files)
                     (mkdir #$output)
                     (for-each (lambda (file) (install-file file #$output))
                               target-files))))))))
       (inputs extended-inputs)
       (license (delete-duplicates
                 (cons (package-license zephyr-application)
                       (map (compose package-license second)
                            (filter package? extended-inputs))))))
    c-toolchain)))

(define*-public (make-zephyr-application-for-arm zephyr-application
                                                 #:key
                                                 (zephyr zephyr)
                                                 files-to-install
                                                 (directory-to-install-from
                                                  "zephyr")
                                                 (source-prefix "zephyr")
                                                 target-prefix)
  "Make a Zephyr application for Arm microcontrollers by completing the
incomplete ZEPHYR-APPLICATION package with Arm specific Zephyr boilerplate."
  (complete-zephyr-application zephyr-application
                               zephyr
                               zephyr-build-tools
                               "arm-none-eabi"
                               gcc12-cross-newlib-arm-none-eabi-toolchain
                               gcc12-cross-newlib-arm-none-eabi-c-toolchain
                               directory-to-install-from
                               source-prefix
                               (or target-prefix
                                   (package-name zephyr-application))))

(define-public zephyr-hello-world
  (make-zephyr-application-for-arm
   (package
     (name "zephyr-hello-world")
     (version (package-version zephyr))
     (source (file-append zephyr "/zephyr-base/samples/hello_world"))
     (build-system #f)
     (arguments
      (list
       #:configure-flags
       #~(list "-DBOARD=nucleo_wb55rg"
               "-DCONFIG_BT=y"
               "-DCONFIG_BT_STM32_IPM=y"
               "-DCMAKE_C_FLAGS=-DCFG_BLE_LSE_SOURCE=1"
               "-DCMAKE_BUILD_TYPE=RelMinSize")))
     (inputs (list zephyr-module-cmsis
                   zephyr-module-hal-stm32
                   zephyr-module-tinycrypt))
     (home-page (package-home-page zephyr))
     (synopsis "Hello-world sample of the Zephyr Project")
     (description "A simple Zephyr Project sample that prints \"Hello World\" to
the console.")
     (license (package-license zephyr)))))

(define*-public (make-zephyr-mcuboot-for-arm board extra-inputs
                 #:key
                 (configure-flags #~(list))
                 (key (file-append zephyr-module-mcuboot
                                   (zephyr-module-installation-target
                                    zephyr-module-mcuboot)
                                   "/main/root-rsa-2048.pem")))
  "Make an MCUboot bootloader package for Zephyr targeting the Arm
microcontroller BOARD.  Add EXTRA-INPUTS to the build and use the list of
optional CONFIGURE-FLAGS.  Use the public KEY file for firmware decryption."
  (make-zephyr-application-for-arm
   (package/inherit zephyr-module-mcuboot
     (name (string-append "zephyr-mcuboot-" board))
     (source
       (file-append zephyr-module-mcuboot
                    (zephyr-module-installation-target zephyr-module-mcuboot)))
     (arguments
      (list
       #:configure-flags
       #~(append #$configure-flags
                 (list "-S../source/boot/zephyr"
                       (string-append "-DBOARD=" #$board)
                       (string-append "-DTINYCRYPT_DIR=PATH:"
                                      #$zephyr-module-tinycrypt
                                      "/zephyr-module/tinycrypt/lib")))))
     (inputs (append extra-inputs (list python-cbor2
                                        python-click
                                        python-cryptography
                                        python-intelhex
                                        zephyr-module-mcuboot
                                        zephyr-module-mbedtls
                                        zephyr-module-zcbor))))))

(define-public zephyr-mcuboot-nrf52840dongle_nrf52840
 (make-zephyr-mcuboot-for-arm "nrf52840dongle_nrf52840"
                              (list zephyr-module-hal-nordic
                                    zephyr-module-cmsis)
                              #:configure-flags
                              #~(list "-DMCUBOOT_USE_MBED_TLS=y"
                                      "-DCONFIG_LOG=y")))

(define-public imgtool
    (package
      (name "imgtool")
      (version (package-version zephyr-module-mcuboot))
      (source (file-append zephyr-module-mcuboot
                           (zephyr-module-installation-target
                            zephyr-module-mcuboot)
                           "mcuboot/scripts"))
      (build-system python-build-system)
      (arguments
        (list #:phases
              #~(modify-phases %standard-phases
                 (add-after 'unpack 'disable-broken-tests
                  (lambda _
                    (substitute* "imgtool/keys/ecdsa_test.py"
                     ;; This one is calling _unsupported, which raises an
                     ;; ECDSAUsageError.
                     (("def test_keygen") "def broken_test_keygen")
                     ;; This one is failing with an AttributeError.
                     (("def test_emit_pub") "def broken_test_emit_pub")))))))
      (propagated-inputs (list openssl-3.0
                               python-cbor2
                               python-click
                               python-cryptography
			                   python-intelhex
                               python-pyyaml))
	  (home-page (package-home-page zephyr-module-mcuboot))
	  (synopsis "MCUboot's image signing and key management")
	  (description "A tool to securely sign firmware images for booting by
MCUboot.")
	  (license (package-license zephyr-module-mcuboot))))

[-- Attachment #6: zmk.scm --]
[-- Type: text/x-scheme, Size: 24011 bytes --]

;;; GNU Guix --- Functional package management for GNU
;;;
;;; Copyright © 2023 Stefan <stefan-guix@vodafonemail.de>
;;;
;;; This file is not part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (zephyr zmk)
  #:use-module (guix build union)
  #:use-module (guix build utils)
  #:use-module (guix build-system trivial)
  #:use-module (guix gexp)
  #:use-module (guix git-download)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (ice-9 match)
  #:use-module (ice-9 optargs)
  #:use-module (srfi srfi-1)
  #:use-module (zephyr)
  #:use-module (zephyr apps)
  #:use-module (zephyr modules))

(define zmk-config
  (package
    (name "zmk-config")
    (version "0")
    (source #f)
    (build-system trivial-build-system)
    (arguments (list #:builder #~(mkdir #$output)))
    (native-search-paths
     (list
      (search-path-specification
      (variable "ZMK_CONFIG")
      (files '("zmk-config"))
      (separator #f)
      (file-type 'directory)
      (file-pattern "^config$"))))
    (home-page "https://zmk.dev/docs/config#config-file-locations")
    (synopsis "ZMK firmware configuration")
    (description "This ZMK Firmware configuration is a helper to set the
ZMK_CONFIG environment varibale during a ZMK Firmware package build to its
configuration input.  Add a file-like object like a file-union or a package
containing a zmk-config/config folder as build input to a ZMK Firmare packege.")
    (license license:expat)))


(define*-public (make-zmk board
                          #:key
                          (shield "")
                          (extra-inputs '())
                          (extra-name "")
                          (patches '())
                          snippet)
  "Make a ZMK firmware package for a keyboard consisting of an Arm
microcontroller BOARD with a SHIELD PCB using the list of EXTRA-INPUTS.  Add an
EXTRA-NAME with a trailing hyphen to customize the package name.  Use PATCHES or
SNIPPET to modify the ZMK sources."
  (make-zephyr-application-for-arm
   (let* ((revision "1")
          (commit "9d714c0b69fee2098a010d29e534051aeca26386")
          (underscore->hyphen (lambda (name)
                                (string-map (lambda (char)
                                              (if (char=? char #\_)
                                                  #\-
                                                  char))
                                             name)))
          (board-name (underscore->hyphen board))
          (shield-name (underscore->hyphen shield))
          (shield (if (string-null? shield) #f shield)))
     (package
       (name (string-append shield-name (if shield "-" "")
                            extra-name board-name "-zmk"))
       (version (git-version "2023.06.12" revision commit))
       (source (origin
                 (method git-fetch)
                 (uri (git-reference
                      (url "https://github.com/zmkfirmware/zmk")
                      (commit commit)))
                 (file-name (git-file-name name version))
                 (sha256
                  (base32
                   "08mihhcdlb9hh1qa0l6limggmvy98qiq6051p9qhnh6zbs8021h7"))
                 (patches patches)
                 (snippet snippet)))
       (build-system #f)
       (arguments
        (list
         #:out-of-source? #t
         #:configure-flags
         #~(append (list "-S../source/app"
                         (string-append "-DBOARD=" #$board))
                   (if #$shield
                       (list (string-append "-DSHIELD=" #$shield))
                       '()))))
       (inputs (append extra-inputs
                       (list zephyr-module-cmsis
                             zephyr-module-lvgl-8.2.0
                             zephyr-module-tinycrypt
                             zmk-config)))
       (home-page "https://zmk.dev")
       (synopsis (if shield (format #f "ZMK Firmware for a ~a keyboard with ~a"
                                       shield-name board-name)
                            (format #f "ZMK Firmware for a ~a keyboard"
                                       board-name)))
       (description "ZMK Firmware is an open source (MIT) keyboard firmware
built on the Zephyr™ Project Real Time Operating System (RTOS).")
       (license license:expat)))
    #:zephyr zephyr-3.2+zmk-fixes
    #:source-prefix "zmk"))

(define*-public (make-zmk-union zmk-packages #:key name synopsis)
  "Make a union of several ZMK Firmware packages for left and right hand or
settings-reset firmware files."
  (package
    (inherit (car zmk-packages))
    (name (or name (package-name (car zmk-packages))))
    (source #f)
    (build-system trivial-build-system)
    (arguments
      (list #:modules '((guix build union))
            #:builder
            #~(begin
                (use-modules ((guix build union)))
                (union-build #$output (quote #$zmk-packages)))))
    (synopsis (or synopsis (package-synopsis (car zmk-packages))))))

(define*-public (make-nrfmicro-13-zmk shield #:key zmk-config (extra-name ""))
  "Make a ZMK firmware package for a keyboard consisting of the nrfmicro 1.3/1.4
board with a SHIELD PCB.  Use the ZMK-CONFIG directory containing optional
boards/ or dts/ directories, or .conf, .keypad, .overlay files prefixed with
shield or board names."
  (make-zmk
   "nrfmicro_13"
   #:shield shield
   #:extra-name extra-name
   #:extra-inputs (append (list zephyr-module-hal-nordic-2.11)
                          (if zmk-config (list zmk-config)
                                         '()))
   #:snippet
   #~(begin
       (use-modules (guix build utils))
       (substitute* "app/CMakeLists.txt"
         ;; Move combo.c and behaviour_tap_dance.c above all other behaviors.
         ;; This fix is needed to get working layer-tap-dance. 
         (("^  target_sources\\(app PRIVATE src/combo.c\\)\n") "")
         (("^  target_sources\\(app PRIVATE src/behaviors/behavior_tap_dance.c\\)\n")
          "")
         (("^  target_sources\\(app PRIVATE src/hid.c\\)\n" line)
          (string-append
           line
           "  target_sources(app PRIVATE src/combo.c)\n"
           "  target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)\n"))))))

(define (hid-modifier modifier)
  "Map a symbol for a MODIFIER key into a macro symbol for a ZMK keymap file.
An unknown MODIFIER symbol is just returned."
  (define hid-modifier->zmk-macro
    '((⇧ . LS) (⌃ . LC) (⌥ . LA) (⌘ . LG)
      (R⌘ . RG) (R⌥ . RA) (R⌃ . RC) (R⇧ . RS)))
  (or (assoc-ref hid-modifier->zmk-macro modifier) modifier))

(define-public (special-bindings key-label)
  "Map a KEY-LABEL matching a special-binding into a binding symbol for a
ZMK keymap file.  An unknown KEY-LABEL symbol is just returned."
  (define special-bindings->zmk-name
    '(;; A whole in the keyboard matrix without meaning to ZMK.
      (◌ . "")
      ;; No functionality.
      (☒ . &none)
      ;; Fall-through to the next active lower layer.
      (☐ . &trans)
      ;; Keypress on sensor, requires two parameters for up and down keycodes.
      (⟳ . &inc_dec_kp)
      ;; Reset and bootloader, on split keyboards this is side specific.
      (⎊ . &sys_reset) (↯ . &bootloader)
      ;; Bluetooth, requires one or two parameters.
      (⌔ . &bt)
      ;; Backlight, requires one parameter.
      (☼ . &bl)))
  (or (assoc-ref special-bindings->zmk-name key-label) key-label))

(define-public (hid key-label)
  "Map a HID KEY-LABEL into a macro symbol for a ZMK keymap file. Any other
KEY-LABEL will be treated by 'special-bindings'."
  (define hid->zmk-name
    '((⎋ . ESC) (⎙ . PSCRN) (⤓ . SLCK) (⎉ . PAUSE_BREAK)
      (^ . GRAVE) (- . MINUS)
      (= . EQUAL) (⌫ . BSPC)
      (⇥ . TAB) (⟦ . LBKT) (⟧ . RBKT) (↲ . RET) (⏎ . RET) (↩ . RET)
      (⇪ . CAPS) (⍮ . SEMI) (⍘ . SQT) (⋕ . NUHS)
      (⇧ . LSHFT) (\ . NUBS)
      (‚ . COMMA) (· . DOT) (/ . SLASH) (R⇧ . RSHFT)
      (⌃ . LCTRL) (⌥ . LALT) (⌘ . LGUI) (␣ . SPC)
      (R⌘ . RGUI) (R⌥ . RALT) (R⌃ . RCTRL) (☰ . K_APP)
      (⌵ . INS) (⇱ . HOME) (↖ . HOME) (⇞ . PG_UP)
      (⌦ . DEL) (⇲ . END) (↘ . END) (⇟ . PG_DN)
      (← . LEFT) (↓ . DOWN) (↑ . UP) (→ . RIGHT)
      (⇠ . LEFT) (⇣ . DOWN) (⇡ . UP) (⇢ . RIGHT)
      (⇭ . KP_NUMLOCK) (NUM . KP_NUMLOCK)
      (⌧ . KP_CLEAR) (⟨ . KP_LPAR) (⟩ . KP_RPAR) (P= . KP_EQUAL)
      (÷ . KP_DIVIDE) (* . KP_MULTIPLY) (− . KP_MINUS) (+ . KP_PLUS)
      (P1 . KP_N1) (P2 . KP_N2) (P3 . KP_N3) (P4 . KP_N4) (P5 . KP_N5)
      (P6 . KP_N6) (P7 . KP_N7) (P8 . KP_N8) (P9 . KP_N9) (P0 . KP_N0)
      (P. . KP_DOT) (P, . KP_COMMA) (⌤ . ENTER)
      (✄ . C_AC_CUT) (◫ . C_AC_COPY) (⎀ . C_AC_PASTE)
      (↶ . C_AC_UNDO) (↷ . C_AC_REDO)
      (⌨ . C_AL_KEYBOARD_LAYOUT)))
  (special-bindings (or (assoc-ref hid->zmk-name key-label) key-label)))

(define-public (de key-label)
  "Map a german KEY-LABEL based on the QWERTZ-layout into an international HID
key-label, if needed, and return a symbol for a ZMK keymap file."
  (define de->hid
    '((ß . -) (´ . =)
      (Z . Y) (Ü . ⟦) (+ . ⟧)
      (Ö . ⍮) (Ä . ⍘)
      (< . \) (Y . Z) (- . /)
      (P+ . +) (P, . P.) (P. . P,)))
  (hid (or (assoc-ref de->hid key-label) key-label)))

(define-public (neo key-label)
  "Map a german KEY-LABEL based on the neo-layout into the international HID
key-label, if needed, and return a symbol as needed by a ZMK keymap file."
  (define neo->de
   '((T1 . ^)
               (X . Q) (V . W) (L . E) (C . R) (W . T)
     (M3 . ⇪)  (U . A) (I . S) (A . D) (E . F) (O . G)
     (M4 . <) (Ü . Y) (Ö . X) (Ä . C) (P . V) (Z . B)
                                             (- . ß) (T2 . ´)
     (K . Z) (H . U) (G . I) (F . O) (Q . P) (ẞ . Ü) (T3 . +)
     (S . H) (N . J) (R . K) (T . L) (D . Ö) (Y . Ä) (RM3 . ⋕)
     (B . N)                         (J . -) (RM4 . R⌥)
     (P⇥ . ⇭)))
  (de (or (assoc-ref neo->de key-label) key-label)))

(define*-public (zmk-keymap #:key (properties '())
                                  (behaviors '())
                                  (combos '())
                                  (conditional_layers '())
                                  (layers '())
                                  (macros '()))
  "Generate the content of a keymap file for ZMK.  Each layer in LAYERS has a
name, a layout and multiple rows, of which each contains the key-bindings.  The
last row contains the bindings for sensors.  The key-bindings use symbols from
the layout.  The BEHAVIORS, COMBOS, MACROS and CONDITIONAL-LAYERS contain lists
of strings to inject own appropiate definitions for ZMK.  PROPERTIES may contain
properties for behaviors or even C macro definitions."
  (define (include file)
    "Return an include statement for file"
    (string-append "#include <" file ">"))
  (define (include-binding file)
    "Return an include statement for file defining bindings."
    (include (string-append "dt-bindings/zmk/" file)))
  (define (includes)
    "Return all include statements offered by ZMK for keymap files."
    (append (map include '("behaviors.dtsi"))
            (map include-binding '("backlight.h" "bt.h" "ext_power.h"
                                   "hid_usage.h" "hid_usage_pages.h" "keys.h"
                                   "kscan_mock.h" "matrix_transform.h"
                                   "modifiers.h" "outputs.h" "reset.h"
                                   "rgb.h"))))

  (define* (keymap-layer name layout rows)
    "Return a string with a keymap layer definition NAME for a ZMK keymap file,
consisting of ROWS of keys with their labels based on LAYOUT."

    (define (zmk-name->string zmk-name)
      "Tansform a ZMK-NAME into a string."
      (cond ((string? zmk-name) zmk-name)
            ((number? zmk-name) (number->string zmk-name))
            (else (symbol->string zmk-name))))

    (define (key-label->zmk key-label)
      "Tansform a key-label based on a keyboard-layout into a ZMK string."
      (zmk-name->string (layout key-label)))

    (define (modified-key->zmk modified-key)
      "Transform a possibly MODIFIED-KEY like '(⇧ ⌥ ⎋) into the \"LS((LA(ESC))\"
respresentation of ZMK."
      (match modified-key
        ((modifier modifier-or-key . rest)
         (string-append (zmk-name->string (hid-modifier modifier))
                        "("
                        (modified-key->zmk (cdr modified-key))
                        ")"))
        ((unmodified-key)
         (modified-key->zmk unmodified-key))
        (key-label
         (key-label->zmk key-label))))

    (define (behavior->zmk behavior strings-of-layers-and-modified-keys)
      "Join a BEHAVIOR symbol like '&mt with STRINGS-OF-LAYERS-AND-MODIFIED-KEYS
as parameters like '(\"LALT\" \"ESC\") into the \"&mt LALT ESC\" respresentation
of ZMK."
      (string-join (cons (key-label->zmk behavior)
                   strings-of-layers-and-modified-keys)))

    (define (&-symbol? symbol)
      "Predicate to identify a symbol as a ZMK behavior prefixed with &."
      (string=? "&" (string-take (key-label->zmk symbol) 1)))

    (define (key-binding->zmk key-binding)
      "Transform the KEY-BINDING, which could be a key-label, a modified key, or
a behavior with layer and modified key parameters, into the representation of a
ZMK behavior for a keymap layer."
      (match key-binding
        (((? &-symbol? behavior) . parameters)
          ;; A list starting with an &-symbol is a behavior with parameters.
          ;; The parameters themselves may be layers or modified keys.
          (behavior->zmk behavior (map modified-key->zmk parameters)))
        (modified-key
          (let ((modified-key (modified-key->zmk modified-key)))
            (if (or (string-null? modified-key)
                    (&-symbol? modified-key))
                ;; There is nothing or a behavior is present, just use it.
                modified-key
                ;; Add a key-press behavior to the modified-key and start over.
                (behavior->zmk '&kp (list modified-key)))))))

    (define (keys->zmk key-bindings)
      "Transform a list of KEY-BINDINGS into ZMK behaviors for a keymap layer."
      (string-join (map (lambda (zmk-behavior)
                          (string-pad-right
                           zmk-behavior
                           (max 12 (string-length zmk-behavior))))
                        (map key-binding->zmk key-bindings))))

    (string-append  "    " name "_layer {"
                    "\n      bindings = <"
                    (string-join (map keys->zmk (drop-right rows 1))
                                 "\n        " 'prefix)
                    "\n      >;"
                    (if (null? (last rows))
                        ""
                        (string-append
                         "\n      sensor-bindings = <"
                         (string-join (map keys->zmk (last rows))
                                      "\n        " 'prefix)
                         "\n      >;"))
                    "\n    };"))

  (define (layer layer)
    "Return a string for a ZMK keymap file containing a layer definition."
    (match layer
      ((name layout . rows)
       (keymap-layer name layout rows))))

  (string-join (append (includes)
                       properties
                       (list "/ {"
                             "  behaviors {")
                       behaviors
                       (list "  };"
                             "  combos {"
                             "    compatible = \"zmk,combos\";")
                       combos
                       (list "  };"
                             "  conditional_layers {"
                             "    compatible = \"zmk,conditional_layers\";")
                       conditional_layers
                       (list "  };"
                             "  keymap {"
                             "    compatible = \"zmk,keymap\";")
                       (map layer layers)
                       (list "  };"
                             "  macros {")
                       macros
                       (list "  };"
                             "};"))
               "\n"))

;; This is a hold-tap behavior for a key, which momentarily activates a layer,
;; if hold, or switches to that layer, if tapped.
(define-public layer-hold-tap
"    /omit-if-no-ref/ lht: behavior_layer_hold_tap {
      compatible = \"zmk,behavior-hold-tap\";
      label = \"LAYER_HOLD_TAP\";
      #binding-cells = <2>;
      flavor = \"balanced\";
      tapping-term-ms = <200>;
      bindings = <&mo>, <&to>;
    };
")

(define-public (layer-tap-dance n)
  "Give a tap-dance behavior '&ltdN', which counts the taps for the layer number
and momentarily activates that layer on hold, or switches to that layer on tap.
If the parameter N is 0, then taps select the layers 1, 2, 3.  If N is 1, taps
select the layers 0, 2, 3, and so on."
  (let ((first (if (>= n 1) "0 0" "1 1"))
         (second (if (>= n 2) "1 1" "2 2"))
         (third (if (>= n 3) "2 2" "3 3"))
         (n (number->string n)))
    (string-append
"    /omit-if-no-ref/ ltd" n ": behavior_layer_tap_dance" n " {
      compatible = \"zmk,behavior-tap-dance\";
      label = \"LAYER_TAP_DANCE" n "\";
      #binding-cells = <0>;
      tapping-term-ms = <200>;
      bindings = <&lht " first ">, <&lht " second ">, <&lht " third ">;
    };
")))

(define-public settings-reset-nrfmicro-13-zmk
  (package
    (inherit (make-nrfmicro-13-zmk "settings_reset"))
    (synopsis "ZMK settings reset firmware for split-keyboards with nrfmicro
1.3/1.4 boards")
    (description "Pairing issues of ZMK firmware split-keyboard halves can be
resolved by flashing this settings reset firmware to both controllers.")))

(define-public redox-left-nrfmicro-13-zmk
  (make-nrfmicro-13-zmk "redox_left"))

(define-public redox-right-nrfmicro-13-zmk
  (make-nrfmicro-13-zmk "redox_right"))

(define-public redox-nrfmicro-13-zmk
  (make-zmk-union
   (list settings-reset-nrfmicro-13-zmk
         redox-left-nrfmicro-13-zmk
         redox-right-nrfmicro-13-zmk)
   #:name "redox-nrfmicro-13-zmk"
   #:synopsis "ZMK firmware for a Redox shield with nrfmicro-1.3/1.4 board"))

(define-public redox-neo-keymap
  (let* ((M3Y '(&mt RM3 Y))
         (⇧- '(&mt ⇧ -))
         (R⇧ẞ '(&mt R⇧ ẞ))
         (⌥- '(&mt ⌥ -))
         (⌥. '(&mt ⌥ ·))
         (l1␣ '(&lt 1 ␣))
         (l0 '(&ltd0)) ; Layer tap-dance for layer 0.
         (l1 '(&ltd1)) ; Layer tap-dance for layer 1.
         (l2 '(&ltd2)) ; Layer tap-dance for layer 2.
         (l3 '(&ltd3)) ; Layer tap-dance for layer 3.
         (⌔1 '(⌔ BT_SEL 0))
         (⌔2 '(⌔ BT_SEL 1))
         (⌔3 '(⌔ BT_SEL 2))
         (⌔4 '(⌔ BT_SEL 3))
         (⌔5 '(⌔ BT_SEL 4))
         (⌔⌧ '(⌔ BT_CLR))
         (⌔→ '(⌔ BT_NXT))
         (⌔← '(⌔ BT_PRV))
         (keymap
          (zmk-keymap
           #:layers
           `(("default" ,neo
              ( ⎋   N1  N2  N3  N4  N5  ◌   ◌   ◌   ◌   N6  N7  N8  N9  N0  ⌫  )
              ( ⇥   X   V   L   C   W   T2  ◌   ◌   ☰   K   H   G   F   Q   ↲  )
              ( M3  U   I   A   E   O   T3  ◌   ◌   ⌵   S   N   R   T   D  ,M3Y)
              (,⇧-  Ü   Ö   Ä   P   Z   ⇧   ⌘   R⌘  R⇧  B   M   ‚   ·   J  ,R⇧ẞ)
              ( ⌃   ⌥   T1  ⌦  ,l0  ◌   ⌃   M4  RM4 R⌃  ◌  ,l1␣ ⌦  ,l0 ,⌥-  R⌃ )
              ())
             ("cursor" ,neo
              ( ⎋   F1  F2  F3  F4  F5  ◌   ◌   ◌   ◌   F6  F7  F8  F9  F10 ⌫  )
              ( ⇥   ⇞   ⌫   ↑   ⌦   ⇟   ⎉   ◌   ◌   ☒   ⇞   ⌫   ↑   ⌦   ⇟   ↲  )
              ( ☒   ⇱   ←   ↓   →   ⇲   ☒   ◌   ◌   ☒   ⇱   ←   ↓   →   ⇲   ☒  )
              (,⇧-  ⎋   ⇥   ⎀   ↲   ↶   ⇧   ⌘   R⌘  ⇧   ⎋   ⇥   ⎀   ↲   ↶   R⇧ )
              ( ⌃   ⌥   ⎙   ⌦  ,l1  ◌   ⌃   ⌥   ⌥   R⌃  ◌   ␣   ⌦  ,l1 ,⌥-  R⌃ )
              ())
             ("keypad" ,neo
              ( ⎋   F11 F12 F13 F14 F15 ◌   ◌   ◌   ◌   ⎋   P⇥  ÷   *   −   ⌫  )
              ( ⇥   ⇞   ⌫   ↑   ⌦   ⇟   ☒   ◌   ◌   ⇭   ☒   P7  P8  P9  P+  ↲  )
              ( M3  ⇱   ←   ↓   →   ⇲   ☒   ◌   ◌   ☒   ☒   P4  P5  P6  P=  M3 )
              (,⇧-  ⎋   ⇥   ⎀   ↲   ↶   ⇧   ⌘   R⌘  R⇧  ␣   P1  P2  P3  ⌤   R⇧ )
              ( ⌃   ⌥   ☒   ⌦  ,l2  ◌   ⌃   M4  RM4 R⌃  ◌   P0  ⌦   P, ,⌥.  R⌃ )
              ())
             ("zmk" ,neo
              ( ⎊  ,⌔1 ,⌔2 ,⌔3 ,⌔4 ,⌔5  ◌   ◌   ◌   ◌   ☒   ☒   ☒   ☒   ☒   ⎊  )
              ( ↯   ☒   ☒   ☒   ☒   ☒   ☒   ◌   ◌   ☒   ☒   ☒   ☒   ☒   ☒   ↯  )
              ( ☒   ☒  ,⌔← ,⌔⌧ ,⌔→  ☒   ☒   ◌   ◌   ☒   ☒   ☒   ☒   ☒   ☒   ☒  )
              ( ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒   ☒  )
              ( ☒   ☒   ☒   ☒  ,l3  ◌   ☒   ☒   ☒   ☒   ☒   ☒   ☒  ,l3  ☒   ☒  )
              ()))
           #:properties (list "&lt {quick-tap-ms = <200>;};"
                              "&mt {quick-tap-ms = <200>;};")
           #:combos (list "    combo_up {" ; G F ⇒ ↑
                          "      key-positions = <22 23>;"
                          "      bindings = <&kp UP>;"
                          "    };"
                          "    combo_left {" ; N R ⇒ ←
                          "      key-positions = <35 36>;"
                          "      bindings = <&kp LEFT>;"
                          "    };"
                          "    combo_down {" ; R T ⇒ ↓
                          "      key-positions = <36 37>;"
                          "      bindings = <&kp DOWN>;"
                          "    };"
                          "    combo_right {" ; T D ⇒ →
                          "      key-positions = <37 38>;"
                          "      bindings = <&kp RIGHT>;"
                          "    };")
           #:behaviors (list layer-hold-tap
                             (layer-tap-dance 0)
                             (layer-tap-dance 1)
                             (layer-tap-dance 2)
                             (layer-tap-dance 3)))))
    (file-union "redox-config"
                (list (list "zmk-config/config/redox.keymap"
                            (plain-file "redox-neo.keymap" keymap))))))

(define-public redox-left-neo-nrfmicro-13-zmk
  (make-nrfmicro-13-zmk "redox_left"
                        #:zmk-config redox-neo-keymap
                        #:extra-name "neo-"))

(define-public redox-right-neo-nrfmicro-13-zmk
  (make-nrfmicro-13-zmk "redox_right"
                        #:zmk-config redox-neo-keymap
                        #:extra-name "neo-"))

(define-public redox-neo-nrfmicro-13-zmk
  (make-zmk-union
   (list settings-reset-nrfmicro-13-zmk
         redox-left-neo-nrfmicro-13-zmk
         redox-right-neo-nrfmicro-13-zmk)
   #:name "redox-neo-nrfmicro-13-zmk"
   #:synopsis
   "Neo layout ZMK firmware for a Redox shield with nrfmicro-1.3/1.4 board"))


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2023-10-02 18:55 A different way to build GCC to overcome issues, especially with C++ for embedded systems Stefan
@ 2023-12-21 13:32 ` Attila Lendvai
  2023-12-21 14:01   ` Jean-Pierre De Jesus Diaz
  2023-12-22  9:33   ` Stefan
  0 siblings, 2 replies; 13+ messages in thread
From: Attila Lendvai @ 2023-12-21 13:32 UTC (permalink / raw)
  To: Stefan; +Cc: guix-devel

hi Stefan,


> In the end it worked nicely for my embedded C++ stuff and I also managed
> to compile a custom keyboard firmware based on ZMK using Zephyr,
> although that is just C code.


i've also encountered a problem with the guix cross compiling tools as i have described here:

https://lists.gnu.org/archive/html/guix-devel/2023-12/msg00179.html

i tried with your gcc (copied into guix as (gnu packages embedded2)):

~/workspace/guix/guix/pre-inst-env guix shell gcc-toolchain cmake make pkg-config -e '(@ (gnu packages embedded2) gcc12-cross-newlib-arm-none-eabi-toolchain)'
cd ~/workspace/bios/pico-serprog
cmake .
make

but it errors out with:

$ make
[  1%] Linking ASM executable bs2_default.elf
arm-none-eabi-gcc: error: nosys.specs: No such file or directory

IIRC, this happens with the vanilla guix packages when i try to use a gcc package instead of a gcc-toolchain package.

any thoughts on this?

-- 
• attila lendvai
• PGP: 963F 5D5F 45C7 DFCD 0A39
--
“There can be no causeless love or any sort of causeless emotion. An emotion is a response to a fact of reality, an estimate dictated by your standards.”
	— Ayn Rand (1905–1982)



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2023-12-21 13:32 ` Attila Lendvai
@ 2023-12-21 14:01   ` Jean-Pierre De Jesus Diaz
  2023-12-22  9:56     ` Stefan
  2023-12-22  9:33   ` Stefan
  1 sibling, 1 reply; 13+ messages in thread
From: Jean-Pierre De Jesus Diaz @ 2023-12-21 14:01 UTC (permalink / raw)
  To: Attila Lendvai; +Cc: Stefan, guix-devel

Hello everyone,

I was working before on embedded toolchains with Guix and added AVR
platform as a result. [1]

Just FYI, I have a WIP patch series to add support for arm-none-eabi using the
Guix cross compilation methods, e.g.: using #:target and so on and
also to add an user installable toolchain as done with AVR on [1].

The arm-none-eabi target is not finished yet since I'm running into some
issues when building Axoloti which depends on the (gnu packages embedded)
toolchains and I'm trying to migrate it to use `cross-gcc-toolchain` but it is
proving a bit difficult due to search paths but I'm trying to solve it anyway.

>$ make
>[  1%] Linking ASM executable bs2_default.elf
>arm-none-eabi-gcc: error: nosys.specs: No such file or directory
>
>IIRC, this happens with the vanilla guix packages when i try to use a gcc package instead of a gcc-toolchain package.

This happens when the toolchain doesn't have the Newlib C library which
includes the nosys.specs file so probably if Newlib is present it's then that
GCC can't find the specs file.

[1]: https://issues.guix.gnu.org/66263

-- 
Jean-Pierre De Jesus DIAZ
Foundation Devices, Inc.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2023-12-21 13:32 ` Attila Lendvai
  2023-12-21 14:01   ` Jean-Pierre De Jesus Diaz
@ 2023-12-22  9:33   ` Stefan
  2023-12-22 10:56     ` Attila Lendvai
  1 sibling, 1 reply; 13+ messages in thread
From: Stefan @ 2023-12-22  9:33 UTC (permalink / raw)
  To: Attila Lendvai; +Cc: guix-devel

Hi Attila!

>i tried with your gcc … but it errors out with:
>
>$ make
>[  1%] Linking ASM executable bs2_default.elf
>arm-none-eabi-gcc: error: nosys.specs: No such file or directory

That file is located here: /gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/lib/nosys.specs

Hm, it might be necessary to add that path per default to COMPILER_PATH as well with a -B option. This path currently only appears under LIBRARY_PATH, which seems to not be searched for spec files.
  
$ arm-none-eabi-g++ -v -E -xc++ - < /dev/null
Using built-in specs.
COLLECT_GCC=/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-toolchain-12.2.0/bin/arm-none-eabi-g++
Target: arm-none-eabi
Configured with:
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 12.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-E' '-mcpu=arm7tdmi' '-mfloat-abi=soft' '-marm' '-mlibarch=armv4t' '-march=armv4t'
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/libexec/gcc/arm-none-eabi/12.2.0/cc1plus -E -quiet -v -D__USES_INITFINI__ - -mcpu=arm7tdmi -mfloat-abi=soft -marm -mlibarch=armv4t -march=armv4t -dumpbase -
ignoring nonexistent directory "/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/../../../../../../../arm-none-eabi/include"
#include "..." search starts here:
#include <...> search starts here:
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/include-c++
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/include-c++/arm-none-eabi
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/include-c++/backward
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/include
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/include
  /gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/include-fixed
  /gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/include
End of search list.
# 0 "<stdin>"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "<stdin>"
COMPILER_PATH=/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/libexec/gcc/arm-none-eabi/12.2.0/:/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/libexec/gcc/arm-none-eabi/12.2.0/:/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0/libexec/gcc/arm-none-eabi/:/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/:/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/
LIBRARY_PATH=/gnu/store/…-gcc12-cross-newlib-arm-none-eabi-12.2.0-lib/lib/gcc/arm-none-eabi/12.2.0/:/gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/lib/
COLLECT_GCC_OPTIONS='-v' '-E' '-mcpu=arm7tdmi' '-mfloat-abi=soft' '-marm' '-mlibarch=armv4t' '-march=armv4t'

You may want to try to add -B /gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/lib to the linker options or to add COMPILER_PATH=/gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/lib in front of your command. Tell me about your results.

I'm about to update to GCC 13. There is some issue to work around (which smells like a similar one in Gentoo¹), I’ll see if I can add the newlib path to the COMPILER_PATH as well.


Bye

Stefan


¹ https://bugs.gentoo.org/905118



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2023-12-21 14:01   ` Jean-Pierre De Jesus Diaz
@ 2023-12-22  9:56     ` Stefan
  0 siblings, 0 replies; 13+ messages in thread
From: Stefan @ 2023-12-22  9:56 UTC (permalink / raw)
  To: Jean-Pierre De Jesus Diaz, Attila Lendvai; +Cc: guix-devel

Hi Jean-Pierre!

>The arm-none-eabi target is not finished yet since I'm running into some
>issues when building Axoloti which depends on the (gnu packages embedded)
>toolchains and I'm trying to migrate it to use `cross-gcc-toolchain` but it is
>proving a bit difficult due to search paths but I'm trying to solve it anyway.

These include path problems where exactly the problems which I solved with that gcc12 and gcc12-cross packages. Let's say that they are a proof-of-concept for a better way to build GCC, not relying on environment variables for standard include paths. My gut feeling is that the whole GCC version chain starting in (gnu packages commencement) should be build this way, and in the end also the cross-gcc-toolchain would not have these issues. However, I think that would be an enormous effort – a bit like rewriting the bootstrapping of Guix – and I have no clue how to start myself with it.


Bye

Stefan



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2023-12-22  9:33   ` Stefan
@ 2023-12-22 10:56     ` Attila Lendvai
  0 siblings, 0 replies; 13+ messages in thread
From: Attila Lendvai @ 2023-12-22 10:56 UTC (permalink / raw)
  To: Stefan; +Cc: guix-devel

TL;DR it's probably due to some cmake mess. and i gave up on compiling this; if i really want to, i'll do it in a debian chroot.


> > i tried with your gcc … but it errors out with:
> >
> > $ make
> > [ 1%] Linking ASM executable bs2_default.elf
> > arm-none-eabi-gcc: error: nosys.specs: No such file or directory
>
>
> That file is located here: /gnu/store/…-newlib-arm-none-eabi-4.3.0/arm-none-eabi/lib/nosys.specs


that didn't help:

~/workspace/guix/guix/pre-inst-env guix shell gcc-toolchain cmake make pkg-config -e '(@ (gnu packages embedded2) gcc12-cross-newlib-arm-none-eabi-toolchain)'
cd ~/workspace/bios/pico-serprog
cmake .
COMPILER_PATH=/gnu/store/i9kpjzbagdlpm8bs10gxmm21b271s056-newlib-3.0.0-0.3ccfb40/arm-none-eabi/lib/ LDFLAGS=-B/gnu/store/i9kpjzbagdlpm8bs10gxmm21b271s056-newlib-3.0.0-0.3ccfb40/arm-none-eabi/lib/ make

it leads to the same problem.

but then i tried to compile the pico-sdk subproject as a standalone project, and then it succeeds (but fails with a different error later). therefore i think it's due to some cmake mess that i don't want to get deeper into. so, the rest is just FYI:

git clone https://github.com/raspberrypi/pico-sdk

~/workspace/guix/guix/pre-inst-env guix shell gcc-toolchain cmake make pkg-config -e '(@ (gnu packages embedded2) gcc12-cross-newlib-arm-none-eabi-toolchain)'

cmake .
make

$ make
[  0%] Building ASM object src/rp2_common/boot_stage2/CMakeFiles/bs2_default.dir/compile_time_choice.S.obj
[  0%] Linking ASM executable bs2_default.elf
[  0%] Built target bs2_default
[  0%] Creating directories for 'ELF2UF2Build'
[  0%] No download step for 'ELF2UF2Build'
[  0%] No update step for 'ELF2UF2Build'
[  0%] No patch step for 'ELF2UF2Build'
[  0%] Performing configure step for 'ELF2UF2Build'
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: /gnu/store/3yqw7js9slid5q3d1f5bpbk92vann109-profile/bin/gcc
-- Check for working C compiler: /gnu/store/3yqw7js9slid5q3d1f5bpbk92vann109-profile/bin/gcc - broken
CMake Error at /gnu/store/4bn07jsqk6lxp0qdxv7kkc3krz3afnna-cmake-3.25.1/share/cmake-3.25/Modules/CMakeTestCCompiler.cmake:70 (message):
  The C compiler

    "/gnu/store/3yqw7js9slid5q3d1f5bpbk92vann109-profile/bin/gcc"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: /home/alendvai/workspace/bios/pico-sdk/elf2uf2/CMakeFiles/CMakeScratch/TryCompile-fg3QLY

    Run Build Command(s):/gnu/store/3yqw7js9slid5q3d1f5bpbk92vann109-profile/bin/make -f Makefile cmTC_12bac/fast && make[3]: Entering directory '/home/alendvai/workspace/bios/pico-sdk/elf2uf2/CMakeFiles/CMakeScratch/TryCompile-fg3QLY'
    /gnu/store/3yqw7js9slid5q3d1f5bpbk92vann109-profile/bin/make  -f CMakeFiles/cmTC_12bac.dir/build.make CMakeFiles/cmTC_12bac.dir/build
    make[4]: Entering directory '/home/alendvai/workspace/bios/pico-sdk/elf2uf2/CMakeFiles/CMakeScratch/TryCompile-fg3QLY'
    Building C object CMakeFiles/cmTC_12bac.dir/testCCompiler.c.o
    /gnu/store/3yqw7js9slid5q3d1f5bpbk92vann109-profile/bin/gcc    -o CMakeFiles/cmTC_12bac.dir/testCCompiler.c.o -c /home/alendvai/workspace/bios/pico-sdk/elf2uf2/CMakeFiles/CMakeScratch/TryCompile-fg3QLY/testCCompiler.c
    as: unrecognized option '--64'
    make[4]: *** [CMakeFiles/cmTC_12bac.dir/build.make:78: CMakeFiles/cmTC_12bac.dir/testCCompiler.c.o] Error 1
    make[4]: Leaving directory '/home/alendvai/workspace/bios/pico-sdk/elf2uf2/CMakeFiles/CMakeScratch/TryCompile-fg3QLY'
    make[3]: *** [Makefile:127: cmTC_12bac/fast] Error 2
    make[3]: Leaving directory '/home/alendvai/workspace/bios/pico-sdk/elf2uf2/CMakeFiles/CMakeScratch/TryCompile-fg3QLY'


the root cause of the messy error message above is the following:

as: unrecognized option '--64'

this happens with the host gcc (or due to some misconfiguration the host gcc is used wrongly).

$ file src/rp2_common/boot_stage2/bs2_default.elf
src/rp2_common/boot_stage2/bs2_default.elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped
 
--
• attila lendvai
• PGP: 963F 5D5F 45C7 DFCD 0A39
--
“Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.”
	— Antoine de Saint-Exupery (1900–1944)



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
@ 2024-05-18 12:45 Sergio Pastor Pérez
  2024-05-19 22:06 ` Stefan
  0 siblings, 1 reply; 13+ messages in thread
From: Sergio Pastor Pérez @ 2024-05-18 12:45 UTC (permalink / raw)
  To: stefan-guix; +Cc: guix-devel

Hello. I'm very interested in the code for ZMK provided in this
thread[1].

I've tried it locally and it compiles successfully. Does anyone know if
this is available in a public repository? Or if it has been moved
forward?

Anyone here have tried to do something with ZMK? I'm interested in what
would be the Guix approach for ZMK development.

The blog post of Zephyr[2] was a very interesting read, does anyone know
of other resources regarding this topic?

Have a great day!
Sergio.

[1]: https://lists.gnu.org/archive/html/guix-devel/2023-10/msg00014.html
[2]: https://guix.gnu.org/en/blog/2023/building-toolchains-with-guix


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2024-05-18 12:45 Sergio Pastor Pérez
@ 2024-05-19 22:06 ` Stefan
  2024-05-20  6:59   ` Attila Lendvai
  0 siblings, 1 reply; 13+ messages in thread
From: Stefan @ 2024-05-19 22:06 UTC (permalink / raw)
  To: Sergio Pastor Pérez; +Cc: guix-devel, Attila Lendvai

[-- Attachment #1: Type: text/plain, Size: 1558 bytes --]

Hi Sergio!

> I'm very interested in the code for ZMK provided in this thread[1].
> 
> I've tried it locally and it compiles successfully. 

That's nice to hear!

> Does anyone know if this is available in a public repository? Or if it has been moved forward?

There is no public repository for it. I moved it a bit further. There is now a GCC with picolibc. GCC in general is more self-contained and is completely usable by itself (including paths to specs; Attila, this may solve the issue you were facing). There is no real need for GCC-toolchain packages anymore. However, as some projects invoke programs of Binutils directly and because of locales, there are still GCC-toolchain packages. The Binutils for arm-none-eabi get build separately as well now, as the one from Guix has failing tests (if activated) due to the selected configure flags. GCC is bumped to 13.2.0. Zephyr is updated to 3.5 and ZMK to end of April. There is also more ZMK support for combos, conditional-layers and a bit more.

A problem I figured for arm-none-eabi-g++ is that it always links the generic libstdc++.a, instead of the existing CPU and FPU specific multilib variant from a sub-directory. I'd appreciate any GCC configuration hint to solve this.

> Anyone here have tried to do something with ZMK? I'm interested in what would be the Guix approach for ZMK development.
> 
> The blog post of Zephyr[2] was a very interesting read, does anyone know of other resources regarding this topic?

I'm not aware of anything else regarding ZMK or Zephyr in Guix.


Bye

Stefan

[-- Attachment #2: embedded.tar.gz --]
[-- Type: application/gzip, Size: 29929 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2024-05-19 22:06 ` Stefan
@ 2024-05-20  6:59   ` Attila Lendvai
  2024-05-24 15:48     ` Sergio Pastor Pérez
  0 siblings, 1 reply; 13+ messages in thread
From: Attila Lendvai @ 2024-05-20  6:59 UTC (permalink / raw)
  To: Stefan; +Cc: Sergio Pastor Pérez, guix-devel

hi Stefan,


> > Does anyone know if this is available in a public repository? Or if it has been moved forward?
>
>
> There is no public repository for it.


this is a much more valuable piece of contribution than to allow it to hang in the void indefinitely!

if the only reason that you have not made a channel for this yet is that you've never done it before, then i'd be happy to walk you through it off list.

or i can help you setting up a guix fork where you can push your own signed commits, and guix pull from.

or if you don't mind that the initial commit will be signed by me, then i can even set up a guix channel on codeberg, give you commit access, and then you can push any further changes there.

just let me know.

--
• attila lendvai
• PGP: 963F 5D5F 45C7 DFCD 0A39
--
“Fear is not in the habit of speaking truth; when perfect sincerity is expected, perfect freedom must be allowed; nor has anyone, who is apt to be angry when he hears the truth, any cause to wonder that he does not hear it.”
	— Cornelius Tacitus (ca. 56–117)



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2024-05-20  6:59   ` Attila Lendvai
@ 2024-05-24 15:48     ` Sergio Pastor Pérez
  2024-05-24 17:05       ` Jean-Pierre De Jesus Diaz
  0 siblings, 1 reply; 13+ messages in thread
From: Sergio Pastor Pérez @ 2024-05-24 15:48 UTC (permalink / raw)
  To: Attila Lendvai, Stefan; +Cc: guix-devel

Hi both of you.

I want to echo Attila's sentiments. This is a valuable contribution, and
creating a channel would serve as a central hub for other contributors.

Thanks for sharing, Stefan.

Have nice day.
Sergio.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2024-05-24 15:48     ` Sergio Pastor Pérez
@ 2024-05-24 17:05       ` Jean-Pierre De Jesus Diaz
  2024-05-25 22:20         ` Ricardo Wurmus
  0 siblings, 1 reply; 13+ messages in thread
From: Jean-Pierre De Jesus Diaz @ 2024-05-24 17:05 UTC (permalink / raw)
  To: Sergio Pastor Pérez; +Cc: Attila Lendvai, Stefan, guix-devel

Hello,

Adding to this conversation I have been making a arm-none-eabi
toolchain with Newlib included as the default C standard library like
in the official Arm toolchain but I'm not quite happy with the patches
yet.[1]

I haven't contributed it yet because it has been a bit hard adapting axoloti-*
packages to use a modern toolchain because I'm also intending to remove
the old toolchains in `gnu/packages/embedded.scm' eventually and
instead use the ones in `cross-gcc-toolchain'.

[1]: https://github.com/Foundation-Devices/guix-mirror/compare/master...wip/arm-none-eabi

On Fri, May 24, 2024 at 3:53 PM Sergio Pastor Pérez
<sergio.pastorperez@outlook.es> wrote:
>
> Hi both of you.
>
> I want to echo Attila's sentiments. This is a valuable contribution, and
> creating a channel would serve as a central hub for other contributors.
>
> Thanks for sharing, Stefan.
>
> Have nice day.
> Sergio.
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2024-05-24 17:05       ` Jean-Pierre De Jesus Diaz
@ 2024-05-25 22:20         ` Ricardo Wurmus
  2024-05-27 10:48           ` Jean-Pierre De Jesus Diaz
  0 siblings, 1 reply; 13+ messages in thread
From: Ricardo Wurmus @ 2024-05-25 22:20 UTC (permalink / raw)
  To: Jean-Pierre De Jesus Diaz
  Cc: Sergio Pastor Pérez, Attila Lendvai, Stefan, guix-devel

Jean-Pierre De Jesus Diaz <jean@foundation.xyz> writes:

> I haven't contributed it yet because it has been a bit hard adapting axoloti-*
> packages to use a modern toolchain because I'm also intending to remove
> the old toolchains in `gnu/packages/embedded.scm' eventually and
> instead use the ones in `cross-gcc-toolchain'.

Could you explain why it is difficult to adjust the axoloti/ksoloti
packages?  They only need an arm-none-eabi cross-compiler with newlib.
Since I have axoloti boards here, I could test your changes.

-- 
Ricardo


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: A different way to build GCC to overcome issues, especially with C++ for embedded systems
  2024-05-25 22:20         ` Ricardo Wurmus
@ 2024-05-27 10:48           ` Jean-Pierre De Jesus Diaz
  0 siblings, 0 replies; 13+ messages in thread
From: Jean-Pierre De Jesus Diaz @ 2024-05-27 10:48 UTC (permalink / raw)
  To: Ricardo Wurmus
  Cc: Sergio Pastor Pérez, Attila Lendvai, Stefan, guix-devel

>> I haven't contributed it yet because it has been a bit hard adapting axoloti-*
>> packages to use a modern toolchain because I'm also intending to remove
>> the old toolchains in `gnu/packages/embedded.scm' eventually and
>> instead use the ones in `cross-gcc-toolchain'.
>
>Could you explain why it is difficult to adjust the axoloti/ksoloti
>packages?  They only need an arm-none-eabi cross-compiler with newlib.
>Since I have axoloti boards here, I could test your changes.

I'm mostly having issues with refactoring cross-base to use the gcc
4.9 branch for
ARM to compile one of the axoloti packages that need a 4.9 toolchain
as trying to
use a newer one gave me some errors and the default gcc 4.9 doesn't have all of
the multilib targets that axoloti needs IIRC.

On Sat, May 25, 2024 at 10:20 PM Ricardo Wurmus <rekado@elephly.net> wrote:
>
> Jean-Pierre De Jesus Diaz <jean@foundation.xyz> writes:
>
> > I haven't contributed it yet because it has been a bit hard adapting axoloti-*
> > packages to use a modern toolchain because I'm also intending to remove
> > the old toolchains in `gnu/packages/embedded.scm' eventually and
> > instead use the ones in `cross-gcc-toolchain'.
>
> Could you explain why it is difficult to adjust the axoloti/ksoloti
> packages?  They only need an arm-none-eabi cross-compiler with newlib.
> Since I have axoloti boards here, I could test your changes.
>
> --
> Ricardo


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-05-27 10:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-02 18:55 A different way to build GCC to overcome issues, especially with C++ for embedded systems Stefan
2023-12-21 13:32 ` Attila Lendvai
2023-12-21 14:01   ` Jean-Pierre De Jesus Diaz
2023-12-22  9:56     ` Stefan
2023-12-22  9:33   ` Stefan
2023-12-22 10:56     ` Attila Lendvai
  -- strict thread matches above, loose matches on Subject: below --
2024-05-18 12:45 Sergio Pastor Pérez
2024-05-19 22:06 ` Stefan
2024-05-20  6:59   ` Attila Lendvai
2024-05-24 15:48     ` Sergio Pastor Pérez
2024-05-24 17:05       ` Jean-Pierre De Jesus Diaz
2024-05-25 22:20         ` Ricardo Wurmus
2024-05-27 10:48           ` Jean-Pierre De Jesus Diaz

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).