aboutsummaryrefslogtreecommitdiff
path: root/distro
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2012-09-11 17:36:21 +0200
committerLudovic Courtès <ludo@gnu.org>2012-09-11 22:08:55 +0200
commit321b099643cd4aae4481e7c9fb23b7c3fd3235cb (patch)
tree7c87d3075b3097cf947ab107e9cf6f73254f8e8e /distro
parentbe13fbfa83dd3e3c7a7a3d09f9c520940eb350d4 (diff)
downloadguix-321b099643cd4aae4481e7c9fb23b7c3fd3235cb.tar.gz
guix-321b099643cd4aae4481e7c9fb23b7c3fd3235cb.zip
distro: Bootstrap via a cross-toolchain.
This allows the final toolchain to be completely independent of %BOOTSTRAP-INPUTS. * distro/base.scm (glibc-dynamic-linker): New procedure. (gcc-4.7): Remove #:path-exclusions argument. Check whether LIBC is #f before using it. (glibc): Remove "libc_cv_as_needed" hack. Patch `Makeconfig' to remove `-lgcc_s'. (nix-system->gnu-triplet, boot-triplet): New variables. (binutils-boot0): Turn into a cross-Binutils targeting (boot-triplet SYSTEM). (gcc-boot0): Likewise. Add configure options to make a smaller build. Remove "binutils-source" from the input, and use BINUTILS-BOOT0 instead. (glibc-final): Cross-build using GCC-BOOT0 and BINUTILS-BOOT0. (gcc-boot0-wrapped): New variable. (%boot2-inputs): Use it. (m4-boot2, gmp-boot2, mpfr-boot2, mpc-boot2): Remove. (binutils-final): New variable. (gcc-final): Turn into a joint build with GMP/MPFR/MPC. Use BINUTILS-FINAL. (%boot3-inputs): Adjust accordingly. (%boot4-inputs): Remove. (%final-inputs): Use %BOOT3-INPUTS.
Diffstat (limited to 'distro')
-rw-r--r--distro/base.scm397
1 files changed, 245 insertions, 152 deletions
diff --git a/distro/base.scm b/distro/base.scm
index 1c5a3d9085..c72a496c2a 100644
--- a/distro/base.scm
+++ b/distro/base.scm
@@ -21,6 +21,7 @@
#:use-module (guix packages)
#:use-module (guix http)
#:use-module (guix build-system gnu)
+ #:use-module (guix build-system trivial)
#:use-module (guix utils)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
@@ -647,6 +648,12 @@ BFD (Binary File Descriptor) library, `gprof', `nm', `strip', etc.")
(license "GPLv3+")
(home-page "http://www.gnu.org/software/binutils/")))
+(define (glibc-dynamic-linker system)
+ "Return the name of Glibc's dynamic linker for SYSTEM."
+ (if (string=? system "x86_64-linux")
+ "ld-linux-x86-64.so.2"
+ (error "dynamic linker name not known for this system" system)))
+
(define-public gcc-4.7
(let ((stripped? #t)) ; TODO: make this a parameter
(package
@@ -671,26 +678,23 @@ BFD (Binary File Descriptor) library, `gprof', `nm', `strip', etc.")
`("--enable-plugin"
"--enable-languages=c,c++"
"--disable-multilib"
- ,(string-append "--with-native-system-header-dir="
- (assoc-ref %build-inputs "libc")
- "/include"))
+ ,(let ((libc (assoc-ref %build-inputs "libc")))
+ (if libc
+ (string-append "--with-native-system-header-dir=" libc
+ "/include")
+ "--without-headers")))
#:make-flags
(let ((libc (assoc-ref %build-inputs "libc")))
- `(,(string-append "LDFLAGS_FOR_BUILD="
- "-L" libc "/lib "
- "-Wl,-dynamic-linker "
- "-Wl," libc "/lib/ld-linux-x86-64.so.2")
+ `(,@(if libc
+ (list (string-append "LDFLAGS_FOR_BUILD="
+ "-L" libc "/lib "
+ "-Wl,-dynamic-linker "
+ "-Wl," libc
+ "/lib/ld-linux-x86-64.so.2"))
+ '())
,(string-append "BOOT_CFLAGS=-O2 "
,(if stripped? "-g0" "-g"))))
- ;; Exclude libc from $LIBRARY_PATH since the compiler being used
- ;; should know where its libc is, and to avoid linking build tools
- ;; like `genhooks' against the wrong libc (for instance, when
- ;; building a gcc-for-glibc-2.16 with a gcc-for-glibc-2.13,
- ;; `genhooks' could end up being linked with glibc-2.16 but using
- ;; crt*.o from glibc-2.13.)
- #:path-exclusions '(("LIBRARY_PATH" "libc"))
-
#:tests? #f
#:phases
(alist-cons-before
@@ -698,23 +702,29 @@ BFD (Binary File Descriptor) library, `gprof', `nm', `strip', etc.")
(lambda* (#:key inputs outputs #:allow-other-keys)
(let ((out (assoc-ref outputs "out"))
(libc (assoc-ref inputs "libc")))
- ;; Fix the dynamic linker's file name.
- (substitute* "gcc/config/i386/linux64.h"
- (("#define GLIBC_DYNAMIC_LINKER([^ ]*).*$" _ suffix)
- (format #f "#define GLIBC_DYNAMIC_LINKER~a \"~a\"~%"
- suffix
- (string-append libc "/lib/ld-linux-x86-64.so.2"))))
-
- ;; Tell where to find libstdc++, libc, and `?crt*.o', except
- ;; `crt{begin,end}.o', which come with GCC.
- (substitute* ("gcc/config/gnu-user.h"
- "gcc/config/i386/gnu-user.h"
- "gcc/config/i386/gnu-user64.h")
- (("#define LIB_SPEC (.*)$" _ suffix)
- (format #f "#define LIB_SPEC \"-L~a/lib -rpath=~a/lib64 -rpath=~a/lib \" ~a~%"
- libc out out suffix))
- (("([^ ]*)crt([^\\.])\\.o" _ prefix suffix)
- (string-append libc "/lib/" prefix "crt" suffix ".o")))
+ (when libc
+ ;; The following is not performed for `--without-headers'
+ ;; cross-compiler builds.
+
+ ;; Fix the dynamic linker's file name.
+ (substitute* "gcc/config/i386/linux64.h"
+ (("#define GLIBC_DYNAMIC_LINKER([^ ]*).*$" _ suffix)
+ (format #f "#define GLIBC_DYNAMIC_LINKER~a \"~a\"~%"
+ suffix
+ (string-append libc "/lib/ld-linux-x86-64.so.2"))))
+
+ ;; Tell where to find libstdc++, libc, and `?crt*.o', except
+ ;; `crt{begin,end}.o', which come with GCC.
+ ;; XXX: For crt*.o, use `STANDARD_STARTFILE_PREFIX' instead? See
+ ;; <http://www.linuxfromscratch.org/lfs/view/stable/chapter05/gcc-pass1.html>.
+ (substitute* ("gcc/config/gnu-user.h"
+ "gcc/config/i386/gnu-user.h"
+ "gcc/config/i386/gnu-user64.h")
+ (("#define LIB_SPEC (.*)$" _ suffix)
+ (format #f "#define LIB_SPEC \"-L~a/lib -rpath=~a/lib64 -rpath=~a/lib \" ~a~%"
+ libc out out suffix))
+ (("([^ ]*)crt([^\\.])\\.o" _ prefix suffix)
+ (string-append libc "/lib/" prefix "crt" suffix ".o"))))
;; Don't retain a dependency on the build-time sed.
(substitute* "fixincludes/fixincl.x"
@@ -1229,10 +1239,6 @@ call interface, and powerful string processing.")
;; GNU libc for details.
"--enable-kernel=2.6.30"
- ;; To avoid linking with -lgcc_s (dynamic link) so the libc does
- ;; not depend on its compiler store path.
- "libc_cv_as_needed=no"
-
;; XXX: Work around "undefined reference to `__stack_chk_guard'".
"libc_cv_ssp=no")
#:tests? #f ; XXX
@@ -1250,7 +1256,14 @@ call interface, and powerful string processing.")
(("^\\$\\(inst_sysconfdir\\)/rpc(.*)$" _ suffix)
(string-append out "/etc/rpc" suffix "\n"))
(("^install-others =.*$")
- (string-append "install-others = " out "/etc/rpc\n")))))
+ (string-append "install-others = " out "/etc/rpc\n")))
+
+ (substitute* "Makeconfig"
+ ;; According to
+ ;; <http://www.linuxfromscratch.org/lfs/view/stable/chapter05/glibc.html>,
+ ;; linking against libgcc_s is not needed with GCC
+ ;; 4.7.1.
+ ((" -lgcc_s") ""))))
%standard-phases)))
(description "The GNU C Library")
(long-description
@@ -1339,39 +1352,75 @@ previous value of the keyword argument."
("findutils" ,findutils-boot0)
,@%bootstrap-inputs))
+(define* (nix-system->gnu-triplet system #:optional (vendor "unknown"))
+ "Return an a guess of the GNU triplet corresponding to Nix system
+identifier SYSTEM."
+ (let* ((dash (string-index system #\-))
+ (arch (substring system 0 dash))
+ (os (substring system (+ 1 dash))))
+ (string-append arch
+ "-" vendor "-"
+ (if (string=? os "linux")
+ "linux-gnu"
+ os))))
+
+(define boot-triplet
+ ;; Return the triplet used to create the cross toolchain needed in the
+ ;; first bootstrapping stage.
+ (cut nix-system->gnu-triplet <> "guix"))
+
+;; Following Linux From Scratch, build a cross-toolchain in stage 0. That
+;; toolchain actually targets the same OS and arch, but it has the advantage
+;; of being independent of the libc and tools in %BOOTSTRAP-INPUTS, since
+;; GCC-BOOT0 (below) is built without any reference to the target libc.
+
+(define binutils-boot0
+ (package (inherit binutils)
+ (name "binutils-cross-boot0")
+ (arguments
+ (lambda (system)
+ `(#:implicit-inputs? #f
+ ,@(substitute-keyword-arguments (package-arguments binutils)
+ ((#:configure-flags cf)
+ `(list ,(string-append "--target=" (boot-triplet system))))))))
+ (inputs %boot0-inputs)))
+
(define gcc-boot0
(package (inherit gcc-4.7)
- (name "gcc-boot0")
+ (name "gcc-cross-boot0")
(arguments
- `(#:implicit-inputs? #f
-
- ,@(substitute-keyword-arguments (package-arguments gcc-4.7)
- ((#:phases phases)
- (let ((binutils-name (package-full-name binutils)))
+ (lambda (system)
+ `(#:implicit-inputs? #f
+ #:modules ((guix build gnu-build-system)
+ (guix build utils)
+ (ice-9 regex)
+ (srfi srfi-1)
+ (srfi srfi-26))
+ ,@(substitute-keyword-arguments (package-arguments gcc-4.7)
+ ((#:configure-flags flags)
+ `(append (list ,(string-append "--target="
+ (boot-triplet system))
+
+ ;; No libc yet.
+ "--without-headers"
+
+ ;; Disable features not needed at this stage.
+ "--disable-shared"
+ "--enable-languages=c"
+ "--disable-libmudflap"
+ "--disable-libgomp"
+ "--disable-libssp"
+ "--disable-libquadmath"
+ "--disable-decimal-float")
+ (remove (cut string-match "--enable-languages.*" <>)
+ ,flags)))
+ ((#:phases phases)
`(alist-cons-after
- 'unpack 'unpack-binutils&co
+ 'unpack 'unpack-gmp&co
(lambda* (#:key inputs #:allow-other-keys)
- (let ((binutils (assoc-ref %build-inputs "binutils-source"))
- (gmp (assoc-ref %build-inputs "gmp-source"))
- (mpfr (assoc-ref %build-inputs "mpfr-source"))
- (mpc (assoc-ref %build-inputs "mpc-source")))
-
- ;; We want to make sure feature tests like the
- ;; `.init_array' one really look at the linker we're
- ;; targeting (especially since our target Glibc requires
- ;; these features.) Thus, make a joint GCC/Binutils
- ;; build.
- (or (zero? (system* "tar" "xvf" binutils))
- (error "failed to unpack tarball" binutils))
-
- ;; By default, `configure' looks for `ld' under `ld', not
- ;; `binutils/ld'. Thus add an additional symlink. Also
- ;; add links for its dependencies, so it can find BFD
- ;; headers & co.
- ,@(map (lambda (tool)
- `(symlink ,(string-append binutils-name "/" tool)
- ,tool))
- '("bfd" "ld"))
+ (let ((gmp (assoc-ref %build-inputs "gmp-source"))
+ (mpfr (assoc-ref %build-inputs "mpfr-source"))
+ (mpc (assoc-ref %build-inputs "mpc-source")))
;; To reduce the set of pre-built bootstrap inputs, build
;; GMP & co. from GCC.
@@ -1403,24 +1452,28 @@ previous value of the keyword argument."
"-I" b "/mpfr/src"))
(("gmplibs='-L([^ ]+)/mpfr" _ a)
(string-append "gmplibs='-L" a "/mpfr/src")))))
- ,phases))))))
-
- (inputs `(("binutils-source" ,(package-source binutils))
- ("gmp-source" ,(package-source gmp))
+ (alist-cons-after
+ 'install 'symlink-libgcc_eh
+ (lambda* (#:key outputs #:allow-other-keys)
+ (let ((out (assoc-ref outputs "out")))
+ ;; Glibc wants to link against libgcc_eh, so provide
+ ;; it.
+ (with-directory-excursion
+ (string-append out "/lib/gcc/"
+ ,(boot-triplet system)
+ "/" ,(package-version gcc-4.7))
+ (symlink "libgcc.a" "libgcc_eh.a"))))
+ ,phases)))))))
+
+ (inputs `(("gmp-source" ,(package-source gmp))
("mpfr-source" ,(package-source mpfr))
("mpc-source" ,(package-source mpc))
- ,@%boot0-inputs))))
+ ("binutils-cross" ,binutils-boot0)
-(define binutils-boot0
- ;; Since Binutils in GCC-BOOT0 does not get installed, we need another one
- ;; here.
- (package (inherit binutils)
- (name "binutils-boot0")
- (arguments
- `(#:implicit-inputs? #f
- ,@(package-arguments binutils)))
- (inputs `(("gcc" ,gcc-boot0)
- ,@(alist-delete "gcc" %boot0-inputs)))))
+ ;; Call it differently so that the builder can check whether
+ ;; the "libc" input is #f.
+ ("libc-native" ,@(assoc-ref %boot0-inputs "libc"))
+ ,@(alist-delete "libc" %boot0-inputs)))))
(define linux-headers-boot0
(package (inherit linux-headers)
@@ -1432,96 +1485,135 @@ previous value of the keyword argument."
(define %boot1-inputs
;; 2nd stage inputs.
`(("gcc" ,gcc-boot0)
- ("binutils" ,binutils-boot0)
- ,@(fold alist-delete %boot0-inputs
- '("gcc" "binutils"))))
+ ("binutils-cross" ,binutils-boot0)
+
+ ;; Keep "binutils" here because the cross-gcc invokes `as', not the
+ ;; cross-`as'.
+ ,@%boot0-inputs))
(define-public glibc-final
- ;; The final libc.
- ;; FIXME: It depends on GCC-BOOT0, which depends on some of
- ;; %BOOTSTRAP-INPUTS.
+ ;; The final libc, "cross-built". If everything went well, the resulting
+ ;; store path has no dependencies.
(package (inherit glibc)
(arguments
- `(#:implicit-inputs? #f
-
- ;; Leave /bin/sh as the interpreter for `ldd', `sotruss', etc. to
- ;; avoid keeping a reference to the bootstrap Bash.
- #:patch-shebangs? #f
- ,@(substitute-keyword-arguments (package-arguments glibc)
- ((#:configure-flags flags)
- `(cons "BASH_SHELL=/bin/sh" ,flags)))))
+ (lambda (system)
+ `(#:implicit-inputs? #f
+
+ ;; Leave /bin/sh as the interpreter for `ldd', `sotruss', etc. to
+ ;; avoid keeping a reference to the bootstrap Bash.
+ #:patch-shebangs? #f
+ ,@(substitute-keyword-arguments (package-arguments glibc)
+ ((#:configure-flags flags)
+ `(append (list ,(string-append "--host=" (boot-triplet system))
+ ,(string-append "--build="
+ (nix-system->gnu-triplet system))
+ "BASH_SHELL=/bin/sh"
+
+ ;; cross-rpcgen fails to build, because it gets
+ ;; built with the cross-compiler instead of the
+ ;; native compiler. See also
+ ;; <http://sourceware.org/ml/libc-alpha/2012-03/msg00325.html>.
+ "--disable-obsolete-rpc")
+ ,flags))))))
(propagated-inputs `(("linux-headers" ,linux-headers-boot0)))
- (inputs %boot1-inputs)))
+ (inputs `(;; A native GCC is needed to build `cross-rpcgen'.
+ ("native-gcc" ,@(assoc-ref %boot0-inputs "gcc"))
+ ,@%boot1-inputs))))
+
+(define gcc-boot0-wrapped
+ ;; Make the cross-tools GCC-BOOT0 and BINUTILS-BOOT0 available under the
+ ;; non-cross names.
+ (package (inherit gcc-4.7)
+ (name (string-append (package-name gcc-boot0) "-wrapped"))
+ (build-system trivial-build-system)
+ (arguments
+ (lambda (system)
+ `(#:modules ((guix build utils))
+ #:builder (begin
+ (use-modules (guix build utils))
+
+ (let* ((binutils (assoc-ref %build-inputs "binutils"))
+ (gcc (assoc-ref %build-inputs "gcc"))
+ (libc (assoc-ref %build-inputs "libc"))
+ (out (assoc-ref %outputs "out"))
+ (bindir (string-append out "/bin"))
+ (triplet ,(boot-triplet system)))
+ (mkdir out) (mkdir bindir)
+ (with-directory-excursion bindir
+ (for-each (lambda (tool)
+ (symlink (string-append binutils "/bin/"
+ triplet "-" tool)
+ tool))
+ '("ar" "ranlib"))
+
+ ;; GCC-BOOT0 is a libc-less cross-compiler, so it
+ ;; needs to be told where to find the crt files and
+ ;; the dynamic linker.
+ (call-with-output-file "gcc"
+ (lambda (p)
+ (format p "#!/bin/sh
+exec ~a/bin/~a-gcc -B~a/lib -Wl,-dynamic-linker -Wl,~a/lib/~a \"$@\"~%"
+ gcc triplet
+ libc libc
+ ,(glibc-dynamic-linker system))))
+
+ (chmod "gcc" #o555)))))))
+ (native-inputs
+ `(("binutils" ,binutils-boot0)
+ ("gcc" ,gcc-boot0)
+ ("libc" ,glibc-final)))
+ (inputs '())))
(define %boot2-inputs
;; 3rd stage inputs.
`(("libc" ,glibc-final)
- ,@(alist-delete "libc" %bootstrap-inputs)))
-
-(define m4-boot2
- (package (inherit m4)
- (name "m4-boot2")
- (arguments (lambda (system)
- `(#:implicit-inputs? #f
- ,@((package-arguments m4) system))))
- (inputs `(,@(package-inputs m4)
- ,@%boot2-inputs))))
+ ("gcc" ,gcc-boot0-wrapped)
+ ,@(fold alist-delete %boot1-inputs '("libc" "gcc"))))
-(define gmp-boot2
- (package (inherit gmp)
- (name "gmp-boot2")
- (arguments
- `(#:implicit-inputs? #f
- ,@(package-arguments gmp)))
- (native-inputs `(("m4" ,m4-boot2)
- ,@%boot2-inputs))))
-
-(define mpfr-boot2
- (package (inherit mpfr)
- (name "mpfr-boot2")
+(define binutils-final
+ (package (inherit binutils)
(arguments
- `(#:implicit-inputs? #f
- ,@(package-arguments mpfr)))
- (inputs `(("gmp" ,gmp-boot2)
- ,@%boot2-inputs))))
+ (lambda (system)
+ `(#:implicit-inputs? #f
+ ,@(package-arguments binutils))))
+ (inputs %boot2-inputs)))
-(define mpc-boot2
- (package (inherit mpc)
- (name "mpc-boot2")
+(define-public gcc-final
+ ;; The final GCC.
+ (package (inherit gcc-boot0)
+ (name "gcc")
(arguments
- `(#:implicit-inputs? #f
- ,@(package-arguments mpc)))
- (inputs `(("gmp" ,gmp-boot2)
- ("mpfr" ,mpfr-boot2)
+ (lambda (system)
+ `(#:implicit-inputs? #f
+
+ ;; Build again GMP & co. within GCC's build process, because it's hard
+ ;; to do outside (because GCC-BOOT0 is a cross-compiler, and thus
+ ;; doesn't honor $LIBRARY_PATH, which breaks `gnu-build-system'.)
+ ,@(substitute-keyword-arguments ((package-arguments gcc-boot0) system)
+ ((#:configure-flags boot-flags)
+ (let loop ((args (package-arguments gcc-4.7)))
+ (match args
+ ((#:configure-flags normal-flags _ ...)
+ normal-flags)
+ ((_ rest ...)
+ (loop rest)))))
+ ((#:phases phases)
+ `(alist-delete 'symlink-libgcc_eh ,phases))))))
+
+ (inputs `(("gmp-source" ,(package-source gmp))
+ ("mpfr-source" ,(package-source mpfr))
+ ("mpc-source" ,(package-source mpc))
+ ("binutils" ,binutils-final)
,@%boot2-inputs))))
(define %boot3-inputs
;; 4th stage inputs.
- `(("libc" ,glibc-final)
- ("gmp" ,gmp-boot2)
- ("mpfr" ,mpfr-boot2)
- ("mpc" ,mpc-boot2)
- ,@(fold alist-delete
- %boot2-inputs
- '("libc" "gmp" "mpfr" "mpc"))))
-
-(define-public gcc-final
- ;; The final GCC.
- (package (inherit gcc-4.7)
- (name "gcc")
- (arguments `(#:implicit-inputs? #f
- ,@(package-arguments gcc-4.7)))
- (inputs %boot3-inputs)))
-
-(define %boot4-inputs
- ;; 5th stage inputs.
`(("gcc" ,gcc-final)
- ,@(fold alist-delete %boot3-inputs
- '("gcc" "gmp" "mpfr" "mpc"))))
+ ,@(alist-delete "gcc" %boot2-inputs)))
(define-public %final-inputs
;; Final derivations used as implicit inputs by `gnu-build-system'.
- (let ((finalize (cut package-with-explicit-inputs <> %boot4-inputs
+ (let ((finalize (cut package-with-explicit-inputs <> %boot3-inputs
(current-source-location))))
`(,@(map (match-lambda
((name package)
@@ -1538,10 +1630,10 @@ previous value of the keyword argument."
("bash" ,bash)
("findutils" ,findutils)
("gawk" ,gawk)
- ("make" ,gnu-make)
- ("binutils" ,binutils)))
+ ("make" ,gnu-make)))
+ ("binutils" ,binutils-final)
("gcc" ,gcc-final)
- ("glibc" ,glibc-final))))
+ ("libc" ,glibc-final))))
;;;
@@ -1702,4 +1794,5 @@ beginning.")
;;; eval: (put 'substitute* 'scheme-indent-function 1)
;;; eval: (put 'with-directory-excursion 'scheme-indent-function 1)
;;; eval: (put 'package 'scheme-indent-function 1)
+;;; eval: (put 'substitute-keyword-arguments 'scheme-indent-function 1)
;;; End: