(define-module (ruther packages embedded)
#:use-module (guix utils)
#:use-module (guix gexp)
#:use-module (guix memoization)
#:use-module (guix packages)
#:use-module (guix download)
#:use-module (guix git-download)
#:use-module (guix build-system trivial)
#:use-module (gnu packages)
#:use-module (gnu packages embedded)
#:use-module (gnu packages flex)
#:use-module (gnu packages cross-base)
#:use-module (gnu packages texinfo)
#:use-module (guix build-system gnu)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix build utils)
#:use-module (gnu packages gcc)
#:export (make-gcc-arm-none-eabi-12.3.rel1
make-newlib-nano-arm-none-eabi-12.3.rel1
make-newlib-arm-none-eabi-12.3.rel1
arm-none-eabi-nano-toolchain-12.3.rel1
arm-none-eabi-toolchain-12.3.rel1))
(define make-newlib-arm-none-eabi
(mlambda ()
(package
(name "newlib")
(version "2.4.0")
(source (origin
(method url-fetch)
(uri (string-append "ftp://sourceware.org/pub/newlib/newlib-"
version ".tar.gz"))
(sha256
(base32
"01i7qllwicf05vsvh39qj7qp5fdifpvvky0x95hjq39mbqiksnsl"))))
(build-system gnu-build-system)
(arguments
`(#:out-of-source? #t
;; The configure flags are identical to the flags used by the "GCC ARM
;; embedded" project.
#:configure-flags '("--target=arm-none-eabi"
"--enable-newlib-io-long-long"
"--enable-newlib-register-fini"
"--disable-newlib-supplied-syscalls"
"--disable-nls")
#:phases
(modify-phases %standard-phases
(add-after 'unpack 'fix-references-to-/bin/sh
(lambda _
(substitute* (find-files "libgloss" "^Makefile\\.in$")
(("/bin/sh") (which "sh")))
#t)))))
(native-inputs
`(("xbinutils" ,(cross-binutils "arm-none-eabi"))
("xgcc" ,(make-gcc-arm-none-eabi-4.9))
("texinfo" ,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 make-newlib-nano-arm-none-eabi
(mlambda ()
(let ((base (make-newlib-arm-none-eabi)))
(package
(inherit base)
(name "newlib-nano")
(arguments
(substitute-keyword-arguments (package-arguments base)
;; The configure flags are identical to the flags used by the "GCC
;; ARM embedded" project. They optimize newlib for use on small
;; embedded systems with limited memory.
((#:configure-flags _)
''("--target=arm-none-eabi"
"--enable-multilib"
"--disable-newlib-supplied-syscalls"
"--enable-newlib-reent-small"
"--disable-newlib-fvwrite-in-streamio"
"--disable-newlib-fseek-optimization"
"--disable-newlib-wide-orient"
"--enable-newlib-nano-malloc"
"--disable-newlib-unbuf-stream-opt"
"--enable-lite-exit"
"--enable-newlib-global-atexit"
"--enable-newlib-nano-formatted-io"
"--disable-nls"))
((#:phases phases)
`(modify-phases ,phases
;; XXX: Most arm toolchains offer both *.a and *_nano.a as
;; newlib and newlib-nano respectively. The headers are
;; usually arm-none-eabi/include/newlib.h for newlib and
;; arm-none-eabi/include/newlib-nano/newlib.h for newlib-nano.
;; We have two different toolchain packages for each which
;; works but is a little strange.
(add-after 'install 'hardlink-newlib
(lambda* (#:key outputs #:allow-other-keys)
(let ((out (assoc-ref outputs "out")))
;; The nano.specs file says that newlib-nano files should
;; end in "_nano.a" instead of just ".a". Note that this
;; applies to all the multilib folders too.
(for-each
(lambda (file)
(link file
(string-append
;; Strip ".a" off the end
(substring file 0 (- (string-length file) 2))
;; Add "_nano.a" onto the end
"_nano.a")))
(find-files
out
"^(libc.a|libg.a|librdimon.a|libstdc\\+\\+.a|\
libsupc\\+\\+.a)$"))
;; newlib.h is usually in this location instead so both
;; newlib and newlib-nano can be in the toolchain at the
;; same time
(mkdir (string-append
out "/arm-none-eabi/include/newlib-nano"))
(symlink
"../newlib.h"
(string-append
out
"/arm-none-eabi/include/newlib-nano/newlib.h")))))))))
(synopsis "Newlib variant for small systems with limited memory")))))
(define make-base-newlib-arm-none-eabi-7-2018-q2-update
;; This is the same commit as used for the 7-2018-q2-update release
;; according to the release.txt.
(mlambda (base)
(let ((commit "3ccfb407af410ba7e54ea0da11ae1e40b554a6f4")
(revision "0"))
(package
(inherit base)
(version (git-version "3.0.0" revision commit))
(source
(origin
(method git-fetch)
(uri (git-reference
(url "http://sourceware.org/git/newlib-cygwin.git")
(commit commit)))
(file-name (git-file-name "newlib" commit))
(sha256
(base32
"1dq23fqrk75g1a4v7569fvnnw5q440zawbxi3w0g05n8jlqsmvcy"))))
(arguments
(substitute-keyword-arguments (package-arguments base)
;; The configure flags are identical to the flags used by the "GCC
;; ARM embedded" project.
((#:configure-flags flags)
`(cons* "--enable-newlib-io-c99-formats"
"--enable-newlib-retargetable-locking"
"--with-headers=yes"
,flags))))
(native-inputs
`(("xbinutils" ,(cross-binutils "arm-none-eabi"))
("xgcc" ,(make-gcc-arm-none-eabi-7-2018-q2-update))
("texinfo" ,texinfo)))))))
(define-public make-gcc-arm-none-eabi-12.3.rel1
(mlambda ()
(let ((base (make-gcc-arm-none-eabi-7-2018-q2-update))
(xgcc-base (cross-gcc "arm-none-eabi"
#:xgcc gcc-12
#:xbinutils (cross-binutils "arm-none-eabi"))))
(package
(inherit base)
(version "12.3.rel1")
(source
(origin
(inherit (package-source xgcc-base))
(method git-fetch)
(uri (git-reference
(url "git://gcc.gnu.org/git/gcc.git")
(commit "0f54a73b998b72f7c8452a63730ec3b16fc47854")))
(sha256
(base32 "0r6q0m3d8g3k3rkmnqjw8aw5fcnsrmywf4ispdkxmk1al3whk1vk"))))
(arguments
(substitute-keyword-arguments (package-arguments base)
((#:phases phases)
#~(modify-phases #$phases
(replace 'expand-version-string
(lambda _
(make-file-writable "gcc/DEV-PHASE")
(with-output-to-file "gcc/DEV-PHASE"
(lambda ()
(display "12.3.rel1")))))))
((#:configure-flags flags)
#~(cons* "--with-multilib-list=aprofile,rmprofile"
"--with-headers=yes"
"--enable-checking=release"
"--with-gnu-as"
"--with-gnu-ld"
(filter
(lambda (flag)
(not (member flag
'("--with-multilib-list=rmprofile"
"--enable-plugins"
"--disable-libffi"))))
#$flags)))))))))
(define make-base-newlib-arm-none-eabi-12.3.rel1
(mlambda (original-base)
(let ((base (make-base-newlib-arm-none-eabi-7-2018-q2-update original-base))
(commit "4c7d0dfec5793cbf5cf3930b91f930479126d8ce")
(revision "0"))
(package
(inherit base)
(version (git-version "4.3.0" revision commit))
(source
(origin
(method git-fetch)
(uri (git-reference
(url "http://sourceware.org/git/newlib-cygwin.git")
(commit commit)))
(sha256
(base32
"0drs9v8avh4y2h5bs0ixjn9x662jzkkikx8z034wgl41dxmn6786"))))
(arguments (substitute-keyword-arguments (package-arguments base)
((#:configure-flags flags)
#~(cons* "--enable-newlib-mb"
"--enable-newlib-reent-check-verify"
"--enable-newlib-register-fini"
#$flags))))))))
(define make-newlib-arm-none-eabi-12.3.rel1
(mlambda ()
(make-base-newlib-arm-none-eabi-12.3.rel1 (make-newlib-arm-none-eabi))))
(define make-newlib-nano-arm-none-eabi-12.3.rel1
(mlambda ()
(make-base-newlib-arm-none-eabi-12.3.rel1 (make-newlib-nano-arm-none-eabi))))
(define make-libstdc++-arm-none-eabi
(mlambda (xgcc newlib)
(let* ((libstdc++ (make-libstdc++ xgcc))
(src (package-source libstdc++)))
(package
(inherit libstdc++)
(source
(origin
(inherit src)
(patches (append
; libstdc++ cannot be linked with since the configure phase
; cannot detect properly the presence of getentropy function.
; The function is inside of a header, but it's not present in the resulting
; newlib. configure will conclude getentropy is present,
; random will use getentropy, and any linking with random will fail.
(if (version>=? (package-version xgcc) "12.0")
(search-patches "newlib-getentropy.patch")
'())
(origin-patches src)))))
(name "libstdc++-arm-none-eabi")
(arguments
(substitute-keyword-arguments (package-arguments libstdc++)
((#:make-flags flags #f)
#~(cons* "CFLAGS=-g -O2 -fdata-sections -ffunction-sections"
"CXXFLAGS=-g -O2 -fdata-sections -ffunction-sections"
(or #$flags '())))
((#:configure-flags _)
``(; This is more of a hack. This option doesn't really seem
; to change what subdir is used eventually, but without it there is
; error: Link tests are not allowed after GCC_NO_EXECUTABLES with
; The 12.3 toolchain
"--with-target-subdir=\".\""
"--target=arm-none-eabi"
"--host=arm-none-eabi"
"--disable-libstdcxx-pch"
"--enable-multilib"
"--with-multilib-list=armv6-m,armv7-m,armv7e-m"
"--disable-shared"
"--disable-tls"
"--disable-plugin"
"--with-newlib"
,(string-append "--libdir="
(assoc-ref %outputs "out")
"/arm-none-eabi/lib")
,(string-append "--with-gxx-include-dir="
(assoc-ref %outputs "out")
"/arm-none-eabi/include/c++")))
((#:strip-directories _ #f)
''("arm-none-eabi/lib"))))
(native-inputs
`(("newlib" ,newlib)
("xgcc" ,xgcc)
,@(package-native-inputs libstdc++)))))))
(define make-arm-none-eabi-toolchain-12.3.rel1
(mlambda ()
((@@ (gnu packages embedded) make-arm-none-eabi-toolchain)
(make-gcc-arm-none-eabi-12.3.rel1)
(make-newlib-arm-none-eabi-12.3.rel1))))
(define make-arm-none-eabi-nano-toolchain-12.3.rel1
(mlambda ()
((@@ (gnu packages embedded) make-arm-none-eabi-toolchain)
(make-gcc-arm-none-eabi-12.3.rel1)
(make-newlib-nano-arm-none-eabi-12.3.rel1))))
(define arm-none-eabi-toolchain-12.3.rel1
(make-arm-none-eabi-toolchain-12.3.rel1))
(define arm-none-eabi-nano-toolchain-12.3.rel1
(make-arm-none-eabi-nano-toolchain-12.3.rel1))