;;; GNU Guix --- Functional package management for GNU ;;; ;;; Copyright © 2023 Stefan ;;; ;;; 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 . (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 and ;; . ;; The gcc package used by the gnu-build-system is to blame here. ;; This patch is necessary when using --disable-bootstrap. (("#include ") #$(string-join (list "#include " "#if SANITIZER_LINUX" "#include " "#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 . (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 . "--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. ;; ;; page 20 ;; ;; 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 ;; . ;; Got that link in section "Linaro ABE example ;; manifest files for Linux hosted cross ;; toolchains" form ;; . '("--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 ;; . ;; Got that link in section "Linaro ABE example manifest files for ;; Linux hosted cross toolchains" form ;; . #: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)))