From: Stefan <stefan-guix@vodafonemail.de>
To: guix-devel@gnu.org
Subject: A different way to build GCC to overcome issues, especially with C++ for embedded systems
Date: Mon, 2 Oct 2023 20:55:33 +0200 [thread overview]
Message-ID: <0db7f8a7-906f-6552-26e8-93162f6d266e@vodafonemail.de> (raw)
[-- 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/37801
⁴ https://issues.guix.gnu.org/43579
⁵ https://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 '<dN', 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␣ '(< 1 ␣))
(l0 '(<d0)) ; Layer tap-dance for layer 0.
(l1 '(<d1)) ; Layer tap-dance for layer 1.
(l2 '(<d2)) ; Layer tap-dance for layer 2.
(l3 '(<d3)) ; 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 "< {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"))
next reply other threads:[~2023-10-02 19:09 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-02 18:55 Stefan [this message]
2023-12-21 13:32 ` A different way to build GCC to overcome issues, especially with C++ for embedded systems 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0db7f8a7-906f-6552-26e8-93162f6d266e@vodafonemail.de \
--to=stefan-guix@vodafonemail.de \
--cc=guix-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/guix.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.