embedded-channel/embedded.scm

1080 lines
55 KiB
Scheme
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; 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 meson)
#: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 git-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 dejagnu)
#:use-module (gnu packages elf)
#:use-module (gnu packages flex)
#:use-module (gnu packages gcc)
#:use-module (gnu packages gdb)
#:use-module (gnu packages multiprecision)
#:use-module (gnu packages perl)
#:use-module (gnu packages pkg-config)
#:use-module (gnu packages texinfo)
#:use-module (ice-9 optargs)
#:use-module ((srfi srfi-1) #:select (second)))
(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))
;; For cross-builds the phase make-dynamic-linker-cache needs to find the
;; native ldconfig executable.
(setenv "PATH" (string-append (getenv "PATH") ":" #$glibc "/bin"))
(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 which has beed used to build glibc itself.
(string-append (getcwd) "/build/gcc"))
(format #t
"environment variable `LD_LIBRARY_PATH' set to `~a'~%"
(getenv "LD_LIBRARY_PATH"))
(for-each
(lambda (include-path-env)
(when (getenv include-path-env)
(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
include-path-env
;; 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 and OBJCPLUS_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.
;; Actually the same problem exists with C_INCLUDE_PATH and
;; OBJC_INCLUDE_PATH. Just by chance it makes no troubles.
(string-join
(remove (lambda (path) (member path paths-to-delete))
(string-split (getenv include-path-env) #\:))
":"))
(format #t
"environment variable `~a' set to `~a'~%"
include-path-env
(getenv include-path-env)))))
'("C_INCLUDE_PATH" "CPLUS_INCLUDE_PATH"
"OBJC_INCLUDE_PATH" "OBJCPLUS_INCLUDE_PATH"))))
(define*-public (make-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 STARTFILE-DIR is a
suffix for LIBC to form the path to startfiles like crt1.o from glibc or crt0.o
from newlib. All default values match for glibc. For newlib set STARTFILE-DIR
to (string-append \"/\" target \"/lib/\"). If LIBC is #f, then $output:lib is
siffixed with STARTFILE-DIR."
;; In case libc is #f, we still need a valid path for substitutions.
(let* ((libc (or libc #~#$output:lib))
(leading-/? (string=? "/" (string-take startfile-dir 1)))
(trailing-/? (string=? "/" (string-take-right startfile-dir 1)))
(startfile-dir (string-append (if leading-/? "" "/")
startfile-dir
(if trailing-/? "" "/"))))
#~(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"))
(substitute* (find-files "gcc/config" "^.+\\.h$")
;; 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.
;;See <https://gcc.gnu.org/bugzilla//show_bug.cgi?id=99476> and
;; <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 necessary when using --disable-bootstrap.
(("#include <limits\\.h>")
#$(string-join (list "#include <limits.h>"
"#if SANITIZER_LINUX"
"#include <linux/limits.h>"
"#endif")
"\n"))))))
(define*-public (make-gcc-configure-flags
#:key
(libc glibc)
(binutils binutils)
(ld-wrapper ld-wrapper)
(kernel-headers
(car (assoc-ref (package-propagated-inputs glibc)
"kernel-headers")))
#:allow-other-keys)
"Make 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 consists of #$gcc/include-c++/… and
;; #$gcc:lib/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 set 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/lib 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. Otherwise the GNU libc may dlopen libgcc_s.so
;; in e.g. pthread_exit but will not find it. 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} "
;; Embed the program search path to the ld-wrapper before the binutils.
"-B" #$ld-wrapper "/bin "
;; Embed the program search path to the binutils.
"-B" #$binutils "/bin")
;; 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, CPLUS_INCLUDE_PATH and
;; OBJC_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, C++, Objective-C and
;; Objective-C++.
"--enable-languages=c,c++,objc,obj-c++"
;; Save space by disabling pre-compiled libstdc++ headers.
"--disable-libstdcxx-pch"
;; Use the zlib package instead of the bundled zlib.
"--with-system-zlib"
;; Avoid parallel linking to not crash on systems with limited memory.
"--enable-link-serialization"
;; Prevent the generation of useless dependency files.
"--disable-dependency-tracking"
;; Prevent the built gcc to build itself again to save time.
#;"--disable-bootstrap"))
(define-public (make-gcc phase-pre-configure configure-flags)
"Make a GCC package using the PHASE-PRE-CONFIGURE and the CONFIGURE-FLAGS in
the build-process."
(package
(name "GCC")
(version "13.2.0")
(source (origin
(method url-fetch)
(uri (string-append "mirror://gnu/gcc/gcc-"
version "/gcc-" version ".tar.xz"))
(sha256
(base32 "1nj3qyswcgc650sl3h0480a171ixp33ca13zl90p61m689jffxg2"))
(patches
(search-patches "gcc-12-strmov-store-file-names.patch"))))
(build-system gnu-build-system)
(outputs '("out" "lib" "debug" #;"include" #;"doc"))
;; The packages zstd and elfutils are needed for LTO support.
(inputs (list elfutils gmp isl mpfr mpc zlib zstd))
;; To generate man pages and info documents, perl and texinfo are needed.
(native-inputs (list perl texinfo))
(arguments
(list
#:tests? #f
#:out-of-source? #t
#:configure-flags configure-flags
#:phases
#~(modify-phases %standard-phases
(add-before 'set-paths 'create-local-prefix-include
;; The include path configured via --with-local-prefix has to be
;; present during build. See <https://bugs.gentoo.org/905118>.
(lambda _
(use-modules ((srfi srfi-1) #:select (find)))
(mkdir-p
(string-append
(string-drop
(find (lambda (flag)
(string-prefix? "--with-local-prefix=" flag))
#$configure-flags)
(string-length "--with-local-prefix="))
"/include"))))
(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 "OBJC_INCLUDE_PATH")
(files (list "include")))
(search-path-specification (variable "OBJCPLUS_INCLUDE_PATH")
(files (list "include")))
(search-path-specification (variable "LIBRARY_PATH")
(files (list "lib")))))
(synopsis "GNU Compiler Collection")
(description "The GNU Compiler Collection includes front ends for C, C++,
Objective-C, Fortran, Ada, Go, and D, as well as libraries for these languages
(libstdc++, …).")
(home-page "https://gcc.gnu.org/")
(license license:gpl3+)))
(define-public GCC
(make-gcc (make-gcc-phase-pre-configure) (make-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
#:key (propagated-inputs '()))
"Make a C-toolchain consisting of the packages GCC, BINUTILS, guix-locpath and
optionally LD-WRAPPER. 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 include paths build-in to preserve a necessary include-order.
The GCC package is expected to know the paths to LD-WRAPPER and BINUTILS and
therefore neither needs to be part of the created c-toolchain. However, some packages my invoke the assembler or linker directly, so these packages still
need to be accessible via the PATH environment variable.
The PROPAGATED_INPUTS argument is an alist of package-names and packages which
take percedence over the usual toolchain packages. This might be needed to
override tools from the toolchain."
(append propagated-inputs
(if ld-wrapper
;; The ld-wrapper has to be in front of binutils.
(list (list "ld-wrapper" ld-wrapper))
'())
(list (list "binutils" binutils)
(list "guix-locpath" guix-locpath)
(list "gcc" gcc))))
(define-public gcc-c-toolchain
(make-c-toolchain GCC binutils ld-wrapper))
(define-public (c-toolchain-input-package c-toolchain name)
"Get the input package named NAME from the C-TOOLCHAIN package list."
(car (assoc-ref c-toolchain name)))
(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 (c-toolchain-input-package 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++/Objective-C development")
(description "This package provides a complete GCC toolchain for
C/C++/Objective-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 GCC-toolchain
(make-gcc-toolchain-package gcc-c-toolchain))
(define*-public (make-binutils #:optional target)
(package-with-c-toolchain
(package
(name (string-append "Binutils" (if target (string-append "-" target)
"")))
(version "2.42")
(source
(origin
(method url-fetch)
(uri (string-append "mirror://gnu/binutils/binutils-"
version ".tar.bz2"))
(sha256
(base32 "04mgvzgsdcksm7cm0qs8j4ljb562asqdkhjfrmr4q1m5pl78am5a"))
;; The binutils-mingw-w64-timestamp.patch can't be applied.
(patches (search-patches #;"binutils-mingw-w64-timestamp.patch"
"binutils-mingw-w64-deterministic.patch"))))
(build-system gnu-build-system)
(arguments
(list
#:out-of-source? #t ; Recommended in binutils/README.
#:phases
#~(modify-phases %standard-phases
(add-after 'unpack 'fix-testsuite
(lambda _
;; The configure flag --enable-deterministic-archives makes the
;; tests "replacing non-deterministic member" and
;; "replacing SOURCE_DATE_EPOCH deterministic member" fail due to
;; unexpected output. To fix the relevant parts we need to
;; temporarily concatenate two lines to limit the substitution.
(substitute* "binutils/testsuite/binutils-all/ar.exp"
(("^( set got \\[binutils_run \\$AR \"ru \\$archive \\$older_objfile\"\\])\n"
_ first-line-without-newline)
first-line-without-newline))
;; Now do the actually needed substitutions.
(substitute* "binutils/testsuite/binutils-all/ar.exp"
;; Correct the output to be a warning instead of being empty.
(("^( set got \\[binutils_run \\$AR \"ru \\$archive \\$older_objfile\"\\]) .*$"
_ first-line-without-newline)
(string-append
first-line-without-newline
"\n if ![string match \"*`u' modifier ignored since `D' is the default*\" $got] {\n"))
;; With --enable-deterministic-archives ar takes the older
;; instead of the newer object file in the test
;; "replacing non-deterministic member".
(("^ # set older_length ")
" set older_length ")
(("(\\$\\{?)newer_length" _ dereference)
(string-append dereference "older_length")))
(substitute* "gold/testsuite/Makefile.in"
;; Embed the runtime search paths to #$zlib/lib and
;; #$zstd:lib/lib.
(("_unittest_LDFLAGS =")
(string-append "_unittest_LDFLAGS ="
" -Wl,--rpath=" #$zlib "/lib"
" -Wl,--rpath=" #$zstd:lib "/lib"))))))
#:configure-flags
#~(quote
#$(cons*
;; Speed up the build.
"--disable-dependency-tracking"
;; Disable separate-code as the testsuite unveils Arm bugs in ld:
;; FAIL: R_ARM_THM_JUMP24 Relocation veneers: Short 1
;; FAIL: Cortex-A8 erratum fix, headers
;; FAIL: Cortex-A8 erratum fix, relocate bl.w to PLT
;; FAIL: Thumb only PLT and GOT
;; FAIL: Thumb only PLT and GOT LSB Symbol
"--disable-separate-code"
;; Build a 64-bit bfd lib also on 32-bit hosts.
"--enable-64-bit-bfd"
;; Enable compressed debug sections with all supported formats.
"--enable-compressed-debug-sections=all"
;; Ensure that generated archives will be reproducable.
"--enable-deterministic-archives"
;; Build the faster gold linker.
"--enable-gold"
;; Build gprofng.
"--enable-gprofng"
;; Install the build libraries and headers.
"--enable-install-libbfd"
;; Enable the use of DT_RUNPATH by default for elf targets.
"--enable-new-dtags"
;; Enable support for plugins.
"--enable-plugins"
;; Build shared libraries.
"--enable-shared"
;; Enable multi-threaded linking in gold.
"--enable-threads"
;; Enforce an empty LIB_PATH, a colon is the documented method,
;; to avoid the usual default of /lib:/usr/lib:/usr/local/lib.
"--with-lib-path=:"
;; All paths to --with-… options are relative to the sysroot. As
;; store paths are absolute, the sysroot needs to be /. This is
;; also needed to make cross ld find absolute DT_RUNPATH entries
;; when searching for needed libraries, which are only searched
;; relative to the configured sysroot directory or not at all.
;; See <http://sourceware.org/ml/binutils/2013-05/msg00312.html>.
"--with-sysroot=/"
;; Use the zlib package instead of the bundled zlib.
"--with-system-zlib"
;; Support zstd compressed debug sections.
"--with-zstd"
(if target
(list
;; Build for a specific target. Actually the configure option
;; --enable-targets=all could build executables usable for
;; any target, but this is not yet supported by the assembler.
(string-append "--target=" target))
'())))))
(native-inputs (list perl pkg-config texinfo dejagnu))
(inputs (list zlib (list zstd "lib")))
(synopsis "The GNU binary utilities ld, as, gold and others")
(description
"The GNU Binutils are a collection of binary tools. The main ones are
@itemize
@item ld - the GNU linker
@item as - the GNU assempler
@item gold - a new, faster, elf only linker.
@end itemize
But they also include:
@itemize
@item addr2line - Converts addresses into filenames and line numbers.
@item ar - A utility for creating, modifying and extracting from archives.
@item c++filt - Filter to demangle encoded C++ symbols.
@item dlltool - Creates files for building and using DLLs.
@item elfedit - Allows alteration of ELF format files.
@item gprof - Displays profiling information.
@item gprofng - Collects and displays application performance data.
@item nlmconv - Converts object code into an NLM.
@item nm - Lists symbols from object files.
@item objcopy - Copies and translates object files.
@item objdump - Displays information from object files.
@item ranlib - Generates an index to the contents of an archive.
@item readelf - Displays information from any ELF format object file.
@item size - Lists the section sizes of an object or archive file.
@item strings - Lists printable strings from files.
@item strip - Discards symbols.
@item windmc - A Windows compatible message compiler.
@item windres - A compiler for Windows resource files.
@end itemize
As well as some libraries:
@itemize
@item libbfd - A library for manipulating binary files in a variety of different formats.
@item libctf - A library for manipulating the CTF debug format.
@item libopcodes - A library for assembling and disassembling a variety of different assembler languages.
@item libsframe - A library for manipulating the SFRAME debug format.
@end itemize
Most of these programs use BFD, the Binary File Descriptor library, to do
low-level manipulation. Many of them also use the opcodes library to assemble
and disassemble machine instructions.")
(license license:gpl3+)
(home-page "https://www.gnu.org/software/binutils/"))
gcc-c-toolchain))
(define-public Binutils-arm-none-eabi
(make-binutils "arm-none-eabi"))
(define*-public (make-gcc-cross-sans-libc-configure-flags #:key
target
(configure-flags '())
binutils
#:allow-other-keys)
"Make configure-flags to build a GCC cross-compiler for TARGET without a
libc, which can be used to build a C-library as newlib or picolibc. Additional
CONFIGURE-FLAGS can be used for target or C-library specific GCC options."
#~(cons*
(string-append "--target=" #$target)
;; All paths to --with-… options are relative to the sysroot. As store
;; paths are absolute and to get --without-headers working properly, the
;; --with-sysroot option must not be used.
;; The first set of include paths consists of #$gcc/include-c++/… and
;; #$gcc:lib/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 set of include paths is normally for a libc, which usually needs a
;; fourth set of include paths for kernel and system headers, which we do
;; not want.
;; Using --without-headers there will be no further sets of include paths.
"--without-headers"
(string-append
"--with-specs="
;; Without a libc we have to ensure to not link missing files. The option
;; -nostlib removes -lgcc as well, which we want to preserve. Without the
;; startfiles there is no _start entry function, and the linker prints a
;; warning. To suppress this warning we use main instead as entry.
"-nolibc -nostartfiles -Wl,-entry=main "
;; Ensure that the built GCC will find the right executables from
;; Binutils. Unfortunately GCC does not search for a target-prefixed
;; assembler but just 'as'. Therefore we need to embed a proper path to
;; the cross Binutils. Luckily collet2 also searches for the linker at
;; this path before searching for a target-prefixed 'ld' somewhere else.
"-B" #$binutils "/" #$target "/bin")
;; Prevent the generation of useless dependency files.
"--disable-dependency-tracking"
;; The libstdc++ requires a libc for a hosted build, which we do not have.
"--disable-hosted-libstdcxx"
;; Save space by disabling pre-compiled libstdc++ headers.
"--disable-libstdcxx-pch"
;; Disable anything not needed to build a libc.
"--disable-decimal-float"
"--disable-libatomic"
"--disable-libgomp"
"--disable-libitm"
"--disable-libmpx"
"--disable-libmudflap"
"--disable-libquadmath"
"--disable-libsanitizer"
"--disable-libssp"
"--disable-libvtv"
"--disable-shared"
"--disable-threads"
;; Disable all language frontends except for C and C++.
"--enable-languages=c,c++"
;; Avoid parallel linking to not crash on systems with limited memory.
"--enable-link-serialization"
;; Enable support for thread-local-storage.
"--enable-tls"
;; Use the zlib package instead of the zlib bundled with gcc.
"--with-system-zlib"
'#$configure-flags))
(define*-public (make-cross-gcc gcc cross-binutils #:key
cross-libc
package-name-suffix)
"Make a GCC cross-compiler package based on a modified but still native GCC
package using the CROSS-BINUTILS and optional CROSS-LIBC packages. If a
CROSS-LIBC is given, then its name, which usually ends with the target name, is
appended to the GCC package name, else the string in PACKAGE-NAME-SUFFIX
is appendneeded and usually containing the target name."
(package
(inherit gcc)
(name (string-append (package-name gcc)
"-cross-"
(if cross-libc (package-name cross-libc)
package-name-suffix)))
(inputs '())
(native-inputs (append (list (list "cross-binutils" cross-binutils))
(package-inputs gcc)))))
(define*-public (make-cross-c-toolchain target
gcc
make-gcc
make-gcc-cross-configure-flags
#:key
(configure-flags '())
cross-libc
(binutils binutils)
(propagated-inputs '()))
"Make a C-toolchain targeting TARGET consisting of a cross-compiler,
cross-compiled BINUTILS, and optionally a C-library.
The cross-compiler will be build with another toolchain using the given host GCC
and BINUTILS. The functions MAKE-GCC and MAKE-GCC-CROSS-CONFIGURE-FLAGS are
used to create a GCC cross-compiler package using an optional C-library package
CROSS-LIBC. 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 additional CONFIGURE-FLAGS get passed to the MAKE-GCC-CROSS-CONFIGURE-FLAGS
function to add target or C-library specific GCC options.
The PROPAGATED_INPUTS argument is an alist of package-names and packages which
take percedence over the usual toolchain packages. This might be needed to
override tools from the toolchain."
(let* ((c-toolchain (make-c-toolchain gcc binutils ld-wrapper))
(cross-binutils (make-binutils target))
;; The startfile-dir is relative to #$cross-libc or #$cross-gcc:lib.
;; By default picolibc has no target specific directory and in newlib
;; we use a snippet to remove it.
(startfile-dir (if cross-libc
;; This is relative to #$cross-libc.
"/lib"
;; This is relative to #$cross-gcc:lib.
(string-append "/lib/gcc/" target)))
(cross-gcc
(package-with-c-toolchain
(make-cross-gcc (make-gcc (make-gcc-phase-pre-configure
#:libc cross-libc
#:startfile-dir startfile-dir)
(make-gcc-cross-configure-flags
#:target target
#:configure-flags configure-flags
#:binutils cross-binutils
#:libc cross-libc))
cross-binutils
#:cross-libc cross-libc
#:package-name-suffix
(string-append "sans-libc-" target))
c-toolchain)))
(make-c-toolchain cross-gcc cross-binutils
#:propagated-inputs propagated-inputs)))
(define*-public (make-picolibc target c-toolchain #:key (configure-flags '()))
"Make a picolibc package for TARGET with the given CONFIGURE-FLAGS, using the
given C-TOOLCHAIN."
(package-with-c-toolchain
(package
(name (string-append "picolibc-" target))
(version "1.8.6")
(source
(origin
(method git-fetch)
(uri (git-reference (url "https://keithp.com/cgit/picolibc.git")
(commit version)))
(sha256
(base32 "16y5xgz07hrlmc8abc1vqdcf953xr4qn6jaz1z6gyf71iazgwvz5"))))
(build-system meson-build-system)
(arguments
(list #:configure-flags
#~(cons* "--cross-file"
(string-append (getcwd)
"/source/scripts/cross-" #$target ".txt")
"-Dspecsdir=lib"
"-Dtests=true"
'#$configure-flags)
#:build-type "release"
;; As we do not use Guix' cross-build facilities to build picolibc,
;; the meson-build-system thinks (inherited from gnu-build-system)
;; that it is doing a native build and uses strip instead of the
;; target-prefixed strip. As a workaround we could add the target
;; specific bin directory of Binutils to PATH. Or we skip the strip
;; phase.
#:strip-binaries? #f
#:phases
#~(modify-phases %standard-phases
(add-after 'unpack 'remove-paths-from-specs
(lambda _
(substitute* "picolibc.specs.in"
;; As we will get the include paths of GCC right, there is
;; no need to use the -isystem option for picolibc. Doing
;; so breaks the include-next chain of libstdc++. The
;; picolibc author provided a GCC patch to crosstool-ng to
;; mitigate the negative effect of using -isystem.
;; <https://keithp.com/picolibc/picolibc-2021-notes.pdf>
;; page 20
;; <https://github.com/crosstool-ng/crosstool-ng/commit/83029d75705e029ba17494d4132e1c01294ce85e>
;; The substitute offers additional --picolibc-prefix and
;; --picolibc-buildtype options, which we cannot support.
(("@SPECS_ISYSTEM@ ") "")
;; The substitute for @SPECS_LIBPATH@ offers additional
;; --picolibc-prefix and --picolibc-buildtype options,
;; which we cannot support. As we will get the library
;; search paths of GCC right, there is no need to specify
;; a library search path in the picolibc.specs file.
(("@SPECS_LIBPATH@") "")
;; The substitute for @PICOLIBC_LD@ offers additional
;; --picolibc-prefix and --picolibc-buildtype options,
;; which we cannot support. Instead we change it to the
;; absolute path of the picolibc.ld linker script. The
;; used -T option depends on preceeding -L options. If
;; we were prepending an -L option in @SPECS_LIBPATH@,
;; then that path would get precedence over multilib
;; search paths and wrong libraries would be linked.
(("@PICOLIBC_LD@")
(string-append #$output "/lib/@PICOLIBC_LD@"))
;; The substitute for @SPECS_STARTFILE@ offers additional
;; --picolibc-prefix and --picolibc-buildtype options,
;; which we cannot support. As we set the build-in
;; spec string *startfile_prefix_spec of GCC right, we do
;; not need to add a path. But we need to keep the
;; startfile itself and the picolibc specific --crt0
;; option to select a different one.
(("@SPECS_STARTFILE@")
"%{-crt0=*:crt0-%*%O%s; :crt0%O%s}"))))
;; The built picolibc has no shared objects with DT_RUNPATH
;; entries to shrink, and this phase fails, probably because the
;; produced elf-files are not native ones. So we simply delete
;; the shrink-runpath phase.
(delete 'shrink-runpath))))
(native-inputs (list texinfo perl))
(home-page "https://www.sourceware.org/newlib/")
(synopsis "C Libraries for smaller embedded systems")
(description "Picolibc is a set of standard C libraries, both libc and
libm, designed for smaller embedded systems with limited ROM and RAM.")
(license (license:non-copyleft
"file://COPYING.picolibc")))
c-toolchain))
(define*-public (make-newlib target
c-toolchain
#:key
(configure-flags
;; The configure-flags are inspired by
;; newlib_configure found in
;; <https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.2.rel1/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>.
'("--disable-dependency-tracking"
"--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")))
"Make a newlib package for TARGET with the given CONFIGURE-FLAGS, using the
given C-TOOLCHAIN."
(package-with-c-toolchain
(package
(name (string-append "newlib-" target))
(version "4.4.0")
(source
(origin
(method url-fetch)
(uri "ftp://sourceware.org/pub/newlib/newlib-4.4.0.20231231.tar.gz")
(sha256
(base32 "04rg1wqwdvxf74pjiml1h1jx7dp4w2gr8s6dmzgm22dzw4wnl5hc"))))
(build-system gnu-build-system)
(arguments
(list #:out-of-source? #t
#:configure-flags
#~(quote #$(cons* (string-append "--target=" target)
configure-flags))
#:phases
#~(modify-phases %standard-phases
(add-before 'configure 'remove-target-directory
(lambda _
;; There is no need to have an intermediate target directory
;; before the include and lib directories of newlib. To
;; keep the flags in make-gcc-cross-configure-flags common
;; for newlib and picolibc, and as the mesa-build-system
;; used by picolib prevents to set a prefix containing a
;; target folder, we remove the target folder from the
;; newlib output. Alternatively we could patch the target
;; directory into the meoson.build file of picolibc.
;; However, to keep the configure-flags for GCC simple and
;; close to the flags for the native GCC, we patch newlib.
(substitute* "configure"
(("^tooldir='\\$\\{exec_prefix\\}'/.*$")
"tooldir='${exec_prefix}'\n"))))
(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. They must all be fixed.
(("/bin/sh") (which "sh")))))
(add-after 'install 'remove-nano
(lambda _
(map delete-file (find-files #$output "nano")))))))
(native-inputs (list texinfo GCC))
(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 (list license:gpl2+
license:lgpl2.1+
license:gpl3+
license:lgpl3
(license:non-copyleft "file://COPYING.LIBGLOSS")
(license:non-copyleft "file://COPYING.NEWLIB"))))
c-toolchain))
(define-public (make-newlib-nano target c-toolchain)
"Make a newlib-nano package for TARGET using the given C-TOOLCHAIN."
(package
(inherit (make-newlib
target
c-toolchain
;; The configure-flags are inspired by newlib_configure found in
;; <https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.2.rel1/manifest/arm-gnu-toolchain-arm-none-eabi-nano-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
'("--disable-dependency-tracking"
"--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")))
(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, not ready")))
(define-public (make-cross-c-library make-cross-libc target configure-flags)
"Make a C-library package for TARGET using the MAKE-CROSS-LIBC function and a
GCC cross c-toolchain, which is build with additional CONFIGURE-FLAGS."
(let ((c-toolchain-sans-libc
(make-cross-c-toolchain target
GCC
make-gcc
make-gcc-cross-sans-libc-configure-flags
#:configure-flags configure-flags)))
(make-cross-libc target c-toolchain-sans-libc)))
(define*-public (make-gcc-cross-configure-flags #:key
target
(configure-flags '())
binutils
libc
#:allow-other-keys)
"Modify configure-flags to build a GCC cross-compiler for TARGET using LIBC.
Additional CONFIGURE-FLAGS can be used for target or C-library specific GCC options."
#~(cons*
(string-append "--target=" #$target)
;; All paths to --with-… options are relative to the sysroot. As store
;; paths are absolute, the sysroot needs to be set to /.
"--with-sysroot=/"
;; The first set of include paths consists 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 set 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 or picolibc for bare-metal does not require kernel-headers.
(string-append
"--with-native-system-header-dir=" #$libc "/include")
(string-append
"--with-specs="
;; Embed the link-time search path to libstdc++ and other C++ libraries.
;; TODO: Why is this needed? GCC should find libstdc++ out of the box.
"%x{-L" #$output "/" #$target "/lib/} "
;; TODO: This seems to be unneeded, probably because of the -B option.
;; Embed the link-time search path to libc.
;"%x{-L" #$libc "/lib} "
;; Embed the specs file (and startfile) search path to #$libc/lib.
"-B" #$libc "/lib "
;; Ensure that the built GCC will find the right executables from
;; Binutils. Unfortunately GCC does not search for a target-prefixed
;; assembler but just 'as'. Therefore we need to embed a proper path to
;; the cross Binutils. Luckily collet2 also searches for the linker at
;; this path before searching for a target-prefixed 'ld' somewhere else.
"-B" #$binutils "/" #$target "/bin")
;; Prevent the generation of useless dependency files.
"--disable-dependency-tracking"
;; Save space by disabling pre-compiled libstdc++ headers.
"--disable-libstdcxx-pch"
;; Disable all language frontends except for C, C++. It seems not to be
;; possible to configure libobjc with newlib or picolibc, therefore
;; Objective-C and Objective-C++ are not supported.
"--enable-languages=c,c++"
;; Avoid parallel linking to not crash on systems with limited memory.
"--enable-link-serialization"
;; Build multiple versions of target libraries.
"--enable-multilib"
;; 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, CPLUS_INCLUDE_PATH and
;; OBJC_INCLUDE_PATH, OBJCPLUS_INCLUDE_PATH.
"--with-gxx-include-dir=$(prefix)/include-c++"
;; Use the zlib package instead of the zlib bundled with gcc.
"--with-system-zlib"
'#$configure-flags))
(define*-public (make-gcc-cross-libc-c-toolchain make-cross-libc
target
#:key
(with-multilib-list "default")
(configure-flags '()))
"Make a cross GCC package for TARGET using a C-library build with
MAKE-CROSS-LIBC. Both the cross GCC and the C-library can be build
WITH-MULTILIB-LIST and the cross GCC with additional CONFIGURE-FLAGS to match
needs of the C-library."
(let* ((with-multilib-list
(string-append "--with-multilib-list=" with-multilib-list))
(cross-libc (make-cross-c-library make-cross-libc
target
(list with-multilib-list))))
(make-cross-c-toolchain target
GCC
make-gcc
make-gcc-cross-configure-flags
#:configure-flags
(cons* with-multilib-list
configure-flags)
#:cross-libc cross-libc)))
(define*-public (make-gcc-cross-libc-arm-none-eabi-c-toolchain
make-cross-libc
#:key (configure-flags '()))
"Make a cross GCC package for arm-none-eabi using a C-library build with
MAKE-CROSS-LIBC. Both the cross GCC and the C-library are build using
'--with-multilib-list=aprofile,rmprofile' and the GCC can be build with
additional CONFIGURE-FLAGS to match needs of the C-library."
(make-gcc-cross-libc-c-toolchain make-cross-libc
"arm-none-eabi"
#:with-multilib-list "aprofile,rmprofile"
#:configure-flags configure-flags))
(define-public GCC-cross-picolibc-arm-none-eabi-c-toolchain
(make-gcc-cross-libc-arm-none-eabi-c-toolchain
make-picolibc
#:configure-flags
'(;; Disable the GCC stack smashing protection, as picolibc has its own. If
;; libssp is enabled, then there will be include/ssp inside GCC as well as
;; inside picolibc and the ones from GCC will be inluded. In the end there
;; would be an error from the preprocessor tha ssp.h is not found.
"--disable-libssp"
;; Ensure that libstdc++ is using the standard C stdio functions from
;; picolibc instead of POSIX implementations.
"--enable-cstdio=stdio_pure"
;; Enable thread-local-storage in GCC, which is used by picolibc.
"--enable-tls"
;; The picolibc implements __eprintf as newlib does.
"--with-newlib")))
(define-public (make-gcc-cross-newlib-arm-none-eabi-c-toolchain
make-newlib-variant)
"Make a GCC cross-compiler c-toolchain with a variont of newlib, which is
build with the MAKE-NEWLIB-VARIANT function."
(make-gcc-cross-libc-arm-none-eabi-c-toolchain
make-newlib-variant
#:configure-flags
'(;; Disable the GCC stack smashing protection, as newlib has its own.
"--disable-libssp"
;; GCC requires __aeabi_read_tp for thread-local-storage, which is not
;; implemented by newlib, contrary to picolibc.
"--disable-tls"
;; Ensure that GCC optimizes for newlib regarding __eprintf.
"--with-newlib")))
(define-public GCC-cross-newlib-arm-none-eabi-c-toolchain
(make-gcc-cross-newlib-arm-none-eabi-c-toolchain make-newlib))
(define-public GCC-cross-newlib-nano-arm-none-eabi-c-toolchain
(make-gcc-cross-newlib-arm-none-eabi-c-toolchain make-newlib-nano))
(define-public GCC-cross-picolibc-arm-none-eabi-toolchain
(package
(inherit (make-gcc-toolchain-package
GCC-cross-picolibc-arm-none-eabi-c-toolchain))
(synopsis
"Complete GCC toolchain for C/C++ cross development on ARM Cortex-A and
Cortex-M micro-controllers with picolibc")
(description "This package provides a complete GCC toolchain for C/C++ cross
development on ARM Cortex-A, Cortex-R and Cortex-M micro-controllers. This
includes GCC, picolibc and Binutils. GCC is the GNU Compiler Collection.")))
(define-public GCC-cross-newlib-arm-none-eabi-toolchain
(package
(inherit (make-gcc-toolchain-package
GCC-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, Cortex-R and Cortex-M micro-controllers. This
includes GCC, newlib and Binutils. GCC is the GNU Compiler Collection.")))
(define-public GCC-cross-newlib-nano-arm-none-eabi-toolchain
(package
(inherit (make-gcc-toolchain-package
GCC-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, Cortex-R and Cortex-M micro-controllers. This
includes GCC, newlib-nano and Binutils. GCC is the GNU Compiler Collection.")))
(define-public GCC-cross-picolibc-arm-none-eabi
(c-toolchain-input-package GCC-cross-picolibc-arm-none-eabi-c-toolchain
"gcc"))
(define-public GCC-cross-newlib-arm-none-eabi
(c-toolchain-input-package GCC-cross-newlib-arm-none-eabi-c-toolchain
"gcc"))
(define-public GCC-cross-newlib-nano-arm-none-eabi
(c-toolchain-input-package GCC-cross-newlib-nano-arm-none-eabi-c-toolchain
"gcc"))
(define-public (c-toolchain gcc-toolchain-package)
"Make a c-toolchain from a GCC-TOOLCHAIN-PACKAGE, a union of GCC, Binutils and
possibly more packages. The result can be used by the transformation function
'package-with-c-toolchain'."
(list (list "toolchain" gcc-toolchain-package)))